(接上一篇)

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 && nInBufSize>=sizeof(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_pUserDriverContainer==NULL)

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: couldn't 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,L"Init",m_hLib);

m_fnPreDeinit = (pDeinitFn)GetDMProcAddr(pEffType,L"PreDeinit",m_hLib);

m_fnDeinit = (pDeinitFn)GetDMProcAddr(pEffType,L"Deinit",m_hLib);

m_fnOpen = (pOpenFn)GetDMProcAddr(pEffType,L"Open",m_hLib);

m_fnPreClose = (pCloseFn)GetDMProcAddr(pEffType,L"PreClose",m_hLib);

m_fnClose = (pCloseFn)GetDMProcAddr(pEffType,L"Close",m_hLib);

m_fnRead = (pReadFn)GetDMProcAddr(pEffType,L"Read",m_hLib);

m_fnWrite = (pWriteFn)GetDMProcAddr(pEffType,L"Write",m_hLib);

m_fnSeek = (pSeekFn)GetDMProcAddr(pEffType,L"Seek",m_hLib);

m_fnControl = (pControlFn)GetDMProcAddr(pEffType,L"IOControl",m_hLib);

m_fnPowerup = (pPowerupFn)GetDMProcAddr(pEffType,L"PowerUp",m_hLib);

m_fnPowerdn = (pPowerupFn)GetDMProcAddr(pEffType,L"PowerDown",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,(L"UserDriver::LoadDriver: dwStatus = 0x%x",dwStatus));

return (dwStatus == ERROR_SUCCESS);

}

return FALSE;

}

至此,分析完毕。

2.User 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,(L"CReflector::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_PRIORITY+55;

}

}

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].dwLen>=sizeof(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_pUSBDStaticAddr=0x%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是同一个概念。

2.User Mode Driver及Host的典型注册表配置

User Mode Driver Registry

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/Serial]

"SysIntr"=dword:13

"IoBase"=dword:02F8

"IoLen"=dword:8

"DeviceArrayIndex"=dword:0

"Prefix"="COM"

"Flags"=dword:10

;"ProcGroup"=dword:2

"IClass"="{CC5195AC-BA49-48a0-BE17-DF6D1B0173DD}"

"Dll"="Com16550.Dll"

"Order"=dword:0

"Priority"=dword:0

; Turn on follows for Installable ISR (isr16550 supporting SOFTWARE FIFO

;"Irq"=dword:3

;"IsrDll"="isr16550.dll"

;"IsrHandler"="ISRHandler"

User Mode Driver Host Registry

[HKEY_LOCAL_MACHINE/Drivers/ProcGroup_0002]

"ProcName"="udevice.exe"    ; Dummy for Service.exe now.

"ProcVolPrefix"="$services"

"Privilege"=dword:xxxxxx    ; Processor Privilege  Bit setting.

任何问题请发送mail到guopeixin@126.com,或在此留言。

User Mode Driver Management 介绍(二)相关推荐

  1. User Mode Driver Management介绍(一)

    User Mode Driver介绍 Windows CE 6.0中引入了User Mode Driver的概念,可是无论是网上,还是各个芯片厂商提供的方案中,都很少提及这方面的内容. 本文以小郭对存 ...

  2. 蒙特卡罗方法介绍( 二)

    蒙特卡罗方法介绍( 二) 一.蒙特卡罗求解定积分 蒙特卡洛方法求解定积分有两种方法,一种是上一节中讲的投点法,另外一种是期望法(也称平均值法). 1.1 投点法 给出如下曲线f(x)f(x)f(x), ...

  3. Python Pillow(PIL)库的用法介绍(二)

    Python Pillow(PIL)库的用法介绍(二) 在上一篇文章中介绍了Pillow库的一些基本用法,参考:https://blog.csdn.net/weixin_43790276/articl ...

  4. Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(一) Lucene.Net中,分词是核心库之一,当然,也可以将它独立出来.目前Lucene.Net的分词库很不完善,实际应用价值不高.唯 ...

  5. abp(net core)+easyui+efcore实现仓储管理系统——解决方案介绍(二)

    abp(net core)+easyui+efcore实现仓储管理系统--解决方案介绍(二) 参考文章: (1)abp(net core)+easyui+efcore实现仓储管理系统--解决方案介绍( ...

  6. 尼康d850相机参数测试软件,新功能介绍二:景深合成与自动调焦_尼康 D850_数码影像评测-中关村在线...

    ·新功能介绍二:景深合成与自动调焦 对于D850来说,机身也加入了非常多的新功能,这里还逐一介绍一下.首先我们要说的机身的景深合成功能.什么是景深合成?相信很多朋友都了解,相机在很多环境下,景深太浅是 ...

  7. 企业级360°全方位用户画像:项目介绍[二]

    絮叨两句: 博主是一名软件工程系的在校生,利用博客记录自己所学的知识,也希望能帮助到正在学习的同学们 人的一生中会遇到各种各样的困难和折磨,逃避是解决不了问题的,唯有以乐观的精神去迎接生活的挑战 少年 ...

  8. 《C#零基础入门之百识百例》(五十二)封装介绍 -- 二维多项式求值

    C#零基础入门 面向对象 -- 封装介绍 -- 二维多项式求值 前言 一,封装概念 二,封装属性 三,实例练习 -- 二维多项式求值 3.1 题目描述 3.2 问题分析 3.3 参考代码 前言 本文属 ...

  9. C语言生成midi文件,介绍二个wave 转 midi的开源项目

    //lihaoyxj@gmail.com 在进行音频处理时,往往需要把wav数据转成其它格式,而作为音乐编辑类的软件,更多则是要以midi格式去处理. 在这里简单介绍二款开源的有关音频中和midi相关 ...

最新文章

  1. 怎么判断前轮左右的位置_如何判定汽车前面左右轮的位置?大家有什么经验?...
  2. Spring AOP两种使用方式以及如何使用解析
  3. 简单说说我对几位认识的号主的印象
  4. 一文看懂什么是MQ消息队列
  5. 计算机机培训论文,一篇文章了解机器学习
  6. 【刷题】LOJ 6007 「网络流 24 题」方格取数
  7. 单片机歌曲代码大全_对于 51 单片机的四大误区!
  8. C++_auto_ptr与unique_ptr智能指针
  9. [pytorch] 深度学习分割网络U-net的pytorch模型实现 原创 2017年03月08日 21:48:21 标签: python / 深度学习 / 生物图
  10. 深入理解 Android 消息机制原理
  11. 三个点在同一个半圆的概率_圆形水池中的四只小鸭子出现在同一个半圆中的概率是?...
  12. VS2010/MFC编程入门之三十三(常用控件:标签控件Tab Control 下)
  13. Java解析魔兽争霸3录像W3G文件(一):Header
  14. Java 堆排序(大根堆及小根堆)
  15. 摄像头视频直播方案比较之方案一:萤石云
  16. 【vue】pdf转图片
  17. Photoshop如何把图片转为RGB颜色模式
  18. Byte measurements
  19. 便宜制作服务器,组建私有云:除了购买NAS服务器外试试自己手工打造吧!
  20. QWebEngineView如何忽略SSL证书错误

热门文章

  1. Linux 指令大全(3)
  2. php实现解压功能的函数
  3. 页面中color颜色值_计算机毕业设计中实现一个简易美观的登录界面
  4. gitlab修改配置重启_centos7下gitlab安装说明
  5. 人工智能状态图matlab,人工智能—TensorFlow(七):matplotlib图形可视化
  6. preparing automatic repair怎么解决_单一窗口插卡登录频繁提示安装IC卡控件的终极解决办法...
  7. Mike and distribution(思维)
  8. php5 php4,自动实现php4和php5环境的切换......
  9. java给定_Java – 在给定示例中使用super()
  10. mysql做前端_MySQL 还可以这样做