网站建设及报价方案,开锁公司网站模板,有域名如何做网站,杭州网站制作工具#xff08;接上一篇#xff09;
3 调用User Mode Driver Host API来将Driver Load到内存 CeFsIoControl()实际上是一个对文件系统驱动FSD进行操作的函数#xff0c;需要传入文件夹名字和IoControlCode。 帮助文档中对该函数的解释如下#xff1a; This function send…接上一篇
3 调用User Mode Driver Host API来将Driver Load到内存 CeFsIoControl()实际上是一个对文件系统驱动FSD进行操作的函数需要传入文件夹名字和IoControlCode。 帮助文档中对该函数的解释如下 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. Syntax BOOL CeFsIoControl( LPCWSTR pszDir, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped ); Parameters pszDir [in] String representing the system mount point. Set to NULL to access the object store file system. dwIoControlCode [in] File system I/O control code. lpInBuffer [in] Long pointer to a buffer that contains the data required to perform the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not require input data. nInBufferSize [in] Size, in bytes, of the buffer pointed to by lpInBuffer. lpOutBuffer [out] Long pointer to a buffer that receives the output data for the operation. Set to NULL if dwIoControlCode does not produce output data. nOutBufferSize [in] Size, in bytes, of the buffer pointed to by lpOutBuffer. lpBytesReturned [out] Long pointer to a variable that receives the size, in bytes, of the data stored in the buffer pointed to by lpOutBuffer. lpOverlapped [in] Ignored. Set to NULL. Return Value TRUE indicates success. FALSE indicates failure. If this function is not supported by an FSD, it returns FALSE, and GetLastError returns ERROR_NOT_SUPPORTED. 实际上被执行的DEVFS_IoControl(IOCTL_USERDRIVER_LOAD)代码如下 // udevice-ioctonrol // 该api已经向系统注册 // 该函数向系统注册后可以通过CeFsIoControl调用 extern C BOOL DEVFS_IoControl(DWORD dwContent, HANDLE hProc, DWORD dwIoControlCode, PVOID pInBuf, DWORD nInBufSize, PVOID pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned, OVERLAPPED *pOverlapped) { //hProc is only from Kernel. BOOL bRet FALSE; DWORD dwOldLastError GetLastError(); SetLastError (ERROR_INVALID_PARAMETER); // dwIoControlCode. switch (dwIoControlCode) { case IOCTL_USERDRIVER_LOAD: // 完成一些结构体的建立并没有真正的开始初始化 // 具体完成的工作就是创建UserDriver对象并将其使用类UserDriverContainer进行维护 // 然后将其地址赋值给((PFNDRIVERLOAD_RETURN)pOutBuf)-dwDriverContext 并返回同时返回的还有udevice.exe向系统注册api handle if (pInBuf nInBufSizesizeof(FNDRIVERLOAD_PARAM) pOutBuf nOutBufSize sizeof(FNDRIVERLOAD_RETURN)) { UserDriver * pUserDriver; // 创建UserDriver并将其加入到g_pUserDriverContainer指向的链表中 pUserDriver CreateDriverObject(*(PFNDRIVERLOAD_PARAM)pInBuf); // udevice.exe在下面将ghDevFileApiHandle返回给调用者其实就是reflector以方便其操作user mode driver host向系统注册的api if (pUserDriver) { // 这里将udevice.exe中创建的UserDriver实例地址填充到pOutBuf-dwDriverContext ((PFNDRIVERLOAD_RETURN)pOutBuf)-dwDriverContext (DWORD) pUserDriver ; // We also create Handle base API set. HANDLE hDev CreateAPIHandle(ghDevFileApiHandle, pUserDriver ); if (hDev!NULL hDev!INVALID_HANDLE_VALUE) { pUserDriver-SetUDriverHandle(hDev); pUserDriver-AddRef(); } // 这里将udevice.exe向系统注册API的Handle值填充到pOutBuf- hDriversAccessHandle ((PFNDRIVERLOAD_RETURN)pOutBuf)-hDriversAccessHandle hDev; if (pBytesReturned) *pBytesReturned sizeof(FNDRIVERLOAD_RETURN); } bRet (pUserDriver!NULL); } break; } } 从上面的这段代码也可以看到User Mode Driver的实例UserDriver其实是由DEVFS_IoControl()àCreateDriverObject()创建也即由udevice.exe创建通过Reflector Service调用API的方式获取其实例这也是为什么说User Mode Driver是由User Mode Driver Host直接进行管理的也是有关描述User Mode Driver的功能框图中总是将User Mode Driver囊括在User Mode Driver Host内部的原因。 正如下面的图中所描述的 CreateDriverObject()完成创建一个类UserDriver实例的任务该函数实际上最终会调用到UserDriver::LoadDriver()在这里将完成将User Mode Driver Load到内存并获取其导出流接口的任务最终这些流接口的导出函数指针将会记录在UserDriver的成员m_fnInit/ m_fnPreDeinit/m_fnOpen/m_fnClose/m_fnControl函数指针中。 呵呵分析了这么久大家终于看到将Driver Load到内存的位置了吧累死我了。 // 创建UserDriver对象并将其插入到g_pUserDriverContainer指向的链表中同时还完成了将driver load到内存中并提取导出函数指针的功能 // 该链表实际上的最小单元结点是类UserDriverContainer inline UserDriver * CreateDriverObject(FNDRIVERLOAD_PARAM fnDriverLoadParam) { if (g_pUserDriverContainerNULL) return NULL; UserDriver* pReturnDriver CreateUserModeDriver(fnDriverLoadParam) ; //new UserDriver(fnDriverLoadParam,NULL); if (pReturnDriver ! NULL !pReturnDriver-Init()) { delete pReturnDriver; pReturnDriver NULL; } if (pReturnDriver !g_pUserDriverContainer-InsertNewDriverObject(pReturnDriver)) { delete pReturnDriver; pReturnDriver NULL; } return pReturnDriver; } UserDriver * CreateUserModeDriver(FNDRIVERLOAD_PARAM fnDriverLoadParam) { return new UserDriver(fnDriverLoadParam,NULL); } virtual BOOL UserDriver:: Init() { return LoadDriver(); }; // 之类完成load user mode driver的过程但是因为执行init所以并没有加载到系统中 BOOL UserDriver::LoadDriver() { DEBUGMSG(ZONE_ACTIVE, (_T(UDEVICE!CreateDevice: loading driver DLL %s/r/n), m_fnDriverLoadParam.DriverName)); if (m_hLib NULL ) { DWORD dwStatus ERROR_SUCCESS; // 这里根据注册表的配置决定加载驱动的方式即LoadDriver() or Loadlibrary() m_hLib (m_fnDriverLoadParam.dwFlags DEVFLAGS_LOADLIBRARY) ? (::LoadLibrary(m_fnDriverLoadParam.DriverName)) : (::LoadDriver(m_fnDriverLoadParam.DriverName)); if (!m_hLib) { DEBUGMSG(ZONE_WARNING, (_T(UDEVICE!CreateDevice: couldnt load %s -- error %d/r/n), m_fnDriverLoadParam.DriverName, GetLastError())); dwStatus ERROR_FILE_NOT_FOUND; } else { LPCTSTR pEffType m_fnDriverLoadParam.Prefix ; m_fnInit (pInitFn)GetDMProcAddr(pEffType,LInit,m_hLib); m_fnPreDeinit (pDeinitFn)GetDMProcAddr(pEffType,LPreDeinit,m_hLib); m_fnDeinit (pDeinitFn)GetDMProcAddr(pEffType,LDeinit,m_hLib); m_fnOpen (pOpenFn)GetDMProcAddr(pEffType,LOpen,m_hLib); m_fnPreClose (pCloseFn)GetDMProcAddr(pEffType,LPreClose,m_hLib); m_fnClose (pCloseFn)GetDMProcAddr(pEffType,LClose,m_hLib); m_fnRead (pReadFn)GetDMProcAddr(pEffType,LRead,m_hLib); m_fnWrite (pWriteFn)GetDMProcAddr(pEffType,LWrite,m_hLib); m_fnSeek (pSeekFn)GetDMProcAddr(pEffType,LSeek,m_hLib); m_fnControl (pControlFn)GetDMProcAddr(pEffType,LIOControl,m_hLib); m_fnPowerup (pPowerupFn)GetDMProcAddr(pEffType,LPowerUp,m_hLib); m_fnPowerdn (pPowerupFn)GetDMProcAddr(pEffType,LPowerDown,m_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 (!(m_fnInit m_fnDeinit) || (m_fnOpen !m_fnClose) || (!m_fnRead !m_fnWrite !m_fnSeek !m_fnControl) || (m_fnPreClose !m_fnPreDeinit)) { DEBUGMSG(ZONE_WARNING, (_T(UDEVICE!CreateDevice: illegal entry point combination in driver DLL %s/r/n), m_fnDriverLoadParam.DriverName)); dwStatus ERROR_INVALID_FUNCTION; } } DEBUGMSG(ZONE_ACTIVE,(LUserDriver::LoadDriver: dwStatus 0x%x,dwStatus)); return (dwStatus ERROR_SUCCESS); } return FALSE; } 至此分析完毕。
2User Mode Driver的初始化调用
1 流程概述 User Mode Driver的初始化就是由Device Manager调用Reflector_InitEx()进而调用到CReflector::InitEx()完成所有Driver初始化的过程。 初始化过分为三步
第一步 调用Reflector Service的导出函数REFL_CreateDeviceServiceHandle(CReflector * pReflect)来获取其向系统注册的API Handle并记录到注册表中供后续CEDDK Bus Driver使用。
第二步 获取Driver的注册表信息包括Memory Window/IO Window/ISR等信息并去创建Memory Window供后续Reflector Service检查物理内存访问权限的时候使用。
第三步 调用CReflector::FnInit()来完成最终的Driver加载动作。 我画了一张流程图如下图所示 下面将对这三步操作分别进行描述和分析。
2 获取Reflector Service向系统注册API Handle Reflector Service的函数REFL_CreateDeviceServiceHandle(CReflector * pReflect)在Driver初始化的时候调用用来创建一个类UserDriverService实例并将其插入到类UDServiceContainer * g_pServiceContainer维护的链表中。然后将UserDriverService实例与Reflector Service向系统注册的API Handle关联起来This function creates a handle and associates the handle to the specified handle object.并返回给调用者。 接着将Reflector Service的操作Handle保存到注册表项ReflectorHandle下。 // dwInfo: 传入的就是activekey的path BOOL CReflector::InitEx(DWORD dwInfo, LPVOID lpvParam) { BOOL bRet FALSE; Lock(); if (m_pUDP) { FNINIT_PARAM fnInitParam; fnInitParam.dwCallerProcessId GetCallerProcessId(); fnInitParam.dwDriverContent m_dwData; // Findout the m_dwInfo is Activete Registry or not. CRegistryEdit activeReg(HKEY_LOCAL_MACHINE, (LPCTSTR)dwInfo); if (activeReg.IsKeyOpened() (SUCCEEDED(StringCbCopy(fnInitParam.ActiveRegistry,sizeof(fnInitParam.ActiveRegistry),(LPCTSTR)dwInfo)))) { // 实际上也就是Reflector Service的操作handle可以用来操作Reflector Service在device.dll初始化时向系统注册的的API // 这些API包括REFL_DevDeviceIoControl和REFL_DevCloseFileHandle // REFL_DevDeviceIoControl完成的功能有所有User Mode下不能够完成的有关物理内存和中断函数的操作实际执行的就是CReflector::ReflService HANDLE hServiceHandle REFL_CreateDeviceServiceHandle(this); if (hServiceHandle !NULL ) { HANDLE hClientHandle NULL; // 下面dumplicate的目的就是hClientHandle hServiceHandle 的内容一旦一个内容发生了变化另外一个也将会变化 BOOL fResult DuplicateHandle( GetCurrentProcess(),hServiceHandle, (HANDLE)m_pUDP-GetUserDriverPorcessorInfo().dwProcessId,hClientHandle, 0,FALSE,DUPLICATE_SAME_ACCESS); ASSERT(fResult); // 将上面dumplicate的Handle也即Reflector Service的操作Handle保存到注册表项ReflectorHandle下 // CEDDK的BUS Driver中可以通过该handle来操作REFL_DevDeviceIoControl和REFL_DevCloseFileHandle // if (fResult) { DWORD dwAccessKey (DWORD)hClientHandle; BOOL fSuccess activeReg.RegSetValueEx(DEVLOAD_UDRIVER_REF_HANDLE_VALNAME, DEVLOAD_UDRIVER_REF_HANDLE_VALTYPE, (PBYTE)dwAccessKey,sizeof(dwAccessKey)); ASSERT(fSuccess); } CloseHandle(hServiceHandle); } // It is copies Registry Correctly. fnInitParam.dwInfo NULL; } else { fnInitParam.dwInfo dwInfo; } CRegistryEdit deviceReg((LPCTSTR)dwInfo); if (deviceReg.IsKeyOpened()) { deviceReg.GetIsrInfo(m_DdkIsrInfo); DDKWINDOWINFO dwi; // This function creates a handle that can be used for accessing a bus. // 调用CEDDK的API来创建一个访问Bus Driver的API HANDLE hParentBus CreateBusAccessHandle((LPCTSTR)dwInfo); // 获取memory window和io window deviceReg.GetWindowInfo(dwi); // 为每一个window创建一个类CPhysMemoryWindow对象 InitAccessWindow(dwi,hParentBus); if (hParentBus) CloseBusAccessHandle(hParentBus); } fnInitParam.lpvParam lpvParam; // 调用driver的初始化函数 bRet FnInit(fnInitParam) ; } Unlock(); DEBUGMSG(ZONE_WARNING !bRet,(LCReflector::InitEx: return FALSE!)); return bRet; } // 这里创建一个handle可以通过该handle调用REFL_DevDeviceIoControl和REFL_DevCloseFileHandle HANDLE REFL_CreateDeviceServiceHandle(CReflector * pReflect) { HANDLE hReturn NULL; if (g_pServiceContainer) { UserDriverService * pNewService new UserDriverService(pReflect); if (pNewService pNewService-Init()) { // 获取m_hDevFileApiHandle和UserDriverService关联起来的handle // 并将其返回给调用者方便后续对reflserv api的调用 // 实际上在CReflector::InitEx()中会调用该函数并把上述的handle存放到注册表键ReflectorHandle下 hReturn pNewService-CreateAPIHandle(g_pServiceContainer-GetApiSetHandle()); // 注意这里的插入变量pNewService其指向了类UserDriverService的实例 // 每一个类UserDriverService的实例在构造函数中和CReflector * pReflect进行关联 // 后续调用REFL_DevDeviceIoControl的时候实际上最终会执行CReflector * pReflect的ReflService函数 if (hReturn!NULL g_pServiceContainer-InsertObjectBy(pNewService)NULL ) { // Fail to insert. CloseHandle(hReturn); hReturn NULL; } } if (hReturn NULL pNewService!NULL) { delete pNewService; } } ASSERT(hReturn!NULL); return hReturn; } // 帮助文档中提到该函数用来创建一个特殊的handle该handle和一个特殊的handle object联系到了一块 // 这里特殊的handle object就是this用来和它联系到一块的handle是hAPISetHandle创建的结果就是CreateAPIHandle的返回值 HANDLE UserDriverService::CreateAPIHandle(HANDLE hAPISetHandle) { return( ::CreateAPIHandle(hAPISetHandle, this)); }
3 获取注册表信息并建立Memory Window 如上面代码中CReflector::InitEx(DWORD dwInfo, LPVOID lpvParam)实现过程我将代码段粘贴如下 CRegistryEdit deviceReg((LPCTSTR)dwInfo); if (deviceReg.IsKeyOpened()) { deviceReg.GetIsrInfo(m_DdkIsrInfo); DDKWINDOWINFO dwi; // This function creates a handle that can be used for accessing a bus. // 调用CEDDK的API来创建一个访问Bus Driver的API HANDLE hParentBus CreateBusAccessHandle((LPCTSTR)dwInfo); // 获取memory window和io window deviceReg.GetWindowInfo(dwi); // 为每一个window创建一个类CPhysMemoryWindow对象 InitAccessWindow(dwi,hParentBus); if (hParentBus) CloseBusAccessHandle(hParentBus); } 首先调用GetIsrInfo()去获取ISR信息然后调用GetWindowInfo()去查询Memory信息。并将前者的结果存放在类CReflector变量m_DdkIsrInfo中后续Reflector Service调用的时候会使用到。 然后调用CEDDK Bus函数CreateBusAccessHandle(active register)来创建Bus操作Handle然后利用GetWindowInfo()查询的结果去创建类CPhysMemoryWindow实例。 // 这里维护的是一张内存访问的window // 这里根据user传入的memory window和io window创建多个CPhysMemoryWindow实例 // memory windows和io windows都是怎么得到的呢 BOOL CReflector::InitAccessWindow( DDKWINDOWINFO dwi, HANDLE hParentBus ) { Lock(); // 从这里可以看到user可以建立多张内存访问的window // dwi.memWindows:Array of dwNumMemWindows DEVICEWINDOW structures, each of which describes a memory resource window for (DWORD dwIndex 0; dwIndex dwi.dwNumMemWindows dwIndex MAX_DEVICE_WINDOWS; dwIndex) { PHYSICAL_ADDRESS PhysicalAddress { dwi.memWindows[dwIndex].dwBase,0 }; CPhysMemoryWindow * pNewWindows new CPhysMemoryWindow(PhysicalAddress,dwi.memWindows[dwIndex].dwLen, 0,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber,hParentBus, m_pPhysicalMemoryWindowList); if (pNewWindows !pNewWindows-Init()) { delete pNewWindows; pNewWindows NULL; }; if (pNewWindows) m_pPhysicalMemoryWindowList pNewWindows; } // dwi.ioWindows:Array of dwNumIoWindows DEVICEWINDOW structures, each of which describes an I/O resource window. for (dwIndex 0; dwIndex dwi.dwNumIoWindows dwIndex MAX_DEVICE_WINDOWS; dwIndex) { PHYSICAL_ADDRESS PhysicalAddress { dwi.ioWindows[dwIndex].dwBase,0 }; CPhysMemoryWindow * pNewWindows new CPhysMemoryWindow(PhysicalAddress,dwi.ioWindows[dwIndex].dwLen, 1,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber,hParentBus, m_pPhysicalMemoryWindowList); if (pNewWindows !pNewWindows-Init()) { delete pNewWindows; pNewWindows NULL; }; if (pNewWindows) m_pPhysicalMemoryWindowList pNewWindows; } Unlock(); return TRUE; } CPhysMemoryWindow::CPhysMemoryWindow( PHYSICAL_ADDRESS PhysicalAddress, ULONG NumberOfBytes,ULONG AddressSpace,INTERFACE_TYPE InterfaceType,ULONG BusNumber, HANDLE hParentBus,CPhysMemoryWindow *pNext) : m_pNextFileFolder(pNext) , m_PhBusAddress(PhysicalAddress) , m_dwSize(NumberOfBytes) , m_AddressSpace(AddressSpace) { m_PhSystemAddresss.QuadPart 0 ; m_pStaticMappedUserPtr NULL; m_dwStaticMappedLength 0; // 该函数将一个总线设备上的设备物理地址转换为总线的系统物理地址会根据Interface_type的类型进行相应的转换一般用于PCI或者ISA总线 BOOL bRet TranslateBusAddr(hParentBus, InterfaceType,BusNumber,m_PhBusAddress,m_AddressSpace,m_PhSystemAddresss); } 需要指出的是同一个Reflector中可能存在多个类CPhysMemoryWindow的实例也即多个Memory Window通过类Reflector:: m_pPhysicalMemoryWindowList可以对其进行遍历。 这些Window会在CEDDK Bus Driver通过DeviceIoControl()调用REFL_DevDeviceIoControl() àCReflector::ReflService()完成内存操作时候使用到。
4 调用Driver的初始化函数完成加载 上面函数CReflector::InitEx()中调用CReflector::FnDriverLoad进而调用User Mode Driver Host向系统注册的API来完成Driver的加载任务。 相关代码如下 // 具体完成的工作就是创建UserDriver对象并将其使用类UserDriverContainer进行维护 // 然后将其地址赋值给((PFNDRIVERLOAD_RETURN)driversReturn)-dwDriverContext 并返回同时返回的还有udevice.exe向系统注册api handle BOOL 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 ; }; // 不知道UD_DevDeviceIoControl和DEVFS_IoControl有什么差别 // 前者用于udevice的管理后者用于device fs的管理 extern C BOOL UD_DevDeviceIoControl(DWORD dwContent, DWORD dwIoControlCode, PVOID pInBuf, DWORD nInBufSize, PVOID pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned, OVERLAPPED *pOverlapped) { DWORD dwOldLastError GetLastError(); SetLastError (ERROR_INVALID_PARAMETER); // 这个dwContent在Driver Load到内存的时候调用DEVFS_IoControl(IOCTL_USERDRIVER_LOAD)创建 // 它就是UserDriver实例用作udevice.exe和user mode driver进行通信 UserDriver * pUserDriver (UserDriver *)dwContent; if (!pUserDriver) { ASSERT(FALSE); return FALSE; } BOOL bRet FALSE; switch (dwIoControlCode) { case IOCTL_USERDRIVER_INIT: // 这里会去执行user mode driver的初始化动作也即加载动作 if (pInBuf!NULL nInBufSize sizeof(FNINIT_PARAM)) { bRet pUserDriver-DriverInit((*(PFNINIT_PARAM) pInBuf)); } break; } } // 这里也会去调用user mode driver初始化函数也就是说driver也可以在这里加载 // 实际上driver的加载就是调用这里完成的 BOOL UserDriver::DriverInit(FNINIT_PARAM fnInitParam) { BOOL bRet FALSE; if (m_fnInit m_dwInitData 0 ) { // 获取操作handle这些handle相当的重要呀呵呵 if (fnInitParam.dwInfo 0 m_hReflector NULL) { // We have ActiveRegistry. DetermineReflectorHandle(fnInitParam.ActiveRegistry); } DWORD dwContent (fnInitParam.dwInfo!0 ?fnInitParam.dwInfo : (DWORD)fnInitParam.ActiveRegistry); DWORD dwOldCaller UTlsPtr()[ PRETLS_DRIVER_DIRECT_CALLER ] ; UTlsPtr()[ PRETLS_DRIVER_DIRECT_CALLER ] fnInitParam.dwCallerProcessId ; __try { // 终于找到Driver的Init()函数了开心 m_dwInitData m_fnInit(dwContent,fnInitParam.lpvParam); bRet (m_dwInitData!0); } __except(EXCEPTION_EXECUTE_HANDLER) { bRet FALSE; } UTlsPtr()[ PRETLS_DRIVER_DIRECT_CALLER ] dwOldCaller; if (!bRet m_hReflector) { CloseHandle(m_hReflector); m_hReflector NULL; } } ASSERT(bRet); return bRet; } 四User Mode Driver对物理内存和中断函数的访问
1创建Bus访问Handle
函数HANDLE CreateBusAccessHandle(LPCTSTR lpActiveRegPath) 该函数用于创建一个可以访问Bus设备驱动的句柄一个客户端驱动(Client Driver)会在它的XXX_Init函数中调用该函数来获得Bus设备的句柄。lpActiveRegPath为Bus设备的注册表路径返回值为句柄。 Sample Code CSerialPDD::CSerialPDD(LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj ) : CRegistryEdit(lpActivePath) , m_pMdd(pMdd) , m_pHwObj(pHwObj) { m_hParent CreateBusAccessHandle(lpActivePath); m_PowerHelperHandle INVALID_HANDLE_VALUE; m_hPowerLock NULL; // Initial Open Count. m_lOpenCount 0; m_ulCommErrors 0; m_PowerCallbackThread NULL; if (!GetRegValue(PC_REG_SERIALPRIORITY_VAL_NAME,(LPBYTE)m_dwPriority256,sizeof(DWORD))) { m_dwPriority256 DEFAULT_CE_THREAD_PRIORITY55; } }
2物理内存的映射
BOOL TranslateBusAddr(HANDLE hBusAccess, INTERFACE_TYPE InterfaceType, ULONG BusNumber, PHYSICAL_ADDRESS BusAddress, PULONG AddressSpace, PPHYSICAL_ADDRESS TranslatedAddress) hBusAccess 总线设备的句柄 interface_Type 接口类型或总线类型
BusNumber 总线号实际使用中这个值为0可供选择的值有 typedef enum _INTERFACE_TYPE { InterfaceTypeUndefined -1, Internal, Isa, Eisa, MicroChannel, TurboChannel, PCIBus, VMEBus, NuBus, PCMCIABus, CBus, MPIBus, MPSABus, ProcessorInternal, InternalPowerBus, PNPISABus, PNPBus, MaximumInterfaceType } INTERFACE_TYPE, *PINTERFACE_TYPE; BusAddress 总线上的物理地址 AddressSpace 作为输入0x0为内存空间0x1为IO空间对于非X86体系的CPU来说不支持IO空间也即AddressSpace必须设置为0 TranslatedAddress 转换后的系统物理地址 该函数将一个总线设备上的设备物理地址转换为总线的系统物理地址会根据Interface_type的类型进行相应的转换一般用于PCI或者ISA总线。 对于User Mode Driver来说如果映射的物理地址空间不在注册表中声明的话则会映射失败。 /* 其实下面的这个代码是.0上的代码其中调用的一些API在6.0上已经被废弃 但是它的结构比较清晰便于理解Device Physical Address/Bus Physical Address/Virtual Address之间的转换所以粘贴出来。 6.0上的代码可以参照下一个函数 */ BOOL CPdd2443Uart::MapHardware() { if (m_pRegVirtualAddr !NULL) return TRUE; // Get IO Window From Registry DDKWINDOWINFO dwi; if ( GetWindowInfo( dwi)!ERROR_SUCCESS || dwi.dwNumMemWindows 1 || dwi.memWindows[0].dwBase 0 || dwi.memWindows[0].dwLen 0x30) //0x2c) return FALSE; DWORD dwInterfaceType; if (m_ActiveReg.IsKeyOpened() m_ActiveReg.GetRegValue( DEVLOAD_INTERFACETYPE_VALNAME, (PBYTE)dwInterfaceType,sizeof(DWORD))) { dwi.dwInterfaceType dwInterfaceType; } // Translate to System Address. PHYSICAL_ADDRESS ioPhysicalBase { dwi.memWindows[0].dwBase, 0}; ULONG inIoSpace 0; if (TranslateBusAddr(m_hParent,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber, ioPhysicalBase,inIoSpace,ioPhysicalBase)) { // Map it if it is Memeory Mapped IO. m_pRegVirtualAddr MmMapIoSpace(ioPhysicalBase, dwi.memWindows[0].dwLen,FALSE); } ioPhysicalBase.LowPart S3C2443_BASE_REG_PA_INTR ; ioPhysicalBase.HighPart 0; inIoSpace 0; if (TranslateBusAddr(m_hParent,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber, ioPhysicalBase,inIoSpace,ioPhysicalBase)) { m_pINTregs (S3C2443_INTR_REG *) MmMapIoSpace(ioPhysicalBase,sizeof(S3C2443_INTR_REG),FALSE); } return (m_pRegVirtualAddr!NULL m_pINTregs!NULL); } /* 6.0上的代码可以参照下面的Sample Code */ BOOL CBulverdeOTG::MapHardware() { DDKWINDOWINFO dwi; if (GetWindowInfo(dwi)ERROR_SUCCESS dwi.dwNumMemWindows!0) { if (dwi.memWindows[0].dwBase dwi.memWindows[0].dwLensizeof(BULVERDE_USBD_REG)) { PHYSICAL_ADDRESS ioPhysicalBase {dwi.memWindows[0].dwBase,0 }; ULONG AddressSpace 0 ; if (!BusTransBusAddrToVirtual( m_hParent,Internal,0, ioPhysicalBase, sizeof(BULVERDE_USBD_REG),AddressSpace, (PPVOID)m_pUSBDReg) || AddressSpace!0) { m_pUSBDReg NULL; } AddressSpace 0 ; if (!BusTransBusAddrToStatic( m_hParent,Internal,0, ioPhysicalBase, sizeof(BULVERDE_USBD_REG),AddressSpace, m_pUSBDStaticAddr) || AddressSpace!0) { m_pUSBDStaticAddr NULL; } DEBUGMSG(ZONE_OTG_FUNCTION,(TEXT(CBulverdeOTG::MapHardware: m_pUSBDReg 0x%x,m_pUSBDStaticAddr0x%x/r/n),m_pUSBDReg,m_pUSBDStaticAddr)); PHYSICAL_ADDRESS gpioPhysicalBase {BULVERDE_BASE_REG_PA_GPIO,0 }; v_pGPIORegs (P_XLLP_GPIO_T) MmMapIoSpace(gpioPhysicalBase, sizeof(XLLP_GPIO_T), FALSE); } } ASSERT(m_pUSBDReg!NULL m_pUSBDStaticAddr!NULL v_pGPIORegs!NULL); return (m_pUSBDReg!NULL m_pUSBDStaticAddr!NULL v_pGPIORegs!NULL); } 其中上面红色标记的函数GetWindowInfo(dwi)是类CPdd2443UartBase Class CRegistryEdit的一个Method必须在Class CRegistryEdit进行过初始化之后才能调用最终调用的是DDKReg_GetWindowInfo()。有关Base Class CRegistryEdit的描述很简单可以参照Public下的源代码或者网上朋友们的解释。 其实在不建议TranslateBusAddr()和MmMapIoSpace()配合来使用了因为TransBusAddrToVirtual function instead of calling HalTranslateBusAddress and MmMapIoSpace。 在Windows CE 6.0中函数TransBusAddrToVirtual ()已经被废弃掉可以使用函数BusTransBusAddrToVirtual()来替代。 有关解释如下
BOOL BusTransBusAddrToVirtual(IN HANDLE hBusAccess, IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, IN PHYSICAL_ADDRESS BusAddress, IN ULONG Length, IN OUT PULONG AddressSpace, OUT PPVOID MappedAddress) hBusAccess 总线设备的句柄 interface_Type 接口类型或总线类型 BusNumber 总线号 BusAddress 总线上的物理地址 Length 被映射的地址空间的大小 AddressSpace 0x0为内存空间0x1为IO空间 TranslatedAddress 映射后的总线的系统虚拟地址 该函数将一个总线上的设备物理地址转换为总线的系统虚拟地址实际上是先调用了TranslateBusAddr函数获得总线的系统物理地址再调用MmMapIoSpace函数该函数可以在User Mode下调用进行虚拟地址映射。
3 关闭Bus操作Handle 直接调用函数CloseBusAccessHandle()关闭Handle就行了。
VOID CloseBusAccessHandle(HANDLE hBusAccess) 该函数用于关闭所访问的总线设备客户端驱动(Client Driver)会在它的XXX_Deinit函数中调用该函数hBusAccess是由CreateBusAccessHandle创建的句柄。 附
1这里所说的User Mode Driver Reflector和Reflector Service是同一个概念。
2User Mode Driver及Host的典型注册表配置 User Mode Driver Registry [HKEY_LOCAL_MACHINE/Drivers/BuiltIn/Serial] SysIntrdword:13 IoBasedword:02F8 IoLendword:8 DeviceArrayIndexdword:0 PrefixCOM Flagsdword:10 ;ProcGroupdword:2 IClass{CC5195AC-BA49-48a0-BE17-DF6D1B0173DD} DllCom16550.Dll Orderdword:0 Prioritydword:0 ; Turn on follows for Installable ISR (isr16550 supporting SOFTWARE FIFO ;Irqdword:3 ;IsrDllisr16550.dll ;IsrHandlerISRHandler User Mode Driver Host Registry [HKEY_LOCAL_MACHINE/Drivers/ProcGroup_0002] ProcNameudevice.exe ; Dummy for Service.exe now. ProcVolPrefix$services Privilegedword:xxxxxx ; Processor Privilege Bit setting. 任何问题请发送mail到guopeixin126.com或在此留言。