以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通过网络下载 NK.bin或者从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 根据stepldr.bib 二 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 1.startup.s 初始化一些硬件外设 --> KernelStart 2.KernelStart 在PRIVATE\WINCEOS\COREOS\NK\LDR\ARM\armstart.s中 根据OALAddress Table初始化页表 , 打开MMU和初始化Cache和中断向量 初始化stack 调用ArmInit mov r12, r0 ldr r0, =KData mov pc, r12 ; jump to entry of kernel.dll 3 ArmInit 在PRIVATE\WINCEOS\COREOS\NK\LDR\ARM\arminit.c中 LPVOID ARMInit (struct KDataStruct *pKData) { /* Initialize kernel globals */ KernelRelocate (pTOC); /* The only argument passed to the entry point of kernel.dll 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); } 主要是内核重定位 .返回kernel.dll的入口位置. 在上面的KernelStart函数中,mov pc, r12指令跳转到kernel.dll的入口位置. 4 FindKernelEntry找到NKStartup 在PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\mdarm.c中 调用 ARMSetup (PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\mdarm.c)to perform addition setup for CPU (vector table, 1st-level PT mappings, etc) 调用OEMInitDebugSerial 以及 OEMInit 5 OEMInit 在\PLATFORM\SMDK6410\SRC\OAL\OALLIB\init.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 interrupts\n")); } ....... 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)\WINCEOS\COREOS\NK\KERNEL\ARM\armtrap.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 KernelInit\r\n")); #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 thread.\r\n")); #endif } 8、FirstSchedule: FirstSchedule函数为Windows CE操作系统启动过程中最后无条件跳转的一个函数,windows CE进行第一个调度,实际为一个空闲线程,因为windows CE系统还没有完成启动,只有当windows CE完全启动并进入稳定状态,然后启动文件系统filesys.dll,设备管理device.dll,窗体图像子系统gews.dll和shell程序 explore.exe。 (2)系统的其它部分初始化 2.1 FirstSchedule --〉SystemStartupFunc 2.2 而在SystemStartupFunc中,会创立一个内核线程 CreateKernelThread (RunApps,0,THREAD_RT_PRIORITY_NORMAL,0) 这样就执行线程的函数RunApps 2.3 在RunApps中,NKLoadLibraryEx (L"filesys.dll", MAKELONG (LOAD_LIBRARY_IN_KERNEL, LLIB_NO_PAGING), NULL); 进行filesys.dll的加载, 2.4 然后启动一个线程,执行filesys.dll的 WinMain 2.5 等待filesys.dll 的event SYSTEM/FSReady 2.6 收到后: InitMUILanguages();// Initialize MUI-Resource loader (requires registry) InitSystemSettings (); // Read system settings from registry 我们再来看看 FILESYS.DLL 。它相当于Windows CE以前版本中的FILESYS.EXE,负责初始化文件系统、对象存储、注册表、CEDB数据库、设备通知以及其它一些工作。 1 Filesys.dll 检测是冷启动还是热启动 如果是冷启动,对象存储内存将被初始化并映射给Filesys.dll.对于热启动,不用初始化而直接映射给Filesys.dll 2 Filesys.dll 从ROM中加载 OEM的 Certification DLL . 3 对于热启动,如果系统必须冷启动, Filesys.dll调用OAL函数pNotifyForceCleanboot. 4 对于冷启动, Filesys.dll 初始化RTC,通过调用OEMIoControl函数,控制号为IOCTL_HAL_INIT_RTC I/O. 5 Filesys.dll 按照顺序初始化下列APIs: Database APIs File system APIs Point-to-point message queue APIs Event log APIs Registry APIs 对于冷启动, Filesys.dll初始化注册表数据.数据初始化过程取决于是hive注册表还是RAM注册表. 如果在注册表里指定了缺省的用户Profile, Filesys.dll加载缺省用户的profile并初始化 HKEY_CURRENT_USER下的数据. 6 如果Device.dll 没有启动并且HKEY_LOCAL_MACHINE\System\StorageManager 指向一个可以加载的DLL, Filesys.dll加载存储管理器. 如果存储管理器加载了, Filesys.dll创建一个线程来初始化它. 7 Filesys.dll 初始化NLS数据(national language support). 8 对于一个干净的启动,Filesys.dll查阅Initobj.dat文件,然后从ROM中拷贝这些文件到根文件系统. 比如Initobj.dat内容为: root:-Directory("Program Files") root:-Directory("My Documents") Directory("\Windows"):-Directory("Desktop") Directory("\Windows"):-Directory("Programs") Directory("\Windows"):-Directory("Recent") Directory("\Windows\Desktop"):-File("Media Player.lnk", "\Windows\ceplayer.lnk") Directory("\Windows\Programs"):-File("Media Player.lnk", "\Windows\ceplayer.lnk") Directory("\Windows\Desktop"):-File("Messenger.lnk", "\Windows\msmsgs.lnk") Directory("\Windows\Programs"):-File("Messenger.lnk", "\Windows\msmsgs.lnk") 它的意思是: 先用root命令在根目录\下面建立2个文件夹,分别叫Program Files和My Documents. 然后在\Windows下面建立3个文件夹Desktop,Program,Recent 最后把Media Player的链接ceplayer.lnk,msmsgs.lnk拷贝到\windows\Desktop,Programs目录下,命名为Media Player.lnk,Messenger.lnk. 9 如果需要的话,Filesys.dll初始化时区并设置夏令时 (daylight saving time ,DST). 10 对于冷启动, Filesys.dll为用数据库引擎设置区域,对于EDB数据库,通过调用CeChangeDatabaseLCID (EDB)而对于CEDB数据库调用CeChangeDatabaseLCID (CEDB). 此外,对于冷启动,Filesys.dll从Initdb.ini文件中加载数据来填充对象存储数据库. 11 Filesys.dll告诉kernel:Filesys.dll已经好了. Filesys.dll然后等待kernel通知去启动OS的其他部分. 12 Filesys.dll根据HKEY_LOCAL_MACHINE\System\Events注册表创建命名的事件. 这些事件被拥有他们的进程设置. 13 Filesys.dll 启动HKEY_LOCAL_MACHINE\Init所列的应用 如果Device.dll在HKEY_LOCAL_MACHINE\Init中,而它又已经被启动,Filesys.dll会去打开SYSTEM/BOOTPHASE2事件,并会向Device.dll发信号。 该动作使得Device.dll会去重读注册表,并完成最后阶段的驱动初始化。任何驱动都可以去等待该同样的事件,这样驱动就可以去再读一次注册表。 在正常的启动过程中,Filesys.dll建立了一些文件并把他们存储在user storage中. 这些文件将占用 1.8 MB的可用的user storage. 下列文件在启动过程中被创建: System.hv \Documents and Settings\system.hv 345 KB 系统注册表hive文件 User.hv \Documents and Settings\default\user.hv 345 KB 缺省用户的用户注册表hive文件 对于filesys.dll启动过程,参见 http://msdn.microsoft.com/en-us/library/aa912276.aspx 再来看Device.dll,它被加载后,将读取 HKLM\Drivers\BuildIn下面的信息,然后一个一个驱动被加载,加载后相应地在 HKLM\Drivers\Active下面创立相应的键. |
wince 6.0 启动过程
最新推荐文章于 2023-10-05 05:01:49 发布