显示驱动
显示驱动连接在WIN32K.SYS,仅仅允许调用Eng* APIs,这些api实际上可以在内核模式和用户模式下找到。Nt4之前,显示驱动是在用户模式。无论如何显示驱动和打印驱动都使用同样的api函数集。遵循这个API函数集,只需要很少的工作就能移植显示驱动到用户模式或者内核模式。
显示驱动不是加载到系统内存空间而是在会话空间。会话空间是内核中类似于进程隔离的。如图地址从OxA0000000开始扩展到0xA2FFFFFF是会话空间。在用户模式下,进程有他们自己的虚拟内存地址空间,在内核模式下,会话有他们自己的虚拟内存地址空间。在内核内存中系统空间对所有会话是全局的。
一个会话是一个登录用户的实例,它包含了自己的窗口管理,桌面,shell和应用程序。最显著的就是windows xp的快速用户切换,即你可以在一台机器上登录多个用户。每个用户实际上有一个独有的会话和一个独有的内核内存范围,我们称为会话空间。
当设计一个视频驱动的时候,你会遇到一个问题。就是说,如果你的迷你小端口驱动可能处理的那个内存超出了当前会话上下文,你不能简单地传递任意的内存到你的迷你小端口驱动。这里有个例子传递这个内存给系统进程中的另外的线程来处理。
如果系统进程没有关联你的会话,你将会访问一个不同的内存区域,而不是你想的那样。当这个发生时,你会得到"A driver has not been correctly ported to Terminal Services"这样的蓝屏信息。
显示驱动不象到目前为止我们接触过的驱动那样。但它仍然是pe格式。它不象迷你小端口驱动那样,是一个连接到一个不同框架的正规的内核驱动。它不能直接通过连接到内核而使用内核api,并且由于前面说明的原因也不能使用他们。如果你的api传递的内存超出了会话空间,那么你就会蓝屏,除非你保证你只是传递了系统内存。这是另一个为什么只能使用Eng* API函数集的原因。然而,你可以从迷你小端口驱动请求一个函数指针表,没有什么东西会阻止你这么做。
任何时候,显示驱动同普通驱动相比表现的更像一个dll,实际上它也是被看作是一个dll.这个驱动框架被绑定在WIN32K.SYS上,WIN32K.SYS实现了windows管理器和GDI.这个驱动编译使用"-entry:DrvEnableDriver@12 /SUBSYSTEM:NATIVE",其中DrvEnableDriver作为显示驱动的入口点。
DrvEnableDriver
DrvEnableDriver是显示驱动的初始入口点。它与DriverEntry没有任何关系。这个API入口参数有一个结构,这个结构需要使用一个指向驱动入口的函数表来填充。这个表包含了一系列函数指针的索引值和函数指针。其中索引值表示了函数类型,就像"INDEX_DrvCompletePDEV"是指它对应的函数指针是指向驱动中一个DrvCompletePDEV型的处理函数。其中一些API是可选的,但有一些是必须的。
这个入口点为了返回你的函数序列负责。你也可以在这里做一些你需要的初始化动作。下面的代码来自于本文的显示驱动例子。
/*
* Display Drivers provide a list of function entry points for specific GDI
* tasks. These are identified by providing a pre-defined "INDEX" value (pre-
* defined
* by microsoft) followed by the function entry point. There are levels of
* flexibility
* on which ones you are REQUIRED and which ones are technically OPTIONAL.
*
*/
DRVFN g_DrvFunctions[] =
{
{ INDEX_DrvAssertMode, (PFN) GdiExample_DrvAssertMode },
{ INDEX_DrvCompletePDEV, (PFN) GdiExample_DrvCompletePDEV },
{ INDEX_DrvCreateDeviceBitmap, (PFN) GdiExample_DrvCreateDeviceBitmap },
{ INDEX_DrvDeleteDeviceBitmap, (PFN) GdiExample_DrvDeleteDeviceBitmap },
{ INDEX_DrvDestroyFont, (PFN) GdiExample_DrvDestroyFont },
{ INDEX_DrvDisablePDEV, (PFN) GdiExample_DrvDisablePDEV },
{ INDEX_DrvDisableDriver, (PFN) GdiExample_DrvDisableDriver },
{ INDEX_DrvDisableSurface, (PFN) GdiExample_DrvDisableSurface },
{ INDEX_DrvSaveScreenBits, (PFN) GdiExample_DrvSaveScreenBits },
{ INDEX_DrvEnablePDEV, (PFN) GdiExample_DrvEnablePDEV },
{ INDEX_DrvEnableSurface, (PFN) GdiExample_DrvEnableSurface },
{ INDEX_DrvEscape, (PFN) GdiExample_DrvEscape },
{ INDEX_DrvGetModes, (PFN) GdiExample_DrvGetModes },
{ INDEX_DrvMovePointer, (PFN) GdiExample_DrvMovePointer },
{ INDEX_DrvNotify, (PFN) GdiExample_DrvNotify },
// { INDEX_DrvRealizeBrush, (PFN) GdiExample_DrvRealizeBrush },
{ INDEX_DrvResetPDEV, (PFN) GdiExample_DrvResetPDEV },
{ INDEX_DrvSetPalette, (PFN) GdiExample_DrvSetPalette },
{ INDEX_DrvSetPointerShape, (PFN) GdiExample_DrvSetPointerShape },
{ INDEX_DrvStretchBlt, (PFN) GdiExample_DrvStretchBlt },
{ INDEX_DrvSynchronizeSurface, (PFN) GdiExample_DrvSynchronizeSurface },
{ INDEX_DrvAlphaBlend, (PFN) GdiExample_DrvAlphaBlend },
{ INDEX_DrvBitBlt, (PFN) GdiExample_DrvBitBlt },
{ INDEX_DrvCopyBits, (PFN) GdiExample_DrvCopyBits },
{ INDEX_DrvFillPath, (PFN) GdiExample_DrvFillPath },
{ INDEX_DrvGradientFill, (PFN) GdiExample_DrvGradientFill },
{ INDEX_DrvLineTo, (PFN) GdiExample_DrvLineTo },
{ INDEX_DrvStrokePath, (PFN) GdiExample_DrvStrokePath },
{ INDEX_DrvTextOut, (PFN) GdiExample_DrvTextOut },
{ INDEX_DrvTransparentBlt, (PFN) GdiExample_DrvTransparentBlt },
};
ULONG g_ulNumberOfFunctions = sizeof(g_DrvFunctions) / sizeof(DRVFN);
/*********************************************************************
* DrvEnableDriver
*
* This is the initial driver entry point. This is the "DriverEntry"
* equivlent for Display and Printer drivers. This function must
* return a function table that represents all the supported entry
* points into this driver.
*
*********************************************************************/
BOOL DrvEnableDriver(ULONG ulEngineVersion,
ULONG ulDataSize, DRVENABLEDATA *pDrvEnableData)
{
BOOL bDriverEnabled = FALSE;
/*
* We only want to support versions > NT 4
*
*/
if(HIWORD(ulEngineVersion) >= 0x3 &&
ulDataSize >= sizeof(DRVENABLEDATA))
{
pDrvEnableData->iDriverVersion = DDI_DRIVER_VERSION;
pDrvEnableData->pdrvfn = g_DrvFunctions;
pDrvEnableData->c = g_ulNumberOfFunctions;
bDriverEnabled = TRUE;
}
return bDriverEnabled;
}