User Mode Driver介绍
Windows CE 6.0中引入了User Mode Driver的概念,可是无论是网上,还是各个芯片厂商提供的方案中,都很少提及这方面的内容。
本文以小郭对存储管理和User Mode Driver Host的理解为基础,结合具体的代码实现,从User Mode Driver的加载流程的角度分析了存储管理对User Mode Driver的处理过程。
由于个人知识水平和项目经验有限,难免有些地方错误,还望你不吝指出,特此说明。
顾名思义,User Mode Driver就是运行在User Mode的Driver,而Kernel Mode Driver是运行在Kernel Mode的Driver。
User Mode和Kernel Mode的有很多差别,首先,运行在Kernel Mode的程序一般都是处理系统的核心功能的程序,而运行在User Mode多是一些与应用有关的程序或者驱动,再者,运行在User Mode下的程序不可以进行物理内存映射和调用中断处理相关函数,而运行在Kernel Mode下的程序和驱动却没有这方面的限制。
在这里,我着重说的是User Mode和Kernel Mode下内存访问权限的差别。
运行在User Mode下的程序合法的虚拟内存空间访问权限如下:
Read:VM_USER_BASE(0x00010000)~ VM_KMODE_BASE(0x80000000) Write:VM_USER_BASE(0x00010000)~ VM_SHARED_HEAP_BASE(0x70000000) |
而运行在Kernel Mode下的程序可以自由地访问4GB的内存空间(对32位机而言)。
在老版本的Windows CE5.0中,所有的Driver和应用程序都运行在User Mode下。操作系统提供了API SetKMode()来在User Mode和Kernel Mode之间自由地切换,提供了API SetProcPermissions()来提升线程的访问权限。另外,Platform Builder提供了编译选项Full Kernel Mode来决定是否让系统中所有的程序,包括驱动和应用程序都运行在Kernel Mode下。
显然,如果一支应用程序恶意的去访问修改Kernel Mode下的一些参数或者结构体的话,整个系统就会增加很多风险。所以,在Windows CE 6.0中,Microsoft将桌面操作系统中的内存管理策略引入进来。例如,所有的Driver都运行在Kernel Mode下,而应用程序运行在User Mode下。
当然,Microsoft也不想让一些写的很差的Driver以及一些有缺陷的Driver运行在Kernel Mode下,由此提出了和桌面操作系统类似的概念User Mode Driver Framework。通过User Mode Driver Framework编写出来的Driver,也就是User Mode Driver,将运行在User Mode下。
熟悉Microsoft Windows桌面驱动程序的人都应该知道,驱动程序包括三种模型,分别是虚拟设备驱动程序(Virtual Device Driver),内核模式驱动程序(Kernel Mode Driver)和Win32驱动程序模型(Win32 Driver Mode)。所以,User Mode Driver Framework是一个很老的概念。
User Mode Driver Framework包括两部分,第一部分是User Mode Driver Reflector(Reflector/Service,有的地方也成为Reflector Service),它存在于Device Manager中,第二部分是User Mode Driver Host,它被User Mode Driver Reflector进行加载和管理,运行在User Mode下。
User Mode Driver Reflector加载User Mode Driver Host后,会将I/O请求传递给它,然后User Mode Driver Host将I/O请求传递给User Mode Driver。
由于User Mode的局限性,User Mode Driver不允许访问硬件,例如不允许使用中断函数以及映射物理内存的函数等。为了解决这个问题,User Mode Driver调用User Mode Driver Reflector来处理类似的这些请求。User Mode Driver Reflector会去检查Registry的配置,去决定是否响应这些要求。
这部分内容可以用下面的几张图来进行描述:
第一张,摘自帮助文档,其中Parent Bus Driver就是CEDDK Driver,而Reflector/Service就是User Mode Driver Reflector。
第二图摘自微软官方关于Windows CE6.0的PPT介绍。
在Device.dll被kernel.dll加载起来的后,Device.dll中的函数StartDeviceManager()将会被kernel.dll调用并执行。该函数会去调用InitUserProcMgr()以完成对User Mode Driver Process进行管理的一系列初始化工作。
函数InitUserProcMgr()完成的初始化工作非常简单,就是创建并初始化类UDPContainer和 UDServiceContainer实例,并赋值给全局变量g_pUDPContainer和g_pServiceContainer,然后调用类的初始化函数。
类UDPContainer用来维护所有User Mode Driver Host的进程。在其初始化过程中会创建一个类UDPContainer的对象,然后调用InsertObjectBy插入到一个莫名其妙的链表中,另外到注册表[HKEY_LOCAL_MACHINE/Drivers]下查找默认的User Group名字和Prefix,对于那些没有指定使用哪个User Group也即User Mode Driver Host的Driver,将会使用这个User Mode Driver Host进行管理。
类UDPContainer可以用下图来描述:
类UDServiceContainer同样是用来维护所有User Mode Driver Host的Reflector Service,每一个User Mode Driver都会存在一个类UserDriverService的实例,而UDServiceContainer则维护着这些UserDriverService结点。在它的初始化过程中会调用API CreateAPISet()和RegisterAPISet()向系统注册ReflServApiMethods[]。ReflServApiMethods包括了函数REFL_DevCloseFileHandle和REFL_DevDeviceIoControl。
当调用CEDDK BUS Driver中BusIoControl() 以及BusTransBusAddrToVirtual()等函数时,实际上执行的就是REFL_DevDeviceIoControl()。
类UDServiceContainer的作用可以用下图来进行描述:
相关的部分代码如下:
extern "C" BOOL InitUserProcMgr() { if ( !g_pUDPContainer ) { // 这里会去创建一个UDPContainer对象,并把地址赋给全局变量g_pUDPContainer // 这个步骤的意义是会去[HKEY_LOCAL_MACHINE/Drivers]下查找默认的User Group名字和Prefix, // 对于那些没有指定使用哪个User Group也即User Mode Driver Host的Driver,将会使用这个User Mode Driver Host进行管理 g_pUDPContainer = new UDPContainer(); if (g_pUDPContainer!=NULL && !g_pUDPContainer->Init()) { delete g_pUDPContainer; g_pUDPContainer = NULL; } } ASSERT(g_pUDPContainer!=NULL); if (!g_pServiceContainer) { g_pServiceContainer = new UDServiceContainer(); if (g_pServiceContainer!=NULL && !g_pServiceContainer->Init()) { delete g_pServiceContainer; g_pServiceContainer = NULL; }
} ASSERT(g_pServiceContainer!=NULL) ; return (g_pUDPContainer!=NULL && g_pServiceContainer!=NULL); } |
const PFNVOID ReflServApiMethods[] = { (PFNVOID)REFL_DevCloseFileHandle, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)REFL_DevDeviceIoControl, };
#define NUM_REFL_SERV_APIS (sizeof(ReflServApiMethods)/sizeof(ReflServApiMethods[0]))
const ULONGLONG ReflServApiSigs[NUM_REFL_SERV_APIS] = { FNSIG1(DW), // CloseFileHandle FNSIG0(), FNSIG5(DW,I_PTR,DW,O_PDW,IO_PDW), // ReadFile FNSIG5(DW,O_PTR,DW,O_PDW,IO_PDW), // WriteFile FNSIG2(DW,O_PDW), // GetFileSize FNSIG4(DW,DW,O_PDW,DW), // SetFilePointer FNSIG2(DW,O_PDW), // GetDeviceInformationByFileHandle FNSIG1(DW), // FlushFileBuffers FNSIG4(DW,O_PDW,O_PDW,O_PDW), // GetFileTime FNSIG4(DW,IO_PDW,IO_PDW,IO_PDW), // SetFileTime FNSIG1(DW), // SetEndOfFile, FNSIG8(DW, DW, I_PTR, DW, O_PTR, DW, O_PDW, IO_PDW), // DeviceIoControl }; |
BOOL UDServiceContainer::Init() { BOOL bReturn = FALSE; // Before any process can become a handle server, the process must create and register a handle-based API set // with this function and RegisterAPISet. m_hDevFileApiHandle = CreateAPISet("REFL", NUM_REFL_SERV_APIS, ReflServApiMethods, ReflServApiSigs ); if (m_hDevFileApiHandle!=INVALID_HANDLE_VALUE) bReturn =RegisterAPISet(m_hDevFileApiHandle, HT_FILE | REGISTER_APISET_TYPE); ASSERT(m_hDevFileApiHandle!=INVALID_HANDLE_VALUE && bReturn) ; return bReturn; }; |
// 这里会去创建一个UserDriverProcessor的对象,然后调用InsertObjectBy插入到一个莫名其妙的链表中, // 另外会去[HKEY_LOCAL_MACHINE/Drivers]下查找默认的User Group名字和Prefix, // 对于那些没有指定使用哪个User Group也即User Mode Driver Host的Driver,将会使用这个User Mode Driver Host进行管理 UDPContainer::UDPContainer() { m_dwCurIndex = UDP_RANDOM_PROCESSOR_START_OFFSET ; m_lpProcName = NULL; DWORD dwLen = 0; DWORD dwType;
CRegistryEdit regKey(HKEY_LOCAL_MACHINE , DEVLOAD_DRIVERS_KEY );
if (regKey.IsKeyOpened() && regKey.RegQueryValueEx(UPD_REG_PROCESSOR_NAME_VAL,&dwType,NULL,&dwLen) && dwType == UPD_REG_PROCESSOR_NAME_TYPE) { dwLen = min(dwLen / sizeof(TCHAR) + 1, MAX_PATH) ; m_lpProcName = new TCHAR [dwLen]; if (m_lpProcName && !regKey.GetRegValue(UPD_REG_PROCESSOR_NAME_VAL,(LPBYTE)m_lpProcName,dwLen*sizeof(TCHAR))) { delete [] m_lpProcName; m_lpProcName = NULL; } if (m_lpProcName) m_lpProcName[dwLen-1] = 0; } m_lpProcVolName = NULL; if (regKey.IsKeyOpened() && regKey.RegQueryValueEx(UDP_REG_PROCESSOR_VOLPREFIX_VAL,&dwType,NULL,&dwLen) && dwType == UDP_REG_PROCESSOR_VOLPREFIX_TYPE) { dwLen = min(dwLen / sizeof(TCHAR) + 1, MAX_PATH) ; m_lpProcVolName = new TCHAR [dwLen]; if (m_lpProcVolName && !regKey.GetRegValue(UDP_REG_PROCESSOR_VOLPREFIX_VAL,(LPBYTE)m_lpProcVolName,dwLen*sizeof(TCHAR))) { delete [] m_lpProcVolName; m_lpProcVolName = NULL; } if (m_lpProcVolName) m_lpProcVolName[dwLen-1] = 0; } if (!(regKey.IsKeyOpened() && regKey.GetRegValue(UDP_REG_PROCESSOR_TIMEOUT_VAL,(LPBYTE)&m_dwProgTimeout,sizeof(DWORD)))) { // If failed we use default. m_dwProgTimeout = UDP_REG_PROCESSOR_TIMEOUT_DEFAULT ; } } |
当设备管理器调用ActivateDeviceEx()来加载流驱动的时候,如果发现设备的注册表中指定了该设备驱动是一个User Mode Driver的时候,则设备管理器将会通过Reflector Service来加载流驱动。
这部分代码可以参照文件DEVICE/DEVCORE/devload.c中的函数CreateDevice(),如下:
// 可以看到,创建user mode driver的唯一条件就是dwFlags & DEVFLAGS_LOAD_AS_USERPROC>0 if ((dwFlags & DEVFLAGS_LOAD_AS_USERPROC)) { lpdev->hLib = NULL; lpdev->dwData = Reflector_Create(lpszDeviceKey, pEffType, lpszLib, dwFlags ); if (lpdev->dwData != 0 ) { lpdev->fnInit = NULL; lpdev->fnInitEx = (pInitExFn)Reflector_InitEx; lpdev->fnPreDeinit = (pDeinitFn)Reflector_PreDeinit; lpdev->fnDeinit = (pDeinitFn)Reflector_Deinit; lpdev->fnOpen = (pOpenFn)Reflector_Open; lpdev->fnPreClose = (pCloseFn)Reflector_PreClose; lpdev->fnClose = (pCloseFn)Reflector_Close; lpdev->fnRead = (pReadFn)Reflector_Read; lpdev->fnWrite = (pWriteFn)Reflector_Write; lpdev->fnSeek = (pSeekFn)Reflector_SeekFn; lpdev->fnControl = (pControlFn)Reflector_Control; lpdev->fnPowerup = (pPowerupFn)Reflector_Powerup; lpdev->fnPowerdn = (pPowerupFn)Reflector_Powerdn; } else { DEBUGMSG(ZONE_WARNING, (_T("DEVICE!CreateDevice: couldn't load(%s) to user mode!!/r/n"),lpszLib)); dwStatus = ERROR_FILE_NOT_FOUND; } } else { DEBUGMSG(ZONE_ACTIVE, (_T("DEVICE!CreateDevice: loading driver DLL '%s'/r/n"), lpszLib)); // 下面这里会去判断两种load library的方式 lpdev->hLib = (dwFlags & DEVFLAGS_LOADLIBRARY) ? LoadLibrary(lpszLib) : LoadDriver(lpszLib); if (!lpdev->hLib) { DEBUGMSG(ZONE_WARNING, (_T("DEVICE!CreateDevice: couldn't load '%s' -- error %d/r/n"), lpszLib, GetLastError())); dwStatus = ERROR_FILE_NOT_FOUND; } else { lpdev->fnInitEx = NULL; lpdev->fnInit = (pInitFn)GetDMProcAddr(pEffType,L"Init",lpdev->hLib); lpdev->fnPreDeinit = (pDeinitFn)GetDMProcAddr(pEffType,L"PreDeinit",lpdev->hLib); lpdev->fnDeinit = (pDeinitFn)GetDMProcAddr(pEffType,L"Deinit",lpdev->hLib); lpdev->fnOpen = (pOpenFn)GetDMProcAddr(pEffType,L"Open",lpdev->hLib); lpdev->fnPreClose = (pCloseFn)GetDMProcAddr(pEffType,L"PreClose",lpdev->hLib); lpdev->fnClose = (pCloseFn)GetDMProcAddr(pEffType,L"Close",lpdev->hLib); lpdev->fnRead = (pReadFn)GetDMProcAddr(pEffType,L"Read",lpdev->hLib); lpdev->fnWrite = (pWriteFn)GetDMProcAddr(pEffType,L"Write",lpdev->hLib); lpdev->fnSeek = (pSeekFn)GetDMProcAddr(pEffType,L"Seek",lpdev->hLib); lpdev->fnControl = (pControlFn)GetDMProcAddr(pEffType,L"IOControl",lpdev->hLib); lpdev->fnPowerup = (pPowerupFn)GetDMProcAddr(pEffType,L"PowerUp",lpdev->hLib); lpdev->fnPowerdn = (pPowerdnFn)GetDMProcAddr(pEffType,L"PowerDown",lpdev->hLib);
// Make sure that the driver has an init and deinit routine. If it is named, // it must have open and close, plus at least one of the I/O routines (read, write // ioctl, and/or seek). If a named driver has a pre-close routine, it must also // have a pre-deinit routine. if (!(lpdev->fnInit && lpdev->fnDeinit) || lpdev->pszDeviceName != NULL && (!lpdev->fnOpen || !lpdev->fnClose || (!lpdev->fnRead && !lpdev->fnWrite && !lpdev->fnSeek && !lpdev->fnControl) || (lpdev->fnPreClose && !lpdev->fnPreDeinit))) { DEBUGMSG(ZONE_WARNING, (_T("DEVICE!CreateDevice: illegal entry point combination in driver DLL '%s'/r/n"), lpszLib)); dwStatus = ERROR_INVALID_FUNCTION; }
if (!lpdev->fnOpen) lpdev->fnOpen = (pOpenFn) DevFileNotSupportedBool; if (!lpdev->fnClose) lpdev->fnClose = (pCloseFn) DevFileNotSupportedBool; if (!lpdev->fnControl) lpdev->fnControl = (pControlFn) DevFileNotSupportedBool; if (!lpdev->fnRead) lpdev->fnRead = (pReadFn) DevFileNotSupportedDword; if (!lpdev->fnWrite) lpdev->fnWrite = (pWriteFn) DevFileNotSupportedDword; if (!lpdev->fnSeek) lpdev->fnSeek = (pSeekFn) DevFileNotSupportedDword; } } |
从上面粘贴出来的代码中可以看到,设备管理器中会去调用Reflector_Create(),该函数就属于Reflector Service,其实User Mode Driver Host进程就是在这里被创建的。
函数Reflector_Create()实质上直接去调用CReflector * CreateReflector()。
函数CReflector * CreateReflector()会去读取User Mode Driver注册表下"UserProcGroup"的键值,然后调用FindUserProcByID()去到类UDPContainer的成员m_rgLinkList指向的链表中去查询系统中有没有该User Mode Driver Host,如果没有的话,则调用UDPContainer::CreateUserProcByGroupID()去读取其"ProcName"和"ProcVolPrefix"去创建该User Mode Driver Host进程。
有关这部分代码如下:
// 看清楚了,这个不是类的method,而是一个返回类实例指针的函数 // 另外,该函数的功能就是根据lpszDeviceKey的值,到当前系统中去寻找是否有对应的user mode driver host // 进程已经创建起来,如果有则返回其指针 // 如果没有的话,则查询注册表中相应的配置值并创建起进程 CReflector * CreateReflector(LPCTSTR lpszDeviceKey, LPCTSTR lpPreFix, LPCTSTR lpDrvName, DWORD dwFlags ) { CRegistryEdit m_DeviceKey (HKEY_LOCAL_MACHINE, lpszDeviceKey); DWORD dwUserProcGroupID = 0; CReflector * pReturn = NULL; UserDriverProcessor * pUserDriverProc = NULL; DWORD dwRetry = 2; do { //获取注册表中TEXT("UserProcGroup")的值,其实也就是获取user mode driver host的编号 if (m_DeviceKey.IsKeyOpened() && m_DeviceKey.GetRegValue(DEVLOAD_USERPROCGROUP_VALNAME,(PBYTE)&dwUserProcGroupID, sizeof(dwUserProcGroupID))) { pUserDriverProc = FindUserProcByID(dwUserProcGroupID,TRUE); } // 判断传入的参数lpszDeviceKey是不是L"services//" else if (IsServicesRegKey(lpszDeviceKey)) { // Not all services may have explicitly set their group explicitly // in registry, so steer them to default here. // 可以看到,service.exe固定为group2 pUserDriverProc = FindUserProcByID(SERVICEDS_EXE_DEFAULT_PROCESSOR_ID,TRUE); } else { pUserDriverProc = CreateUserProc (); if (pUserDriverProc) pUserDriverProc->AddRef(); }; if (pUserDriverProc) { pReturn = pUserDriverProc->CreateReflector(lpPreFix, lpDrvName,dwFlags); pUserDriverProc->DeRef(); } if (pReturn==NULL) Sleep(1000); } while (dwRetry-- != 0 && pReturn == NULL); DEBUGMSG(ZONE_WARNING && pReturn==NULL,(L"CreateReflector : failed to create refelctor object")); return pReturn; } |
// 按照group id来查找系统当前的user mode driver host,如果没有找到的话,就到系统的注册表 // 中查找其对应的注册表信息,然后创建其进程 // 例如查找dwUserProcGroupID=3,系统中没有找到的话,会查询注册表并创建进程udevice.exe // param: // dwUserProcGroupID: user group id // fCreateOnNoExit: 如果当前系统中不存在个该group的话,是否创建该group的线程 inline UserDriverProcessor * FindUserProcByID(DWORD dwUserProcGroupID,BOOL fCreateOnNoExit) { if (g_pUDPContainer) return g_pUDPContainer->FindUserProcByID(dwUserProcGroupID,fCreateOnNoExit); else return NULL; } |
// 这里用user process group id到链表m_rgLinkList中查找UserDriverProcessor // param: // dwUserProcGroupID: user group id // fCreateOnNoExit: 如果当前系统中不存在个该group的话,是否创建该group的线程 UserDriverProcessor * UDPContainer::FindUserProcByID(DWORD dwUserProcGroupID,BOOL fCreateOnNoExit) { UserDriverProcessor * pReturn = NULL; if (dwUserProcGroupID < UDP_RANDOM_PROCESSOR_START_OFFSET && dwUserProcGroupID != 0) { Lock(); UserDriverProcessor * pCur = m_rgLinkList; while (pCur) { if (pCur->GetProcID() == dwUserProcGroupID ) { pReturn = pCur; break; } else { pCur = pCur->GetNextObject(); } } if (pReturn) { pReturn->AddRef(); } // 如果当前系统中不存在该user group,则创建该group的 if (pReturn == NULL && fCreateOnNoExit) { UserDriverProcessor * pNewProc = CreateUserProcByGroupID(dwUserProcGroupID); if (pNewProc) { // This is newly created. So it should succeeded. pReturn = FindUserProcBy(pNewProc); ASSERT(pReturn); } } Unlock(); } else { UserDriverProcessor * pNewProc = CreateUserProc () ; if (pNewProc) { pReturn = FindUserProcBy(pNewProc); ASSERT(pReturn); } } ASSERT(pReturn); return pReturn; } |
// 这里会去创建一个UserDriverProcessor的对象,然后调用InsertObjectBy插入到一个莫名其妙的链表中 // UserDriverProcessor * UDPContainer::CreateUserProcByGroupID(DWORD dwUserProcGroupID) { TCHAR lpGroupSubKeyPath[MAX_PATH] ; LPCTSTR lpProcName = m_lpProcName; LPCTSTR lpProcVolName = m_lpProcVolName; TCHAR localProcName[MAX_PATH]; TCHAR localProcVolume[MAX_PATH]; DWORD dwProgTimeout= m_dwProgTimeout ;
// 读取group_***的注册表值 CRegistryEdit regKey(HKEY_LOCAL_MACHINE , DEVLOAD_DRIVERS_KEY ); if (regKey.IsKeyOpened() && SUCCEEDED(StringCchPrintf(lpGroupSubKeyPath,MAX_PATH,TEXT("%s_%04x"),UDP_REGKEY_PROCESSOR_GROUP_PREFIX,dwUserProcGroupID))) { CRegistryEdit groupSubKey(regKey.GetHKey(),lpGroupSubKeyPath); if (groupSubKey.IsKeyOpened()) { DWORD dwType; DWORD dwLen = sizeof(localProcName); if (groupSubKey.RegQueryValueEx(UPD_REG_PROCESSOR_NAME_VAL,&dwType,(LPBYTE)localProcName,&dwLen) && dwType == UPD_REG_PROCESSOR_NAME_TYPE) { localProcName[MAX_PATH-1] = 0 ; // Force to terminate if it is not. lpProcName = localProcName; } dwLen = sizeof(localProcVolume) ; if (groupSubKey.RegQueryValueEx(UDP_REG_PROCESSOR_VOLPREFIX_VAL,&dwType,(LPBYTE)localProcVolume,&dwLen) && dwType == UDP_REG_PROCESSOR_VOLPREFIX_TYPE) { localProcVolume[MAX_PATH-1] = 0 ; // Force to terminate if it is not. lpProcVolName = localProcVolume; } DWORD dwTimeout; if (groupSubKey.GetRegValue(UDP_REG_PROCESSOR_TIMEOUT_VAL,(LPBYTE)&dwTimeout,sizeof(DWORD))) { dwProgTimeout = dwTimeout ; } } } Lock();
// 创建user proc的时候需要prefix/process name/timeout值 UserDriverProcessor * pNewProc = new UserDriverProcessor(dwUserProcGroupID,lpProcName,lpProcVolName,dwProgTimeout); if (pNewProc!=NULL && !pNewProc->Init()) { // Init Fails. delete pNewProc; pNewProc = NULL; } if (pNewProc) { if (InsertObjectBy(pNewProc)==NULL) { // Something Really Bad. ASSERT(FALSE); delete pNewProc; pNewProc = NULL; } } Unlock(); return pNewProc; }; |
// 创建user mode driver host进程 BOOL UserDriverProcessor::Init() { BOOL bReturn = FALSE; Lock(); if (m_lpProcName!=NULL && m_lpProcVolName!=NULL) { // We have to lauch processor with the value name // 第二个参数,就是m_lpProcVolName,也就是注册表项ProcVolPrefix的值,作为参数传递给m_lpProcName bReturn = CreateProcess( m_lpProcName, m_lpProcVolName, NULL, NULL, FALSE, 0, NULL, NULL, NULL,&m_ProcessInformation); if (bReturn) { DWORD dwWaitTicks = m_dwTimewout ; while (!SendIoControl(IOCTL_USERPROCESSOR_ALIVE,NULL,0,NULL,0,NULL) && dwWaitTicks!=0) { if (WaitForSingleObject(m_ProcessInformation.hProcess,TIMOUT_INTERVAL)== WAIT_OBJECT_0) break; if (dwWaitTicks<=TIMOUT_INTERVAL ) break; else dwWaitTicks-= TIMOUT_INTERVAL; } bReturn = (WaitForSingleObject(m_ProcessInformation.hProcess,1)!= WAIT_OBJECT_0); DEBUGMSG(ZONE_WARNING && !dwWaitTicks,(TEXT("REFLECTOR! Processor %s %s is not responding!/r/n"),m_lpProcName,m_lpProcVolName)); DEBUGMSG(ZONE_ERROR && !bReturn,(TEXT("REFLECTOR! Processor %s %s is dead!!!/r/n"),m_lpProcName,m_lpProcVolName)); } } Unlock(); ASSERT(bReturn); return bReturn; } |
至此,User Mode Driver Host进程就已经创建起来了。
在上述的过程中,值的注意的一点是,创建User Mode Driver Host进程的时候,传入参数m_lpProcVolName 将会用来向系统注册User Mode Driver Host的API时候使用。它形如$udevice_XXX [***为group ID]。
例如udevice.exe的入口函数WinMain中会去调用RegisterAFSAPI来向系统注册FS API,其中就用到了上面传入的m_lpProcVolName,这部分代码如下:
// This routine is the entry point for the device manager. It simply calls the device // management DLL's entry point. // 这里就是udevice.exe的入口 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmdShow) { int status=-1; DEBUGMSG(1,(TEXT("udevice.exe %s /r/n"),lpCmdLine)); DEBUGREGISTER(NULL);
if (RegisterAFSAPI(lpCmdLine)) { BOOL bRet = (WaitForPrimaryThreadExit(INFINITE) == WAIT_OBJECT_0) ; ASSERT(bRet); } else ASSERT(FALSE); DEBUGMSG(1,(TEXT("exiting udevice.exe/r/n"))); UnRegisterAFSAPI(); return status; } |
// 调用CreateAPISet和RegisterAPISet创建udevice.exe的api,以方便后续的操作 // 这里传入的参数就是创建udevice.exe和servicesd.exe进程的时候传入的参数 // cflector中创建user mode driver host进程时候传入的参数 BOOL RegisterAFSAPI (LPCTSTR VolString) { g_pUserDriverContainer = new UserDriverContainer () ;
ghDevFileApiHandle = CreateAPISet("W32D", NUM_UD_SERV_APIS, UdServApiMethods, UdServApiSigs ); BOOL bReturn = FALSE; if (ghDevFileApiHandle!=INVALID_HANDLE_VALUE) bReturn =RegisterAPISet(ghDevFileApiHandle, HT_FILE | REGISTER_APISET_TYPE); ASSERT(ghDevFileApiHandle!=INVALID_HANDLE_VALUE && bReturn) ;
//Before any process can become a handle server, the process must create and register a handle-based API set with CreateAPISet and RegisterAPISet. ghDevFSAPI = CreateAPISet("UDFA", ARRAYSIZE(gpfnDevFSAPIs), (const PFNVOID *) gpfnDevFSAPIs, gDevFSSigs); RegisterAPISet (ghDevFSAPI, HT_AFSVOLUME | REGISTER_APISET_TYPE); ASSERT(ghDevFSAPI!=NULL); giFSIndex = RegisterAFSName(VolString); ASSERT(giFSIndex!=(DWORD)-1); if (ghDevFSAPI!=NULL && giFSIndex!=(DWORD)-1) { gfRegisterOK = RegisterAFSEx(giFSIndex, ghDevFSAPI, 0 , AFS_VERSION, AFS_FLAG_HIDDEN|AFS_FLAG_KMODE); ASSERT(gfRegisterOK); } if (gfRegisterOK) ghExit = CreateEvent(NULL,TRUE,FALSE,NULL) ; ASSERT(ghExit!=NULL);
return (g_pUserDriverContainer && gfRegisterOK && ghExit && ghDevFileApiHandle!=INVALID_HANDLE_VALUE && bReturn); } |
这里创建的API如下:
// 下面定义的api是用作udevice.exe的管理 extern "C" BOOL UD_DevDeviceIoControl(DWORD dwContent, DWORD dwIoControlCode, PVOID pInBuf, DWORD nInBufSize, PVOID pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned, OVERLAPPED *pOverlapped); const PFNVOID UdServApiMethods[] = { (PFNVOID)UD_DevCloseFileHandle, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)0, (PFNVOID)UD_DevDeviceIoControl, };
#define NUM_UD_SERV_APIS (sizeof(UdServApiMethods)/sizeof(UdServApiMethods[0]))
const ULONGLONG UdServApiSigs[NUM_UD_SERV_APIS] = { FNSIG1(DW), // CloseFileHandle FNSIG0(), FNSIG5(DW,I_PTR,DW,O_PDW,IO_PDW), // ReadFile FNSIG5(DW,O_PTR,DW,O_PDW,IO_PDW), // WriteFile FNSIG2(DW,O_PDW), // GetFileSize FNSIG4(DW,DW,O_PDW,DW), // SetFilePointer FNSIG2(DW,O_PDW), // GetDeviceInformationByFileHandle FNSIG1(DW), // FlushFileBuffers FNSIG4(DW,O_PDW,O_PDW,O_PDW), // GetFileTime FNSIG4(DW,IO_PDW,IO_PDW,IO_PDW), // SetFileTime FNSIG1(DW), // SetEndOfFile, FNSIG8(DW, DW, IO_PTR, DW, IO_PTR, DW, O_PDW, IO_PDW), // DeviceIoControl }; |
// 下面定义的api用于FSD的管理 // 因为device.dll和udevice.exe的功能类似,所以两个组件都向系统注册了一组自己的api // User Device Manager filesystem APIs static CONST PFNVOID gpfnDevFSAPIs[] = { (PFNVOID)DEVFS_StubFunction, (PFNVOID)NULL, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_IoControl, (PFNVOID)DEVFS_StubFunction, (PFNVOID)DEVFS_StubFunction, }; static CONST ULONGLONG gDevFSSigs[] = { FNSIG0(), // CloseVolume FNSIG0(), // FNSIG0(), // CreateDirectoryW FNSIG0(), // RemoveDirectoryW FNSIG0(), // GetFileAttributesW FNSIG0(), // SetFileAttributesW FNSIG0(), // CreateFileW FNSIG0(), // DeleteFileW FNSIG0(), // MoveFileW FNSIG0(), // FindFirstFileW FNSIG0(), // CeRegisterFileSystemNotification FNSIG0(), // CeOidGetInfo FNSIG0(), // PrestoChangoFileName FNSIG0(), // CloseAllFiles FNSIG0(), // GetDiskFreeSpace FNSIG0(), // Notify FNSIG0(), // CeRegisterFileSystemFunction FNSIG0(), // FindFirstChangeNotification FNSIG0(), // FindNextChangeNotification FNSIG0(), // FindCloseNotification FNSIG0(), // CeGetFileNotificationInfo FNSIG9(DW, DW, DW, IO_PTR, DW, IO_PTR, DW, O_PDW, IO_PDW), // FsIoControlW FNSIG0(), // SetFileSecurityW FNSIG0(), // GetFileSecurityW }; |
注意上面注册的API的调用方法。其实Reflector Service中就是通过DeviceIoControl()调用上面注册的API的,从而和User Mode Driver Host进行通信。
上面二.1中已经粘贴出来设备管理器在创建User Mode Driver设备时,会去调用Reflector Service的函数Reflector_Create(),进而调用到函数CReflector * CreateReflector()。
函数CReflector * CreateReflector()完成了两个功能:
第一,查询OS中是否已经存在所需要的User Mode Driver Host,如果没有,则创建一个。
查询类UDPContainer维护的UserDriverProcessor实例链表中是否存在所需要的UserDriverProcessor,也即User Mode Driver Host。
其实,上面也曾提到,系统中会在设备管理器初始化的时候创建一个类UDPContainer的实例,并通过g_pUDPContainer指向。
如果没有找到对应的User Mode Driver Host,则创建一个对应的进程。
另外,需要指出的是,一个特定的User Mode Driver Host对应一个UserDriverProcessor实例,而每一个UserDriverProcessor实例下面维护了一张链表m_ReflectorList,可以挂很多个设备驱动。
已经在前面详细的进行过描述,这一章节不再进行描述。
第二, 为设备创建CReflector实例,并将其加入到对应的User Mode Driver Host维护的链表m_ReflectorList中。
上面已经提到,User Mode Driver Host和UserDriverProcessor是一一对应的,UserDriverProcessor下面维护了使用该User Mode Driver Host的所有User Mode Driver。
在这里,一个具体的User Mode Driver的存在形式就是类CReflector实例。
接下来,我会着重的描述这部分得代码实现。
有关函数CReflector * CreateReflector()的实现,我画了一个流程图,如下:
前面已经提到,User Mode Driver存在的具体形式就是挂在类UserDriverProcessor上的一个CReflector实例。上述流程图中红颜色方框中的部分就是创建CReflector的实现。接下来,我会详细的去分析这部分代码。
函数UserDriverProcessor::CreateReflector()到CeFsIoControl()过程
从函数UserDriverProcessor::CreateReflector()的实现可以看到,其为当前的User Mode Driver创建一个CReflector类实例,每一个User Mode Driver都对应一个类 CReflector的实例。
CReflector * UserDriverProcessor::CreateReflector( LPCTSTR lpPreFix, LPCTSTR lpDrvName, DWORD dwFlags) { CReflector * pRetReflect = NULL; Lock(); if (!m_fTerminate) { // 这里看清楚,非常重要 // 将this传递给创建的CReflector对象,然后把CReflector对象加入到类UserDriverProcessor维护的链表中,这样UserDriverProcessor和CReflector就可以互相的调用 // 实际上,每一个user mode driver host对应一个UserDriverProcessor实例,而每一个user mode driver对应一个CReflector实例 pRetReflect = new CReflector(this,lpPreFix, lpDrvName, dwFlags);
// 接下来调用的CReflector::Init()就没有做任何事情 if (pRetReflect && !pRetReflect->Init()) { delete pRetReflect; pRetReflect = NULL; } if (pRetReflect) { m_ReflectorList.InsertObjectBy(pRetReflect) ; } CheckReflectorForEmpty(); } Unlock(); return pRetReflect;
} |
下面对类CReflector的构造函数进行分析,这里是Driver Load到内存的精髓,中间牵扯到很多的类和变量。
类CReflector的构造函数会将类UserDriverProcessor对象指针填充到其自己的成员变量m_pUDP,后面会用它来调用类UserDriverProcessor的Method。然后,调用CReflector::FnDriverLoad()去创建了类对象UserDriver,并获取User Mode Driver Host进程向系统注册API的 Handle。前者记录在类CReflector的成员m_dwData中,而后者记录到m_hUDriver,后续会将其保存到注册项”ReflectorHandle”下,供CEDDK的Bus Driver使用。
// 类CReflector的构造函数 // 参数: // pUDP:其User Mode Driver Host的对象指针 CReflector::CReflector(UserDriverProcessor * pUDP, LPCTSTR lpPreFix, LPCTSTR lpDrvName,DWORD dwFlags, CReflector * pNext) : m_pUDP(pUDP) , m_pNextReflector(pNext) { m_pFileFolderList = NULL; m_pPhysicalMemoryWindowList = NULL; m_dwData = 0 ; m_fUserInit = FALSE ; m_hInterruptHandle = NULL; m_hIsrHandle = NULL; m_hUDriver = INVALID_HANDLE_VALUE ; m_DdkIsrInfo.cbSize = sizeof(m_DdkIsrInfo); m_DdkIsrInfo.dwSysintr = 0; m_DdkIsrInfo.dwIrq = 0;
if (m_pUDP) { m_pUDP->AddRef(); FNDRIVERLOAD_PARAM fnDriverLoad; fnDriverLoad.dwAccessKey = (DWORD)this; fnDriverLoad.dwFlags = dwFlags; BOOL fCpyOk = FALSE; __try { if (lpPreFix==NULL) { // Special case. for naked entry. fnDriverLoad.Prefix[0] = 0 ; fCpyOk = TRUE; } else fCpyOk =SUCCEEDED(StringCbCopy(fnDriverLoad.Prefix,sizeof(fnDriverLoad.Prefix),lpPreFix));
fCpyOk =(fCpyOk && SUCCEEDED(StringCbCopy(fnDriverLoad.DriverName,sizeof(fnDriverLoad.DriverName),lpDrvName))); } __except(EXCEPTION_EXECUTE_HANDLER) { fCpyOk = FALSE ; }
if (fCpyOk) { FNDRIVERLOAD_RETURN driversReturn; driversReturn.dwDriverContext = 0 ; driversReturn.hDriversAccessHandle = INVALID_HANDLE_VALUE ;
// m_hUDriver此时仍为INVALID_HANDLE_VALUE,后面会对其进行初始化 // 函数FnDriverLoad()调用了之前user mode driver host进程向系统注册的api--DEVFS_IoControl(IOCTL_USERDRIVER_LOAD) // 完成了两个功能: 1.创建了类对象UserDriver,并将其填充到driversReturn.dwDriverContext // 2.将user mode driver host进程向系统注册的api的handle填充到driversReturn.hDriversAccessHandle // 后面会将该Handle记录到注册表中,然后CEDDK的Bus Driver会去获取该值并调用相应的功能 BOOL bRet = FnDriverLoad(fnDriverLoad,driversReturn); if (bRet) { m_dwData = driversReturn.dwDriverContext; // 找到了,找到了!!!!!!! // 这里会为类CReflector的成员m_hUDriver赋值,它的值就是driversReturn.hDriversAccessHandle, // 也就是指向了udevice.exe或者其他user mode driver host向系统注册api的handle if (driversReturn.hDriversAccessHandle!=NULL && driversReturn.hDriversAccessHandle!= INVALID_HANDLE_VALUE && m_hUDriver==INVALID_HANDLE_VALUE) { bRet = DuplicateHandle((HANDLE)m_pUDP->GetUserDriverPorcessorInfo().dwProcessId,driversReturn.hDriversAccessHandle, GetCurrentProcess(),&m_hUDriver, 0,FALSE,DUPLICATE_SAME_ACCESS); if (!bRet || m_hUDriver == 0 || m_hUDriver == INVALID_HANDLE_VALUE) { ASSERT(FALSE); m_hUDriver = INVALID_HANDLE_VALUE; } } } DEBUGMSG(ZONE_WARNING && !bRet,(L"CReflector: FnDriverLoad return FALSE!")); } } } |
有关上面提到的函数CReflector::FnDriverLoad()实际上调用了udevice.dll(或其它的User Mode Driver Host)向系统注册的API DEVFS_IoControl()。
调用的Stack如下:
CReflector::FnDriverLoad()àCReflector::SendIoControl()àUserDriverProcessor::SendIoControl()àCeFsIoControl()。
相关代码如下:
// 具体完成的工作就是创建UserDriver对象并将其使用类UserDriverContainer进行维护 // 然后将其地址赋值给((PFNDRIVERLOAD_RETURN)driversReturn)->dwDriverContext 并返回,同时返回的还有udevice.exe向系统注册api handle BOOL class CReflector::FnDriverLoad(FNDRIVERLOAD_PARAM& DriverLoadParam, FNDRIVERLOAD_RETURN& driversReturn) { return SendIoControl(IOCTL_USERDRIVER_LOAD,&DriverLoadParam, sizeof(DriverLoadParam),&driversReturn, sizeof(FNDRIVERLOAD_RETURN) ,NULL); } |
// io control of creflector // 该函数究竟调用到哪里,和m_hUDriver密切相关 // 在m_hUDriver初始化之前,调用到DEVFS_IoControl // 初始化之后,调用到UD_DevDeviceIoControl // m_hUDriver的初始化在类CReflector的构造函数的后半部分中完成 BOOL CReflector::SendIoControl(DWORD dwIoControlCode,LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned) { PREFAST_ASSERT(m_pUDP); DWORD dwOldCaller = UTlsPtr()[ PRETLS_DRIVER_DIRECT_CALLER ] ; UTlsPtr()[ PRETLS_DRIVER_DIRECT_CALLER ] = GetCallerProcessId(); BOOL fReturn = FALSE; // m_hUDriver的初始化是在类CReflector的后半段完成的,所以前半段的时候还是会调用到m_pUDP->SendIoControl的 if (m_hUDriver != INVALID_HANDLE_VALUE) // 没错,这里就调用到了UD_DevDeviceIoControl,呵呵,因为m_hUDriver就是这些api的handle // 有关这一部分内容,可以参照m_hUDriver的定义和初始化[CReflector的构造函数中定义] // 其实,这里就是CReflector和user mode driver host进行交互的地方 fReturn = DeviceIoControl(m_hUDriver, dwIoControlCode,lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned,NULL); else // 实际上这里调用的就是DEVFS_IoControl,因为DEVFS_IoControl所在文件中,已经将 fReturn = m_pUDP->SendIoControl(dwIoControlCode,lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned); UTlsPtr()[ PRETLS_DRIVER_DIRECT_CALLER ] = dwOldCaller; return fReturn ; }; |
BOOL class UserDriverProcessor::SendIoControl(DWORD dwIoControlCode,LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned) { //This function sends an I/O control to a file system driver (FSD). It may not be supported by all file system drivers, and not all implementations support all I/O controls // uses CeFsIoControl to forward the device manager's request to the User Mode Driver Host. The User Mode Driver Host then parses the request to either load, unload, or call the parent bus driver's entry. // 简单说的说,CeFsIoControl实际上调用的就是MyFSD_FsIoControl,只不过直接调用CeFsIoControl的相当于封装了一下 return CeFsIoControl(m_lpProcVolName, dwIoControlCode,lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned,NULL); } |
最终被调用的函数CeFsIoControl()在实质上调用udevice.exe向系统注册的API DEVFS_IoControl()(或其它的User Mode Driver Host向系统注册的其它的API)。
未完待续(请看下一篇)