User Mode Driver Management介绍(一)

User Mode Driver介绍

       Windows CE 6.0中引入了User Mode Driver的概念,可是无论是网上,还是各个芯片厂商提供的方案中,都很少提及这方面的内容。

       本文以小郭对存储管理和User Mode Driver Host的理解为基础,结合具体的代码实现,从User Mode Driver的加载流程的角度分析了存储管理对User Mode Driver的处理过程。

       由于个人知识水平和项目经验有限,难免有些地方错误,还望你不吝指出,特此说明。

一.      User Mode DriverKernel Mode Driver

1User Mode DriverKernel Mode Driver

       顾名思义,User Mode Driver就是运行在User ModeDriver,而Kernel Mode Driver是运行在Kernel ModeDriver

       User ModeKernel Mode的有很多差别,首先,运行在Kernel Mode的程序一般都是处理系统的核心功能的程序,而运行在User Mode多是一些与应用有关的程序或者驱动,再者,运行在User Mode下的程序不可以进行物理内存映射和调用中断处理相关函数,而运行在Kernel Mode下的程序和驱动却没有这方面的限制。

       在这里,我着重说的是User ModeKernel Mode下内存访问权限的差别。

       运行在User Mode下的程序合法的虚拟内存空间访问权限如下:

ReadVM_USER_BASE0x00010000~ VM_KMODE_BASE0x80000000

WriteVM_USER_BASE0x00010000~ VM_SHARED_HEAP_BASE0x70000000

       而运行在Kernel Mode下的程序可以自由地访问4GB的内存空间(对32位机而言)。

       在老版本的Windows CE5.0中,所有的Driver和应用程序都运行在User Mode下。操作系统提供了API SetKMode()来在User ModeKernel 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是一个很老的概念。

2Windows CE 6.0User Mode Driver Framework简介

       User Mode Driver Framework包括两部分,第一部分是User Mode Driver ReflectorReflector/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 HostI/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.0PPT介绍。

      

二.      User Mode Driver Host的加载

1User Mode Driver Host Manager的初始化

       Device.dllkernel.dll加载起来的后,Device.dll中的函数StartDeviceManager()将会被kernel.dll调用并执行。该函数会去调用InitUserProcMgr()以完成对User Mode Driver Process进行管理的一系列初始化工作。

       函数InitUserProcMgr()完成的初始化工作非常简单,就是创建并初始化类UDPContainer UDServiceContainer实例,并赋值给全局变量g_pUDPContainerg_pServiceContainer,然后调用类的初始化函数。

       UDPContainer用来维护所有User Mode Driver Host的进程。在其初始化过程中会创建一个类UDPContainer的对象,然后调用InsertObjectBy插入到一个莫名其妙的链表中,另外到注册表[HKEY_LOCAL_MACHINE/Drivers]下查找默认的User Group名字和Prefix,对于那些没有指定使用哪个User Group也即User Mode Driver HostDriver,将会使用这个User Mode Driver Host进行管理。

       UDPContainer可以用下图来描述:

 

       UDServiceContainer同样是用来维护所有User Mode Driver HostReflector Service,每一个User Mode Driver都会存在一个类UserDriverService的实例,而UDServiceContainer则维护着这些UserDriverService结点。在它的初始化过程中会调用API CreateAPISet()RegisterAPISet()向系统注册ReflServApiMethods[]ReflServApiMethods包括了函数REFL_DevCloseFileHandleREFL_DevDeviceIoControl

       当调用CEDDK BUS DriverBusIoControl() 以及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 HostDriver,将会使用这个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 HostDriver,将会使用这个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 ;

     }

}

2. User Mode Driver Host进程的创建过程

1> 检查注册表判断是否是User Mode Driver

    当设备管理器调用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;

            }

        }

2> User Mode Drive Host进程的创建过程

       从上面粘贴出来的代码中可以看到,设备管理器中会去调用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进程就已经创建起来了。

3User Mode Driver HostReflector Service之间的通信

       在上述的过程中,值的注意的一点是,创建User Mode Driver Host进程的时候,传入参数m_lpProcVolName 将会用来向系统注册User Mode Driver HostAPI时候使用。它形如$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;

}

// 调用CreateAPISetRegisterAPISet创建udevice.exeapi,以方便后续的操作

// 这里传入的参数就是创建udevice.exeservicesd.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.dlludevice.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进行通信。

三.User Mode Driver的加载

1User Mode DriverLoad到内存的过程

1> 流程概述

       上面二.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 HostUserDriverProcessor是一一对应的,UserDriverProcessor下面维护了使用该User Mode Driver Host的所有User Mode Driver

       在这里,一个具体的User Mode Driver的存在形式就是类CReflector实例。

       接下来,我会着重的描述这部分得代码实现。

 

       有关函数CReflector * CreateReflector()的实现,我画了一个流程图,如下:

 

       前面已经提到,User Mode Driver存在的具体形式就是挂在类UserDriverProcessor上的一个CReflector实例。上述流程图中红颜色方框中的部分就是创建CReflector的实现。接下来,我会详细的去分析这部分代码。

2> 函数UserDriverProcessor::CreateReflector()在调用User Mode Driver Host之前的Stack

       函数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维护的链表中,这样UserDriverProcessorCReflector就可以互相的调用

        // 实际上,每一个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,后面会用它来调用类UserDriverProcessorMethod。然后,调用CReflector::FnDriverLoad()去创建了类对象UserDriver,并获取User Mode Driver Host进程向系统注册API Handle。前者记录在类CReflector的成员m_dwData中,而后者记录到m_hUDriver,后续会将其保存到注册项”ReflectorHandle”,CEDDKBus 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进程向系统注册的apihandle填充到driversReturn.hDriversAccessHandle

              //                          后面会将该Handle记录到注册表中,然后CEDDKBus Driver会去获取该值并调用相应的功能

              BOOL bRet = FnDriverLoad(fnDriverLoad,driversReturn);

              if (bRet) {

                   m_dwData = driversReturn.dwDriverContext;

                   // 找到了,找到了!!!!!!!

                   // 这里会为类CReflector的成员m_hUDriver赋值,它的值就是driversReturn.hDriversAccessHandle,

                   // 也就是指向了udevice.exe或者其他user mode driver host向系统注册apihandle

                   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就是这些apihandle

         // 有关这一部分内容,可以参照m_hUDriver的定义和初始化[CReflector的构造函数中定义]

         // 其实,这里就是CReflectoruser 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)。

       未完待续(请看下一篇)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值