(3)Windows CE 6.0
的KITL初始化過程分析
在WinCE6.0中,核心調用OEMInit()函數對目標平台進行初始化過程時,需要啟動KITL的支援,但由於OEMInit()函數屬於oal.exe檔案,不能像WinCE5.0那樣直接調用初始化KITL的函數,根據Windows CE 6.0中共用變數或函數的互訪原則(見Windows CE 6.0啟動分析部分),它們只能通過系統定義的OEMGLOBAL和NKGLOBAL兩個結構體來實現,當在編譯選項(Build
Options)中選中Enable KITL時,編譯器就會將kitl.dll動態連結程式庫連結到到核心中,在OEMGLOBAL結構體定義了利用KITLOEM宏將kitl.dll的入口函數KitlDllMain編譯到系統中條件,這是系統連結的庫為oemmain_statickitl.lib,下面為OEMGLOBAL結構體中KITL的定義部分:
// Platform specific information passed from OAL to KITL.
NULL, // LPVOID pKitlInfo
#ifdef KITLOEM
KitlDllMain, // KITL entry point (KITL is part of OEM)
#else
NULL, // KITL entry point (KITL is in a separate DLL)
#endif
一旦kitl.dll啟動時,在其入口函數KitlDllMain中將KITLIoctl函數地址賦給NKGLOBAL的pfnKITLIoctl指標,同時也從核心啟動參數結構體(KDataStruct )g_pKData中擷取OEMGLOBAL結構體的指標,這樣便可以實現共用變數或函數的互訪。即OAL中的OEMInit()函數通過NKGLOBAL結構體間接調用KITLIoctl
函數啟動KITL的初始化。
$(_PRIVATEROOT)\WINCEOS\COREOS\NK\KITL\ethdbg.c
BOOL WINAPI KitlDllMain (HINSTANCE DllInstance, DWORD dwReason, LPVOID Reserved)
{
if (DLL_PROCESS_ATTACH == dwReason) {
PFN_KLIBIOCTL pfnKLibIoctl = (PFN_KLIBIOCTL) Reserved;
g_kpriv.pfnExtKITLIoctl = ExtKITLIoctl;
(* pfnKLibIoctl) ((HANDLE)KMOD_KITL, IOCTL_KLIB_KITL_INIT, NULL, 0, &g_kpriv, sizeof (g_kpriv), NULL);
g_pKData = g_kpriv.pKData;
g_pprcNK = g_kpriv.pprcNK;
g_pNKGlobal = g_pKData->pNk;
g_pOemGlobal = g_pKData->pOem;
g_pNKGlobal->pfnKITLIoctl = KITLIoctl;
#ifdef DEBUG
g_pNKGlobal->pKITLDbgZone = &dpCurSettings;
#endif
}
return TRUE;
}
$(_PRIVATEROOT)\WINCEOS\COREOS\NK\OEMSTUB\oemstub.c
void OEMInit (void)
{
g_pOemGlobal->pfnInitPlatform ();
}
$(_PRIVATEROOT)\WINCEOS\COREOS\NK\NKSTUB\kitlstub.c
BOOL KITLIoctl (DWORD dwCode, LPVOID pInBuf, DWORD nInSize, LPVOID pOutBuf, DWORD nOutSize, LPDWORD pcbRet)
{
return g_pNKGlobal->pfnKITLIoctl (dwCode, pInBuf, nInSize, pOutBuf, nOutSize, pcbRet);
}
$(_PLATFORMROOT)\xsbase270\src\oal\OalLib\Init.c
void OEMInit()
{
volatile XSBASE270_CPLD_REGS *pCPLDRegs = (volatile XSBASE270_CPLD_REGS *) OALPAtoVA(XSBASE270_BASE_REG_PA_CPLD, FALSE);
volatile XSBASE270_MEMBCR_REGS *pMEMBCRRegs = (volatile XSBASE270_MEMBCR_REGS *) OALPAtoVA(XSBASE270_BASE_PA_BCR, FALSE);
……
// Initialize the KITL connection if required.
KITLIoctl(IOCTL_KITL_STARTUP, NULL, 0, NULL, 0, NULL);
…….
OALMSG(OAL_FUNC, (L"-OEMInit\r\n"));
}
$(_PRIVATEROOT)\WINCEOS\COREOS\NK\KITL\ethdbg.c
BOOL KITLIoctl (DWORD dwIoControlCode, LPVOID lpInBuf, DWORD nInBufSize, LPVOID lpOutBuf, DWORD nOutBufSize, LPDWORD lpBytesReturned)
{
BOOL retval = FALSE;
switch (dwIoControlCode) {
case IOCTL_KITL_STARTUP:
retval = OEMKitlStartup ();
break;
……
return retval;
}
根據上述分析和上面五段代碼,我們再理一下函數的調用順序。
核心調用$(_PRIVATEROOT)\WINCEOS\COREOS\NK\OEMMAIN\oemstub.c中的OEMInit函數,該函數通過OEMGLOBAL結構體中的函數指標pfnInitPlatform(在oemglobal.c中初始化)調用$(_PLATFORMROOT)\xsbase270\src\oal\OalLib\Init.c中的OEMInit函數,該函數在調用KITLIoctl函數時,實際上調用$(_PRIVATEROOT)\WINCEOS\COREOS\NK\NKSTUB\kitlstub.c中的KITLIoctl,KITLIoctl函數通過NKGLOBAL結構體中的pfnKITLIoctl函數指標再調用$(_PRIVATEROOT)\WINCEOS\COREOS\NK\KITL\ethdbg.c中的KITLIoctl函數。Windows
CE 6.0中函數調用好像是在繞圈子,這也是它的奧妙之處。在理順上述函數調用順序之後,後面函數的調用便相當簡單啦。
OEMInit 函數中調用KITLIoctl(IOCTL_KITL_STARTUP, NULL, 0, NULL, 0, NULL)函數的第一個參數為IOCTL_KITL_STARTUP,根據上述函數調用循序關聯性,該KITLIoctl函數最終被調用的位置為$(_PRIVATEROOT)\WINCEOS\COREOS\NK\KITL\ethdbg.c中的KITLIoctl函數,從原始碼可以發現,IOCTL_KITL_STARTUP對於的選擇語句為retval = OEMKitlStartup (),即函數調用回到類似Windows
CE 5.0中OALKitlStart()函數,Windows CE 6.0 KITL的移植步驟中提到需要將Windows CE 5.0中OALKitlStart()函數重新命名為OEMKitlStartup()函數。如果你對Windows CE 5.0的KITL函數調用順序比較熟悉的話,後面的內容就可以不用再看啦