新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > S3C2410下WinCE6.0的啟動過程詳解

        S3C2410下WinCE6.0的啟動過程詳解

        作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
        通過前兩篇文章的介紹,我們已經(jīng)知道NBOOT用來引導EBOOT,繼而EBOOT加載并引導WinCE操作系統(tǒng)(NK)。那么,WinCE6.0啟動過程又是怎樣的呢?本文基于S3C2410的平臺做一個詳細的分析。需要說明的是,WinCE6.0的整個啟動過程對于同一類型的MCU來說大同小異,如S3C2410和PXA270同屬ARM平臺的MCU,所以他們的啟動過程是類似的,可以說唯一的不同就在OAL處,而WinCE操作系統(tǒng)的啟動正是從OAL開始的。

        OAL(OEM Adaptation Layer)即OEM適配層,它的主要作用是在移植WinCE到新的硬件平臺時減少操作系統(tǒng)的修改,通俗的說就是為WinCE操作系統(tǒng)抹平MCU的差異,使其能很方便的在不同MCU上運行。所以,OAL包括了和系統(tǒng)硬件通訊的最底層代碼。內(nèi)核則通過OAL跟硬件進行交互。邏輯上,OAL是介于CE內(nèi)核和設(shè)備硬件之間的一個代碼層,是一個抽象的概念。物理上,OAL和其他一些庫一起鏈接成可執(zhí)行文件,在WinCE6.0中對應(yīng)的文件是OAL.exe,這是OAL的客觀存在。WinCE6.0中的OAL跟先前的OAL比,是有一些變化的,它從內(nèi)核中分離出來成為OAL.exe,而內(nèi)核則變成了Kernel.dll。這樣做的好處是可以單獨升級OAL。但整體的OAL結(jié)構(gòu)并沒有改變,OEM函數(shù)保持一致,OAL和Kernel的接口由共享結(jié)構(gòu)NKGLOBAL實現(xiàn)。這一部分的具體內(nèi)容下一篇再做介紹。下圖所示為WinCE6.0的OAL設(shè)計。

        本文引用地址:http://www.104case.com/article/201611/318750.htm

        在移植WinCE到新的硬件平臺時,創(chuàng)建OAL是最復雜的任務(wù)之一。一般來說,最簡單的方法是拷貝一個跟新的硬件平臺類似的且成熟的OAL,然后根據(jù)硬件的不同進行修改,使其滿足目標硬件的特定要求。這里不展開說明,回頭再單獨整理。
        從EBOOT到OAL.exe的跳轉(zhuǎn)是從OEMLaunch()開始的,函數(shù)OEMLaunch()中調(diào)用Launch(dwPhysLaunchAddr),它的實現(xiàn)代碼如下:



        Code
        LEAF_ENTRYLaunch

        ldrr2,=PhysicalStart
        ldrr3,=(VIR_RAM_START-PHY_RAM_START)

        subr2,r2,r3

        movr1,#0x0070;DisableMMU
        mcrp15,0,r1,c1,c0,0
        nop
        movpc,r2;JumptoPStart
        nop

        ;MMU&cachesnowdisabled.

        PhysicalStart

        movr2,#0
        mcrp15,0,r2,c8,c7,0;FlushtheTLB
        movpc,r0;Jumptoprogramwearelaunching.

        函數(shù)Launch()的參數(shù)為物理地址,因為在跳轉(zhuǎn)之前已將MMU關(guān)閉。該地址可通過VIEWBIN來查看,如下圖所示:


        如何確定這個地址對應(yīng)的是NK.bin中的哪一個文件呢,先前說是OAL.exe,證據(jù)何在。在PB6.0中增加了瀏覽NK.bin的功能,我們可以利用此功能查看NK.bin的詳細情況,如下圖所示:



        從上圖中可以看出0x80205394處對應(yīng)的是NK.exe,而這里的NK.exe即為OAL.exe。
        至此,我們已經(jīng)知道EBOOT是如何跳轉(zhuǎn)到OAL.exe中的了。接下來繼續(xù)看OAL.exe的執(zhí)行過程。
        OAL的啟動代碼如下:

        Code
        LEAF_ENTRYStartUp

        ;ComputetheOEMAddressTablesphysicaladdressand
        ;loaditintor0.KernelStartexpectsr0tocontain
        ;thephysicaladdressofthistable.TheMMUisnt
        ;turnedonuntilwellintoKernelStart.

        addr0,pc,#g_oalAddressTable-(.+8)
        blKernelStart

        OAL的啟動代碼和EBOOT的啟動代碼經(jīng)常復用,但為了代碼的簡潔,最好還是分開實現(xiàn),而且在EBOOT中如果已經(jīng)初始化了相關(guān)硬件,那么OAL的啟動代碼就可以省去那部分工作,可以很簡練,如上面的代碼所示。

        可以看出,OAL的啟動代碼又調(diào)用了函數(shù)KernelStart(),而這個函數(shù)是在文件C:WINCE600PRIVATEWINCEOSCOREOSNKLDRARMarmstart.s中實現(xiàn)的,代碼如下:

        Code
        LEAF_ENTRYKernelStart

        movr11,r0;(r11)=&OEMAddressTable(savepointer)

        ;figureoutthevirtualaddressofOEMAddressTable
        movr1,r11;(r1)=&OEMAddressTable(2ndargumenttoVaFromPa)
        blVaFromPa
        movr6,r0;(r6)=VAofOEMAddressTable

        ;convertbaseofPTstoPhysicaladdress
        ldrr4,=PTs;(r4)=virtualaddressofFirstPT
        movr0,r4;(r0)=virtualaddressofFirstPT
        movr1,r11;(r1)=&OEMAddressTable(2ndargumenttoPaFromVa)
        blPaFromVa

        movr10,r0;(r10)=ptrtoFirstPT(physical)

        ;Zerooutpagetables&kerneldatapage

        movr0,#0;(r0-r3)=0stostore
        movr1,#0
        movr2,#0
        movr3,#0
        movr4,r10;(r4)=firstaddresstoclear
        addr5,r10,#KDEnd-PTs;(r5)=lastaddress+1
        18stmiar4!,{r0-r3}
        stmiar4!,{r0-r3}
        cmpr4,r5
        blo%B18

        ;readthearchitectureinformation
        blGetCpuId
        movr5,r0LSR#16;r5>>=16
        andr5,r5,#0x0000000f;r5&=0x0000000f==architectureid

        ;Setup2ndlevelpagetabletomapthehighmemoryareawhichcontainsthe
        ;firstlevelpagetable,2ndlevelpagetables,kerneldatapage,etc.
        ;(r5)=architectureid

        addr4,r10,#HighPT-PTs;(r4)=ptrtohighpagetable

        cmpr5,#ARMv6;v6orlater?
        ;ARMV6_MMU
        orrger0,r10,#PTL2_KRW+PTL2_SMALL_PAGE+ARMV6_MMU_PTL2_SMALL_XN
        ;(r0)=PTEfor4K,kr/wu-/-page,uncachedunbuffered,nonexecutable
        ;PREARMV6_MMU
        orrltr0,r10,#PTL2_KRW+(PTL2_KRW<<2)+(PTL2_KRW<<4)+(PTL2_KRW<<6)
        ;NeedtoreplicateAPbitsintoall4fields
        orrltr0,r0,#PTL2_SMALL_PAGE+PREARMV6_MMU_PTL2_SMALL_XN
        ;(r0)=PTEfor4K,kr/wu-/-page,uncachedunbuffered,nonexecutable
        strr0,[r4,#0xD0*4];storetheentryinto4slotstomap16Kofprimarypagetable
        addr0,r0,#0x1000;steponthephysicaladdress
        strr0,[r4,#0xD1*4]
        addr0,r0,#0x1000;steponthephysicaladdress
        strr0,[r4,#0xD2*4]
        addr0,r0,#0x1000;steponthephysicaladdress
        strr0,[r4,#0xD3*4]

        addr8,r10,#ExceptionVectors-PTs;(r8)=ptrtovectorpage
        orrr0,r8,#PTL2_SMALL_PAGE;constructthePTE(C=B=0)

        ;;Theexceptionstacksandthevectorsaremappedasasinglekr/wpage.
        ;;Anyalternativewillusemorephysicalmemory.
        ;;Multiplemappingsdontprovideanyrealprotection:ifthevectorswereinar/opage,
        ;;theycouldstillbecorruptedviathekr/wsettingrequiredforthestacks.
        cmpr5,#ARMv6;v6orlater?
        ;ARMV6_MMU
        orrger0,r0,#PTL2_KRW
        ;PREARMV6_MMU
        orrltr0,r0,#PTL2_KRW+(PTL2_KRW<<2)+(PTL2_KRW<<4)+(PTL2_KRW<<6)
        ;NeedtoreplicateAPbitsintoall4fieldsforpre-V6MMU

        strr0,[r4,#0xF0*4];storeentryforexceptionstacksandvectors
        ;other3entriesnowunused

        addr9,r10,#KPage-PTs;(r9)=ptrtokdatapage
        orrr0,r9,#PTL2_SMALL_PAGE;(r0)=PTEfor4K(C=B=0)

        ;ARMV6_MMU(conditioncodesstillset)
        orrger0,r0,#PTL2_KRW_URO;Nosubpageaccesscontrol,sowemustsetthisalltokr/w+ur/o
        ;PREARMV6_MMU
        orrltr0,r0,#(PTL2_KRW<<0)+(PTL2_KRW<<2)+(PTL2_KRW_URO<<4)
        ;(r0)=setpermskr/wkr/wkr/w+ur/or/o
        strr0,[r4,#0xFC*4];storeentryforkerneldatapage
        orrr0,r4,#PTL1_2Y_TABLE;(r0)=1stlevelPTEforhighmemorysection
        addr1,r10,#0x4000
        strr0,[r1,#-4];storePTEinlastslotof1stleveltable

        ;Fillinfirstlevelpagetableentriestocreate"staticallymapped"regions
        ;fromthecontentsoftheOEMAddressTablearray.
        ;
        ;(r5)=architectureid
        ;(r9)=ptrtoKDatapage
        ;(r10)=ptrto1stlevelpagetable
        ;(r11)=ptrtoOEMAddressTablearray

        addr10,r10,#0x2000;(r10)=ptrto1stPTEfor"unmappedspace"

        movr0,#PTL1_SECTION
        orrr0,r0,#PTL1_KRW;(r0)=PTEfor0:1MB(C=B=0,kernelr/w)
        20movr1,r11;(r1)=ptrtoOEMAddressTablearray(physical)


        25ldrr2,[r1],#4;(r2)=virtualaddresstomapBankat
        ldrr3,[r1],#4;(r3)=physicaladdresstomapfrom
        ldrr4,[r1],#4;(r4)=numMBtomap

        cmpr4,#0;Endoftable?
        beq%F29

        ldrr12,=0x1FF00000
        andr2,r2,r12;VAneeds512MB,1MBaligned.

        ldrr12,=0xFFF00000
        andr3,r3,r12;PAneeds4GB,1MBaligned.

        addr2,r10,r2,LSR#18
        addr0,r0,r3;(r0)=PTEfornextphysicalpage

        28strr0,[r2],#4
        addr0,r0,#0x00100000;(r0)=PTEfornextphysicalpage

        subr4,r4,#1;DecrementnumberofMBleft
        cmpr4,#0
        bne%B28;MapnextMB

        bicr0,r0,#0xF0000000;ClearSectionBaseAddressField
        bicr0,r0,#0x0FF00000;ClearSectionBaseAddressField
        b%B25;Getnextelement


        29
        subr10,r10,#0x2000;(r10)=restoreaddressof1stlevelpagetable

        ;Theminimalpagemappingsaresetup.InitializetheMMUandturniton.

        ;therearesomeCPUswithpipelineissuesthatrequiresidentitymappingbeforeturningonMMU.
        ;WellcreateanidentitymappingfortheaddresswelljumptowhenturningonMMUonandremove
        ;themappingafterweturnonMMUandrunningonVirtualaddress.


        ldrr12,=0xFFF00000;(r12)=maskforsectionbits
        andr1,pc,r12;physicaladdressofwhereweare
        ;NOTE:weassumethattheKernelStartfunctionneverspamacross1Mboundary.
        orrr0,r1,#PTL1_SECTION
        orrr0,r0,#PTL1_KRW;(r0)=PTEfor1Mforcurrentphysicaladdress,C=B=0,kernelr/w
        addr7,r10,r1,LSR#18;(r7)=1stlevelPTentryfortheidentitymap
        ldrr8,[r7];(r8)=savedcontentofthe1st-levelPT
        strr0,[r7];createtheidentitymap

        movr1,#1
        mtc15r1,c3;Setupaccesstodomain0andclearother
        mtc15r10,c2;setuptranslationbase(physicalof1stlevelPT)

        movr0,#0
        mcrp15,0,r0,c8,c7,0;FlushtheI&DTLBs

        mfc15r1,c1
        orrr1,r1,#0x007F;changedtoread-mod-writeforARM920Enable:MMU,Align,DCache,WriteBuffer

        cmpr5,#ARMv6;r5stillset
        ;ARMV6_MMU
        orrger1,r1,#0x3000;vectoradjust,ICache
        orrger1,r1,#1<<23;V6-formatpagetables
        orrger1,r1,#ARMV6_U_BIT;V6-setUbit,letAbitcontrolunalignmentsupport
        ;PREARMV6_MMU
        orrltr1,r1,#0x3200;vectoradjust,ICache,ROMprotection

        ldrr0,VirtualStart
        cmpr0,#0;makesurenostallon"movpc,r0"below
        mtc15r1,c1;enabletheMMU&Caches
        movpc,r0;&jumptonewvirtualaddress
        nop

        ;MMU&cachesnowenabled.
        ;
        ;(r10)=physcialaddressof1stlevelpagetable
        ;(r7)=entryin1stlevelPTforidentitymap
        ;(r8)=saved1stlevelPTsaveat(r7)
        VStartldrr2,=FirstPT;(r2)=VAof1stlevelPT
        subr7,r7,r10;(r7)=offsetinto1st-levelPT
        strr8,[r2,r7];restorethetemporaryidentitymap
        mcrp15,0,r0,c8,c7,0;FlushtheI&DTLBs

        ;
        ;setupstackforeachmodes:currentmode=supervisormode
        ;
        ldrsp,=KStack
        addr4,sp,#KData-KStack;(r4)=ptrtoKDataStruct

        ;setupABORTstack
        movr1,#ABORT_MODE:OR:0xC0
        msrcpsr_c,r1;switchtoAbortModew/IRQsdisabled
        addsp,r4,#AbortStack-KData

        ;setupIRQstack
        movr2,#IRQ_MODE:OR:0xC0
        msrcpsr_c,r2;switchtoIRQModew/IRQsdisabled
        addsp,r4,#IntStack-KData

        ;setupFIQstack
        movr3,#FIQ_MODE:OR:0xC0
        msrcpsr_c,r3;switchtoFIQModew/IRQsdisabled
        addsp,r4,#FIQStack-KData

        ;setupUNDEFstack
        movr3,#UNDEF_MODE:OR:0xC0
        msrcpsr_c,r3;switchtoUndefinedModew/IRQsdisabled
        movsp,r4;(sp_undef)=&KData

        ;switchbacktoSupervisormode
        movr0,#SVC_MODE:OR:0xC0
        msrcpsr_c,r0;switchtoSupervisorModew/IRQsdisabled
        ldrsp,=KStack

        ;continueinitializationinC
        addr0,sp,#KData-KStack;(r0)=ptrtoKDataStruct
        strr6,[r0,#pAddrMap];storeVAofOEMAddressTableinKData
        blARMInit;callCfunctiontoperformtherestofinitializations
        ;uponreturn,(r0)=entrypointofkernel.dll

        movr12,r0
        ldrr0,=KData
        movpc,r12;jumptoentryofkernel.dll

        從上面的代碼可以看出,KernelStart()通過OEMAddressTable初始化了MMU,然后通過調(diào)用函數(shù)ARMInit()獲得kernel.dll的入口點,最后跳轉(zhuǎn)到kernel.dll的入口點處。

        為了找到Kernel.dll的入口點,用IDA反匯編kernel.dll文件,可以看到,Kernel.dll的入口點為NKStartup。

        NKStartup()的實現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELARM mdarm.c中,代碼如下:

        Code
        //
        //NKStartup-entrypointofkernel.dll.
        //
        //NKLoadersetuponlytheminimalmappings,whichincludesARMHigharea,andthecachedstaticmappingarea,
        //with*EVERYTHINGUNCACHED*.Interruptvectorsarenotsetupeither.So,theinitsequencereqiures:
        //(1)pickupdatapassedfromnkloader
        //(2)Findentrypointofoal,exchangeglobals,findoutthecachemode.
        //(3)fillintherestofstaticmappedarea(0xa0000000-0xbfffffff),PSLfaultingaddress,interruptvectors,
        //modstacks,etc.Then,changethecachedstaticmappingareatousecache,andflushI&DTLB.
        //(4)continuenormalloadingofkernel(findKITLdll,callOEMInitDebugSerial,etc.)
        //
        voidNKStartup(structKDataStruct*pKData)
        {
        PFN_OEMInitGlobalspfnInitGlob;
        PFN_DllMainpfnKitlEntry;
        DWORDdwCpuId=GetCpuId();

        //(1)pickupargumentsfromthenkloader
        g_pKData=pKData;
        pTOC=(constROMHDR*)pKData->dwTOCAddr;
        g_pOEMAddressTable=(PADDRMAP)pKData->pAddrMap;

        /*getarchitectureidandupdatepageprotectionattributes*/
        pKData->dwArchitectureId=(dwCpuId>>16)&0xf;
        if(pKData->dwArchitectureId>=ARMArchitectureV6){
        //v6orlater
        pKData->dwProtMask=PG_V6_PROTECTION;
        pKData->dwRead=PG_V6_PROT_READ;
        pKData->dwWrite=PG_V6_PROT_WRITE;
        pKData->dwKrwUro=PG_V6_PROT_URO_KRW;
        pKData->dwKrwUno=PG_V6_PROT_UNO_KRW;

        }else{
        //pre-v6
        pKData->dwProtMask=PG_V4_PROTECTION;
        pKData->dwRead=PG_V4_PROT_READ;
        pKData->dwWrite=PG_V4_PROT_WRITE;
        pKData->dwKrwUro=PG_V4_PROT_URO_KRW;
        pKData->dwKrwUno=PG_V4_PROT_UNO_KRW;
        }

        //initializenkglobals
        FirstROM.pTOC=(ROMHDR*)pTOC;
        FirstROM.pNext=0;
        ROMChain=&FirstROM;
        KInfoTable[KINX_PTOC]=(long)pTOC;
        KInfoTable[KINX_PAGESIZE]=VM_PAGE_SIZE;

        g_ppdirNK=(PPAGEDIRECTORY)&ArmHigh->firstPT[0];
        pKData->pNk=g_pNKGlobal;

        //(2)findentryofoal
        pfnInitGlob=(PFN_OEMInitGlobals)pKData->dwOEMInitGlobalsAddr;

        //nocheckinghere,ifOALentrypointdoesntexist,wecantcontinue
        g_pOemGlobal=pfnInitGlob(g_pNKGlobal);
        g_pOemGlobal->dwMainMemoryEndAddress=pTOC->ulRAMEnd;
        pKData->pOem=g_pOemGlobal;

        //setupglobals
        pVMProc=g_pprcNK;
        pActvProc=g_pprcNK;

        g_pNKGlobal->pfnWriteDebugString=g_pOemGlobal->pfnWriteDebugString;

        //(3)setupvectors,UCmappings,modestacks,etc.
        ARMSetup();

        //
        //cacheisenabledfromhereon
        //

        //(4)commonstartupcode.

        //trytoloadKITLifexist
        if((pfnKitlEntry=(PFN_DllMain)g_pOemGlobal->pfnKITLGlobalInit)||
        (pfnKitlEntry=(PFN_DllMain)FindROMDllEntry(pTOC,KITLDLL))){
        (*pfnKitlEntry)(NULL,DLL_PROCESS_ATTACH,(DWORD)NKKernelLibIoControl);
        }

        #ifdefDEBUG
        CurMSec=dwPrevReschedTime=(DWORD)-200000;//~3minutesbeforewrap
        #endif

        OEMInitDebugSerial();

        //debugchkonlyworksafterwehavesomethingtoprintto.
        DEBUGCHK(pKData==(structKDataStruct*)PUserKData);
        DEBUGCHK(pKData==&ArmHigh->kdata);

        OEMWriteDebugString((LPWSTR)NKSignon);

        /*Copyinterlockedapicodeintothekpage*/
        DEBUGCHK(sizeof(structKDataStruct)<=FIRST_INTERLOCK);
        DEBUGCHK((InterlockedEnd-InterlockedAPIs)+FIRST_INTERLOCK<=0x400);
        memcpy((char*)g_pKData+FIRST_INTERLOCK,InterlockedAPIs,InterlockedEnd-InterlockedAPIs);

        /*setupprocessorversioninformation*/
        CEProcessorType=(dwCpuId>>4)&0xFFF;
        CEProcessorLevel=4;
        CEProcessorRevision=(WORD)dwCpuId&0x0f;
        CEInstructionSet=PROCESSOR_ARM_V4I_INSTRUCTION;

        RETAILMSG(1,(L"ProcessorType=%4.4xRevision=%drn",CEProcessorType,CEProcessorRevision));
        RETAILMSG(1,(L"OEMAddressTable=%8.8lxrn",g_pOEMAddressTable));

        OEMInit();//initializefirmware

        //flushI&DTLB
        OEMCacheRangeFlush(NULL,0,CACHE_SYNC_FLUSH_TLB);

        KernelFindMemory();

        DEBUGMSG(1,(TEXT("NKStartupdone,startingupkernel.rn")));

        KernelStart();

        //neverreturned
        DEBUGCHK(0);
        }

        NKStartup()的代碼就不多解釋了,注釋已經(jīng)很詳細。該函數(shù)的最后又調(diào)用了KernelStart ()函數(shù)。注意這里的KernelStart()跟上面曾提到的KernelStart()是不一樣的。這里KernelStart()的實現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELARMarmtrap.s中,代碼和反匯編的對比如下圖所示。
        可以看到,這里調(diào)用了KernelInit()和FirstSchedule()這兩個函數(shù)。先說FirstSchedule(),它開始了WinCE6.0的第一個調(diào)度。它的實現(xiàn)跟KernelStart()在同一文件中,而實現(xiàn)代碼跟WinCE5.0中完全一樣。接下來,我們繼續(xù)跟蹤KernelInit()函數(shù),其實現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELnkinit.c中,代碼如下:

        Code
        //------------------------------------------------------------------------------
        //KernelInit-Kernelinitializationbeforeschedulingthe1stthread
        //------------------------------------------------------------------------------

        voidKernelInit(void)
        {
        #ifdefDEBUG
        g_pNKGlobal->pfnWriteDebugString(TEXT("WindowsCEKernelInitrn"));
        #endif
        APICallInit();//setupAPIset
        HeapInit();//setupkernelheap
        InitMemoryPool();//setupphysicalmemory
        PROCInit();//initializeprocess
        VMInit(g_pprcNK);//setupVMforkernel
        THRDInit();//initializethreads
        MapfileInit();

        #ifdefDEBUG
        g_pNKGlobal->pfnWriteDebugString(TEXT("Schedulingthefirstthread.rn"));
        #endif
        }

        這段代碼跟WinCE5.0中的結(jié)構(gòu)基本一致,但實際上有很大的不同。跟WinCE6.0啟動最緊密的函數(shù)是THRDInit (),這之前都是做相應(yīng)的初始化。THRDInit ()的實現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELthread.c中,代碼如下:

        Code
        //------------------------------------------------------------------------------
        //THRDInit-initializethreadhandling(calledatsystemstartup)
        //------------------------------------------------------------------------------
        voidTHRDInit(void)
        {
        LPBYTEpStack;

        DEBUGLOG(1,g_pprcNK);

        //dontallowthreadcreateonememorydropbelow1%available
        if(g_cMinPageThrdCreateg_cMinPageThrdCreate=PageFreeCount/100;
        }

        //mapW32threadpriorityifOEMchooseto
        if(g_pOemGlobal->pfnMapW32Priority){
        BYTEprioMap[MAX_WIN32_PRIORITY_LEVELS];
        inti;
        memcpy(prioMap,W32PrioMap,sizeof(prioMap));
        g_pOemGlobal->pfnMapW32Priority(MAX_WIN32_PRIORITY_LEVELS,prioMap);
        //validatethethepriorityismono-increase
        for(i=0;iif(prioMap[i]>=prioMap[i+1])
        break;
        }

        DEBUGMSG((MAX_WIN32_PRIORITY_LEVELS-1)!=i,(L"ProcInit:InvalidprioritymapprovidedbyOEM,Ignored!rn"));
        if((MAX_WIN32_PRIORITY_LEVELS-1)==i){
        memcpy(W32PrioMap,prioMap,sizeof(prioMap));
        }
        }

        //allocatememoryforthe1stthread
        pCurThread=AllocMem(HEAP_THREAD);
        DEBUGCHK(pCurThread);

        dwCurThId=(DWORD)HNDLCreateHandle(&cinfThread,pCurThread,g_pprcNK)&~1;
        DEBUGCHK(dwCurThId);

        InitThreadStruct(pCurThread,(HANDLE)dwCurThId,g_pprcNK,THREAD_RT_PRIORITY_ABOVE_NORMAL);

        if(g_pOemGlobal->cbCoProcRegSize){

        DEBUGCHK(g_pOemGlobal->pfnInitCoProcRegs);
        DEBUGCHK(g_pOemGlobal->pfnSaveCoProcRegs);
        DEBUGCHK(g_pOemGlobal->pfnRestoreCoProcRegs);

        //checkthedebugregisterrelatedvalues.
        if(g_pOemGlobal->cbCoProcRegSize>MAX_COPROCREGSIZE){
        g_pOemGlobal->cbCoProcRegSize=g_pOemGlobal->fSaveCoProcReg=0;
        }else{
        PNAMEpTmp=AllocName(g_pOemGlobal->cbCoProcRegSize);
        DEBUGCHK(pTmp);
        g_dwCoProcPool=pTmp->wPool;
        FreeName(pTmp);
        }
        }else{
        g_pOemGlobal->fSaveCoProcReg=FALSE;
        }
        DEBUGMSG(ZONE_SCHEDULE,(TEXT("cbCoProcRegSize=%drn"),g_pOemGlobal->cbCoProcRegSize));

        AddToDListHead(&g_pprcNK->thrdList,&pCurThread->thLink);
        g_pprcNK->wThrdCnt++;


        #ifdefSHx
        SetCPUGlobals();
        OEMCacheRangeFlush(0,0,CACHE_SYNC_ALL);
        #endif


        if(!OpenExecutable(NULL,TEXT("NK.EXE"),&g_pprcNK->oe,TOKEN_SYSTEM,NULL,0)){
        LoadE32(&g_pprcNK->oe,&g_pprcNK->e32,0,0,0);
        g_pprcNK->BasePtr=(LPVOID)g_pprcNK->e32.e32_vbase;
        UpdateKmodVSize(&g_pprcNK->oe,&g_pprcNK->e32);
        }

        //create/setupstack
        pStack=VMCreateStack(g_pprcNK,KRN_STACK_SIZE);
        pCurThread->dwOrigBase=(DWORD)pStack;
        pCurThread->dwOrigStkSize=KRN_STACK_SIZE;
        pCurThread->tlsSecure=pCurThread->tlsNonSecure=pCurThread->tlsPtr=TLSPTR(pStack,KRN_STACK_SIZE);
        pCurThread->hTok=TOKEN_SYSTEM;

        //Saveoffthethreadsprogramcounterforgettingitsnamelater.
        pCurThread->dwStartAddr=(DWORD)SystemStartupFunc;

        MDSetupThread(pCurThread,(LPVOID)SystemStartupFunc,0,TH_KMODE,0);

        CELOG_ThreadCreate(pCurThread,g_pprcNK,NULL);

        MakeRun(pCurThread);
        DEBUGMSG(ZONE_SCHEDULE,(TEXT("Scheduler:Createdmasterthread%8.8lxrn"),pCurThread));

        }

        可以看到,這里開始了一個線程,線程處理函數(shù)為SystemStartupFunc(),其實現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELschedule.c,實現(xiàn)代碼如下:

        Code
        //------------------------------------------------------------------------------
        void
        SystemStartupFunc(
        ulongparam
        )
        {
        HANDLEhTh;

        //recordPendEventaddressforSetInterruptEvent
        KInfoTable[KINX_PENDEVENTS]=(DWORD)&PendEvents1;

        KernelInit2();

        //adjustalarmresolutionifititsnotinbound
        if(g_pOemGlobal->dwAlarmResolutiong_pOemGlobal->dwAlarmResolution=MIN_NKALARMRESOLUTION_MSEC;
        elseif(g_pOemGlobal->dwAlarmResolution>MAX_NKALARMRESOLUTION_MSEC)
        g_pOemGlobal->dwAlarmResolution=MAX_NKALARMRESOLUTION_MSEC;

        VERIFY(LoaderInit());

        //initializethecompiler/GScookie-thismusthappenbeforeotherthreads
        //startrunning
        __security_init_cookie();

        PagePoolInit();

        //Thiscanonlybedoneaftertheloaderinitialization
        LoggerInit();//InitializationforCeLog,profiler,code-coverage,etc.
        SysDebugInit();//initializeSystemDebugger(HWDebugstub,Kerneldumpcapture,SWKernelDebugstub)

        //dothisnow,sothatwecontinuerunningafterwevecreatedthenewthread
        #ifdefSTART_KERNEL_MONITOR_THREAD
        hTh=CreateKernelThread(Monitor1,0,THREAD_RT_PRIORITY_ABOVE_NORMAL,0);
        HNDLCloseHandle(g_pprcNK,hTh);
        #endif

        pCleanupThread=pCurThread;
        hAlarmThreadWakeup=NKCreateEvent(0,0,0,0);
        DEBUGCHK(hAlarmThreadWakeup);
        InitializeCriticalSection(&rtccs);
        IntrEvents[SYSINTR_RTC_ALARM-SYSINTR_DEVICES]=LockIntrEvt(hAlarmThreadWakeup);
        DEBUGCHK(IntrEvents[SYSINTR_RTC_ALARM-SYSINTR_DEVICES]->phdIntr);

        //GivetheOEMafinalchancetodoamorefull-featuredinitbeforeany
        //appsarestarted
        KernelIoctl(IOCTL_HAL_POSTINIT,NULL,0,NULL,0,NULL);

        InitMsgQueue();
        InitWatchDog();

        //createthepowerhandlereventandguardthread
        hEvtPwrHndlr=NKCreateEvent(NULL,FALSE,FALSE,NULL);
        DEBUGCHK(hEvtPwrHndlr);
        hTh=CreateKernelThread(PowerHandlerGuardThrd,NULL,THREAD_PWR_GUARD_PRIORITY,0);
        HNDLCloseHandle(g_pprcNK,hTh);

        //dirtypageevent,initiallyset
        hEvtDirtyPage=NKCreateEvent(NULL,FALSE,TRUE,NULL);
        DEBUGCHK(hEvtDirtyPage);

        //wedontwanttowasteathreadhere(createaseparateforcleaningdirtypages).
        //Instead,RunAppsthreadwillbecome"CleanDirtyPage"threadoncefilesysstarted
        hTh=CreateKernelThread(RunApps,0,THREAD_RT_PRIORITY_NORMAL,0);
        HNDLCloseHandle(g_pprcNK,hTh);

        #defineONE_DAY86400000

        while(1){
        KCall((PKFN)SetThreadBasePrio,pCurThread,dwNKAlarmThrdPrio);
        NKWaitForSingleObject(hAlarmThreadWakeup,ONE_DAY);
        NKRefreshKernelAlarm();
        PageOutIfNeeded();
        }
        }

        這里創(chuàng)建了一個內(nèi)核線程,處理函數(shù)為RunApps,繼續(xù)跟蹤RunApps,其實現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELkmisc.c中,代碼如下:

        Code
        DWORDWINAPI
        RunApps(
        LPVOIDparam
        )
        {
        HMODULEhFilesys;
        DEBUGMSG(ZONE_ENTRY,(L"RunAppsstartedrn"));

        CELOG_LaunchingFilesys();

        hFilesys=(HMODULE)NKLoadLibraryEx(L"filesys.dll",MAKELONG(LOAD_LIBRARY_IN_KERNEL,LLIB_NO_PAGING),NULL);

        if(hFilesys){
        FARPROCpfnMain=GetProcAddressA(hFilesys,(LPCSTR)2);//WinMainoffilesys
        HANDLEhFSReady,hTh;

        DEBUGCHK(pfnMain);

        hFSReady=NKCreateEvent(NULL,TRUE,FALSE,TEXT("SYSTEM/FSReady"));
        hTh=CreateKernelThread((LPTHREAD_START_ROUTINE)pfnMain,hFilesys,THREAD_RT_PRIORITY_NORMAL,0);

        DEBUGCHK(hTh&&hFSReady);
        HNDLCloseHandle(g_pprcNK,hTh);

        //IfpSignalStartedisNULL,wedonthavefilesys(tinykern).Dontbotherwaitingforit.
        if(pSignalStarted){
        NKWaitForSingleObject(hFSReady,INFINITE);

        DEBUGCHK(SystemAPISets[SH_FILESYS_APIS]);

        //InitializeMUI-Resourceloader(requiresregistry)
        InitMUILanguages();

        //Readsystemsettingsfromregistry
        InitSystemSettings();

        //signalfilesysthatweredone
        (*pSignalStarted)(0);
        }
        HNDLCloseHandle(g_pprcNK,hFSReady);

        }else{
        RETAILMSG(1,(L"Filesysdoesntexist,noappstartedrn"));
        }

        //insteadofexiting,weremakethisthreadcleaningdirtypagesinthebackground.
        CleanPagesInTheBackground();

        //shouldveneverreturned
        DEBUGCHK(0);
        NKExitThread(0);

        return0;
        }
        終于啟動filesys.dll了。這個過程簡單說明一下,啟動filesys.dll后等待其執(zhí)行的情況,在完成了文件系統(tǒng)的相應(yīng)的初始化之后,這里繼續(xù)初始化MUI和系統(tǒng)設(shè)置,完成后再通知filesys這邊的工作已經(jīng)完成,filesys繼續(xù)啟動。這一部分的具體內(nèi)容請參考MSDN,F(xiàn)ile System Boot Process:http://msdn.microsoft.com/en-us/library/aa912276.aspx。總之,filesys會完成WinCE的最后啟動過程,包括gwes.dll和explorer.exe等。至此,WinCE6.0啟動完成,如果有LCD且驅(qū)動能正常工作,現(xiàn)在就應(yīng)該能看見可愛的WinCE6.0的界面了。

        呵,沒想到WinCE6.0的啟動過程竟然這么繁長。不過,弄清楚這個啟動流程對于移植BSP相當有好處。總結(jié)一下整個過程,如下圖所示。


        本文通過跟蹤代碼的方式,介紹了WinCE6.0的啟動流程。流于表面了一點,很多細節(jié)應(yīng)該進一步研究,以后再慢慢看吧。文中有不確切的地方,也請您不吝賜教.



        關(guān)鍵詞: S3C2410WinCE6.0啟動過

        評論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 新竹市| 同德县| 措勤县| 青岛市| 青铜峡市| 咸宁市| 乐昌市| 盘山县| 商南县| 霍山县| 哈尔滨市| 安宁市| 德钦县| 定日县| 久治县| 朝阳市| 麦盖提县| 桃园市| 册亨县| 镇康县| 乳源| 武穴市| 淮北市| 闸北区| 灵台县| 陆河县| 永年县| 盈江县| 嘉鱼县| 泽普县| 杭州市| 高陵县| 宜兴市| 卫辉市| 康乐县| 杭锦旗| 新密市| 年辖:市辖区| 汽车| 修水县| 崇阳县|