2023年12月17日发(作者:)

以S3C6410为例子,S3C6410的内部SRAM地址为0x0C00 0000 ~ 0x0C00 1FFF,DRAM的Base地址为0x50000000 ,S3C6410支持NAND,SD启动,S3C6410里面有固化的ROM,

当系统上电的时候,将执行固化ROM中的代码,然后检查硬件的GPIO配置,如果配置成NAND 启动,则把NAND的前8K读入内部的SRAM(stepping Stone)中,然后跳转到

Stepping Stone的开头,执行Bootloader1 (也就是下文的stepldr), stepldr负责把eboot从NAND中搬到DRAM中,然后执行eboot( boot loader 2),eboot通过网络下载

或者从NAND中把内核搬到DRAM中,然后执行WINCE内核.所以整个启动过程分为三阶段,stepldr -->eboot --> wince kernel .

下面详细地分析各个阶段.

一 bootloader 1 stepldr

从stepldr的startup.s开始.startup.s主要是初始化硬件,中断,配置好C运行的环境,然后跳转到main函数中,执行C代码.

startuo.s 的流程是 :

startup --> Enable I cache -->关闭watchdog ,Interrupt dosable -> 时钟初始化 --> 初始化DRAM控制器 --> 初始化IRQ,SVC stack -->

判断是否睡眠 ---N--> Clear DRAM -->main

--Y-> 跳到NK的开头 (也就是DRAM + 0x100000的地方)

main.c :

UART初始化 --> nand 初始化 -> 从NAND中把eboot搬到DRAM中 -->跳转到 eboot的开头

我们看代码有2个全局变量。

ROMHDR * volatile const pTOC = (ROMHDR *)-1; 这个在ROMImage里面会赋值。

static BOOL g_bLargeBlock = FALSE; // For Large Block Check

这两个全局变量的位置为:500F0000 根据

二 bootloader 2 eboot

startup.s

startup --> Enable I cache -->关闭watchdog ,Interrupt dosable -> 时钟初始化 --> Disable

VIC --> enable 中断 -->CLEAR DRAM(从1M到128M地址的DRAM,因为低1M地址

空间目前放的是eboot ) --> 初始化MMU Table (根据g_oalAddressTable,把DRAM的Base地址0x50000000映射到0x80000000,此后地址都用虚拟地址) --> 初始化IRQ,SVC stack

-->

-->main

main.c

main --> BootloaderMain

BootloaderMain的流程:

KernelRelocate -->OEMDebugInit(初始化串口,这样就可以打印信息了) -->OEMPlatformInit

-->OEMPreDownload -->DownloadImage-->OEMLaunch (切换到ce内核了)

OEMPlatformInit :

InitializeDisplay --> 初始化中断 -->NAND Flash驱动 初始化 --> MainMenu (一些选项,比如设置IP) -->ethernet 驱动初始化

OEMPreDownload : get IP , initialize TFTP

DownloadImage :

先用OEMReadData读7位头,然后根据这7位判断是bin 还是 nb0 等

假如是bin , 调用 DownloadBin

三 wince OS

wince os 的启动我们也可以换分为2个阶段,第一个阶段,初始化OAL,一直到FirstSchedule开始调度,第二阶段,开始对文件系统,注册表,driver的

初始化和加载。

(1)初始化 OAL

p.s

初始化一些硬件外设 --> KernelStart

Start

在PRIVATEWINCEOSCOREOSNKLDRARMarmstart.s中

根据OALAddress Table初始化页表 , 打开MMU和初始化Cache和中断向量

初始化stack

调用ArmInit

mov r12, r0

ldr r0, =KData

mov pc, r12 ; jump to entry of

3 ArmInit

在PRIVATEWINCEOSCOREOSNKLDRARMarminit.c中

LPVOID ARMInit (struct KDataStruct *pKData)

{

/* Initialize kernel globals */

KernelRelocate (pTOC);

/* The only argument passed to the entry point of is the address */

/* of KData, we need to put everything we need to pass to in in KData. */

pKData->dwTOCAddr = (DWORD) pTOC;

pKData->dwOEMInitGlobalsAddr = (DWORD) OEMInitGlobals;

SetOsAxsDataBlockPointer(pKData);

return FindKernelEntry (pTOC);

}

主要是内核重定位 .返回的入口位置.

在上面的KernelStart函数中,mov pc, r12指令跳转到的入口位置.

4 FindKernelEntry找到NKStartup

在PRIVATEWINCEOSCOREOSNKKERNELARMmdarm.c中

调用 ARMSetup (PRIVATEWINCEOSCOREOSNKKERNELARMmdarm.c)to perform

addition setup for CPU (vector table, 1st-level PT mappings, etc)

调用OEMInitDebugSerial 以及 OEMInit

5 OEMInit

在PLATFORMSMDK6410SRCOALOALLIBinit.c中

OALCacheGlobalsInit();

.....

OALArgsInit((BSP_ARGS *)IMAGE_SHARE_ARGS_UA_START);// Check and Initialize

the BSP Args area

.....

if (!OALIntrInit())// Initialize Interrupts

{

OALMSG(OAL_ERROR, (L"[OAL:ERR] OEMInit() : failed to initialize interruptsn"));

}

.......

OALTimerInit(RESCHED_PERIOD, (OEM_COUNT_1MS ), 0);// Initialize System Clock

.......

KITLIoctl(IOCTL_KITL_STARTUP, NULL, 0, NULL, 0, NULL); // Initialize the KITL

connection if required

6、KernelSstart函数:

这里的KernelStart函数与前面的KernelStart函数的属于两个完全不同的函数,NKStartup函数中调用的KernelStart 函数为

$(_PRIVATEROOT)WINCEOSCOREOSNKKERNELARMarmtrap.s文件中的KernelStart 函数,

主要完成调用内核初始化函数KernelInit,并跳转到操作系统的第一个启动的任务。

LEAF_ENTRY KernelStart

ldr r4, =KData ; (r4) = ptr to KDataStruct

ldr r0, =APIRet

str r0, [r4, #pAPIReturn] ; set API return address

mov r1, #SVC_MODE

msr cpsr_c, r1 ; switch to Supervisor Mode w/IRQs enabled

CALL KernelInit ; initialize scheduler, etc.

mov r0, #0 ; no current thread

mov r1, #ID_RESCHEDULE

b FirstSchedule

ENTRY_END

7、KernelInit函数:

Windows CE 6.0的内核初始化函数同其他版本的内核初始化函数基本相近,主要完成在启动第一个线程前对内核进行初始化,主要包括API函数集初始化、堆的初始化、初始化内存池、进程初始化、线程初始化和文件映射初始化等操作。

void KernelInit (void)

{

#ifdef DEBUG

g_pNKGlobal->pfnWriteDebugString (TEXT("Windows CE KernelInitrn"));

#endif

APICallInit ();// setup API set

HeapInit ();// setup kernel heap

InitMemoryPool ();// setup physical memory

PROCInit ();// initialize process

VMInit (g_pprcNK);// setup VM for kernel

THRDInit ();// initialize threadsv

MapfileInit ();

#ifdef DEBUG

g_pNKGlobal->pfnWriteDebugString (TEXT("Scheduling the first "));

#endif

}

8、FirstSchedule:

FirstSchedule函数为Windows CE操作系统启动过程中最后无条件跳转的一个函数,windows CE进行第一个调度,实际为一个空闲线程,因为windows CE系统还没有完成启动,只有当windows CE完全启动并进入稳定状态,然后启动文件系统,设备管理,窗体图像子系统和shell程序 。

(2)系统的其它部分初始化

2.1 FirstSchedule --〉SystemStartupFunc

2.2 而在SystemStartupFunc中,会创立一个内核线程

CreateKernelThread (RunApps,0,THREAD_RT_PRIORITY_NORMAL,0)

这样就执行线程的函数RunApps

2.3 在RunApps中,NKLoadLibraryEx (L"", MAKELONG

(LOAD_LIBRARY_IN_KERNEL, LLIB_NO_PAGING), NULL);

进行的加载,

2.4 然后启动一个线程,执行的 WinMain

2.5 等待 的event SYSTEM/FSReady

2.6 收到后:

InitMUILanguages();// Initialize MUI-Resource loader (requires registry)

InitSystemSettings (); // Read system settings from registry

我们再来看看 。它相当于Windows CE以前版本中的,负责初始化文件系统、对象存储、注册表、CEDB数据库、设备通知以及其它一些工作。

1 检测是冷启动还是热启动

如果是冷启动,对象存储内存将被初始化并映射给.对于热启动,不用初始化而直接映射给

2 从ROM中加载 OEM的 Certification DLL .

3 对于热启动,如果系统必须冷启动, 调用OAL函数pNotifyForceCleanboot.

4 对于冷启动, 初始化RTC,通过调用OEMIoControl函数,控制号为

IOCTL_HAL_INIT_RTC I/O.

5 按照顺序初始化下列APIs:

Database APIs

File system APIs

Point-to-point message queue APIs

Event log APIs

Registry APIs

对于冷启动, 初始化注册表数据.数据初始化过程取决于是hive注册表还是RAM注册表.

如果在注册表里指定了缺省的用户Profile, 加载缺省用户的profile并初始化

HKEY_CURRENT_USER下的数据.

6 如果 没有启动并且HKEY_LOCAL_MACHINESystemStorageManager 指向一个可以加载的DLL, 加载存储管理器.

如果存储管理器加载了, 创建一个线程来初始化它.

7 初始化NLS数据(national language support).

8 对于一个干净的启动,查阅文件,然后从ROM中拷贝这些文件到根文件系统.

比如内容为:

root:-Directory("Program Files")

root:-Directory("My Documents")

Directory("Windows"):-Directory("Desktop")

Directory("Windows"):-Directory("Programs")

Directory("Windows"):-Directory("Recent")

Directory("WindowsDesktop"):-File("Media ", "")

Directory("WindowsPrograms"):-File("Media ", "")

Directory("WindowsDesktop"):-File("", "")

Directory("WindowsPrograms"):-File("", "")

它的意思是:

先用root命令在根目录下面建立2个文件夹,分别叫Program Files和My Documents.

然后在Windows下面建立3个文件夹Desktop,Program,Recent

最后把Media Player的链接,拷贝到windowsDesktop,Programs目录下,命名为Media ,.

9 如果需要的话,初始化时区并设置夏令时 (daylight saving time ,DST).

10 对于冷启动, 为用数据库引擎设置区域,对于EDB数据库,通过调用CeChangeDatabaseLCID (EDB)而对于CEDB数据库调用CeChangeDatabaseLCID (CEDB).

此外,对于冷启动,从文件中加载数据来填充对象存储数据库.

11 告诉kernel:已经好了. 然后等待kernel通知去启动OS的其他部分.

12 根据HKEY_LOCAL_MACHINESystemEvents注册表创建命名的事件. 这些事件被拥有他们的进程设置.

13 启动HKEY_LOCAL_MACHINEInit所列的应用

如果在HKEY_LOCAL_MACHINEInit中,而它又已经被启动,会去打开SYSTEM/BOOTPHASE2事件,并会向发信号。

该动作使得会去重读注册表,并完成最后阶段的驱动初始化。任何驱动都可以去等待该同样的事件,这样驱动就可以去再读一次注册表。

在正常的启动过程中,建立了一些文件并把他们存储在user storage中. 这些文件将占用 1.8 MB的可用的user storage.

下列文件在启动过程中被创建:

Documents and 345 KB 系统注册表hive文件

Documents and 345 KB 缺省用户的用户注册表hive文件

对于启动过程,参见 /en-us/library/

再来看,它被加载后,将读取 HKLMDriversBuildIn下面的信息,然后一个一个驱动被加载,加载后相应地在 HKLMDriversActive下面创立相应的键.