Windows CE 6.0的内核传输无关层(KITL)分析(2)

 

3Windows CE 6.0 KITL初始化过程分析

WinCE6.0中,内核调用OEMInit()函数对目标平台进行初始化过程时,需要启动KITL的支持,但由于OEMInit()函数属于oal.exe文件,不能像WinCE5.0那样直接调用初始化KITL的函数,根据Windows CE 6.0中共享变量或函数的互访原则(见Windows CE 6.0启动分析部分),它们只能通过系统定义的OEMGLOBALNKGLOBAL两个结构体来实现,当在编译选项(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函数调用顺序比较熟悉的话,后面的内容就可以不用再看啦

你可能感兴趣的:(Windows CE 6.0的内核传输无关层(KITL)分析(2))