新聞中心

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

S3C2410下WinCE6.0的啟動(dòng)過(guò)程詳解

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

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

本文引用地址:http://butianyuan.cn/article/201611/318750.htm

在移植WinCE到新的硬件平臺(tái)時(shí),創(chuàng)建OAL是最復(fù)雜的任務(wù)之一。一般來(lái)說(shuō),最簡(jiǎn)單的方法是拷貝一個(gè)跟新的硬件平臺(tái)類似的且成熟的OAL,然后根據(jù)硬件的不同進(jìn)行修改,使其滿足目標(biāo)硬件的特定要求。這里不展開(kāi)說(shuō)明,回頭再單獨(dú)整理。
從EBOOT到OAL.exe的跳轉(zhuǎn)是從OEMLaunch()開(kāi)始的,函數(shù)OEMLaunch()中調(diào)用Launch(dwPhysLaunchAddr),它的實(shí)現(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ù)為物理地址,因?yàn)樵谔D(zhuǎn)之前已將MMU關(guān)閉。該地址可通過(guò)VIEWBIN來(lái)查看,如下圖所示:


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



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

Code
LEAF_ENTRYStartUp

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

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

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

可以看出,OAL的啟動(dòng)代碼又調(diào)用了函數(shù)KernelStart(),而這個(gè)函數(shù)是在文件C:WINCE600PRIVATEWINCEOSCOREOSNKLDRARMarmstart.s中實(shí)現(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()通過(guò)OEMAddressTable初始化了MMU,然后通過(guò)調(diào)用函數(shù)ARMInit()獲得kernel.dll的入口點(diǎn),最后跳轉(zhuǎn)到kernel.dll的入口點(diǎn)處。

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

NKStartup()的實(shí)現(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)很詳細(xì)。該函數(shù)的最后又調(diào)用了KernelStart ()函數(shù)。注意這里的KernelStart()跟上面曾提到的KernelStart()是不一樣的。這里KernelStart()的實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELARMarmtrap.s中,代碼和反匯編的對(duì)比如下圖所示。
可以看到,這里調(diào)用了KernelInit()和FirstSchedule()這兩個(gè)函數(shù)。先說(shuō)FirstSchedule(),它開(kāi)始了WinCE6.0的第一個(gè)調(diào)度。它的實(shí)現(xiàn)跟KernelStart()在同一文件中,而實(shí)現(xiàn)代碼跟WinCE5.0中完全一樣。接下來(lái),我們繼續(xù)跟蹤KernelInit()函數(shù),其實(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)基本一致,但實(shí)際上有很大的不同。跟WinCE6.0啟動(dòng)最緊密的函數(shù)是THRDInit (),這之前都是做相應(yīng)的初始化。THRDInit ()的實(shí)現(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));

}

可以看到,這里開(kāi)始了一個(gè)線程,線程處理函數(shù)為SystemStartupFunc(),其實(shí)現(xiàn)在文件C:WINCE600PRIVATEWINCEOSCOREOSNKKERNELschedule.c,實(shí)現(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)建了一個(gè)內(nèi)核線程,處理函數(shù)為RunApps,繼續(xù)跟蹤RunApps,其實(shí)現(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;
}
終于啟動(dòng)filesys.dll了。這個(gè)過(guò)程簡(jiǎn)單說(shuō)明一下,啟動(dòng)filesys.dll后等待其執(zhí)行的情況,在完成了文件系統(tǒng)的相應(yīng)的初始化之后,這里繼續(xù)初始化MUI和系統(tǒng)設(shè)置,完成后再通知filesys這邊的工作已經(jīng)完成,filesys繼續(xù)啟動(dòng)。這一部分的具體內(nèi)容請(qǐng)參考MSDN,F(xiàn)ile System Boot Process:http://msdn.microsoft.com/en-us/library/aa912276.aspx。總之,filesys會(huì)完成WinCE的最后啟動(dòng)過(guò)程,包括gwes.dll和explorer.exe等。至此,WinCE6.0啟動(dòng)完成,如果有LCD且驅(qū)動(dòng)能正常工作,現(xiàn)在就應(yīng)該能看見(jiàn)可愛(ài)的WinCE6.0的界面了。

呵,沒(méi)想到WinCE6.0的啟動(dòng)過(guò)程竟然這么繁長(zhǎng)。不過(guò),弄清楚這個(gè)啟動(dòng)流程對(duì)于移植BSP相當(dāng)有好處??偨Y(jié)一下整個(gè)過(guò)程,如下圖所示。


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



評(píng)論


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

關(guān)閉