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)。

       未完待續(請看下一篇)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章