分析WinCE5.0的启动过程对了解和掌握Windows CE操作系统比较重要,下面主要分析Win CE5.0的启动过程,在后续的文章中将分析WinCE6.0的启动过程。
1、CPU加电,跳转到复位向量;
2、执行引导程序Startup();OAL中的Startup();
• 完成最小的CPU和硬件初始化;
• 关闭中断、缓存(Cache)和内存管理单元(MMU);
• 调用内核启动函数KernelStart
3、执行KernelStart();
• 初始化OEMAddressTable内容中第一级存储器页表;
• 打开MMU和Cache;
• 为每一种操作模式初始化堆栈;
• 依次调用ARMInit、KernelInit、FirstSchedule
4、ARMInit()内核主要初始化函数,负责调用OEM提供的初始化函数
• 调用OEMDebugInit初始化调试串口;
§ InitDebugSerial()
§ OEMWriteDebugByte()
§ OEMReadDebugByte()
§ OEMWriteDebugString()
• 调试串口显示WinCE消息;
• 调用OEMInit初始化目标硬件平台;
§ 中断初始化-OALIntrInit();
§ 系统计时器初始化-OALTimerInit();
§ KITL接口初始化-OALKitlStart()
5、KernelInit() 封装了所有的内核初始化,是内核初始化的入口,通过调用不同的内核初始化函数初始化内核组件;
• 堆栈初始化-HeapInit();
• 内存池初始化-InitMemoryPool();
• 内核进程初始化-ProcInit();
• 初始化内核调度器-SchedInit();并创建SystemStartupFunc线程;
6、FirstSchedule函数启动调度器
• SystemStartupFunc函数通过执行IOCTL_HAL_POSTINIT给OEM最后一个完成其他内核初始化;
• IOCTL_HAL_POSTINIT由OEMIOControl调用
7、内核将查找并运行第一个进程-FileSys.exe
• FileSys.exe是管理文件系统、数据库和注册表的进程。当加载了FileSys.exe后,它将查看RAM中是否存在已初始化的文件系统。
• 如果发现这样的文件系统,FileSys.exe将使用已初始化的文件系统,这将允许CE设备在结束系统的重新启动后能在文件系统中保留数据。
• 如果FileSys.exe没有找到文件系统,它将创建一个文件系统
• FileSys还创建默认的数据库映像和默认的注册表
• 查找在注册表的HKEY_LOCAL_MACHINE/Init键下的值。这个键中值提供了应该作为启动过程的一部分而加载的一组进程的名称、次序及相关性;
• 将要运行的进程由名为“Launch xx”的值指定,这里xx是定义运行次序的数字。一个可选值“Depend xx”可以用来使进程的运行依赖于另一个在这个次序的前面指定的进程。
8、运行设备管理器进程-Device.exe:
• 该模块的作用是加载和管理系统中的可安装设备驱动程序。
• Device.exe加载后,它将观察注册表中HKEY_LOCAL_MACHINE/BuiltIn以查找驱动程序列表,这些驱动程序必须在初始化时加载。
9、运行图像子系统进程-GWES.exe;
• GWES.exe包括了GWES子系统,图形窗口和事件管理器。
• GWES.exe加载三个预定义的驱动程序:键盘驱动、触摸屏驱动、显示驱动。
10、启动并运行定制的Shell应用程序
• explorer.exe:在Explorer.exe初始化了桌面和任务栏窗口后,它将观察 /windows/startup目录,并运行任何包含在这个目录下的可执行文件或快捷方式。
• 没有Explorer嵌入式系统,执行自定义的Shell应用程序
注:几个内核函数的调用位置:
KernelStart-$(_PRIVATEROOT)/WINCEOS/COREOS/NK/KERNEL/ARM/armtrap.s(402)
ARMInit()-$(_PRIVATEROOT)/WINCEOS/COREOS/NK/KERNEL/ARM/mdarm.c(467)
KernelInit() -$(_PRIVATEROOT)/WINCEOS/COREOS/NK/KERNEL/kwin32.c(1125)
bbfar(笔笔发)原创,转载请务必注明出处!
一、stepldr
stepldr流程分为以下几步。
①SetupCopySection(pTOC)
②MMU_EnableICache()——使能ICache
③Port_Init()——GPIO端口初始化
④Uart_Init()——初始化UART(调试端口)
⑤NF_Init()——初始化nand flash接口
⑥将Image从flash拷贝到RAM
⑦((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))()——跳转
二、EBOOT
Main()
调用
BootloaderMain()
调用
KernelRelocate()
将全局变量定位到RAM
OEMPlatformInit()
平台初始化(时钟,驱动等)
OEMDebugInit()
初始化调试端口(串口)
OEMPreDownload()
初始化以太网,判断是否要下载
OEMLaunch()
启动操作系统
DownloadImage()
下载文件
要下载
1 eboot的工作流程从eboot目录中的startup.s中的starup函数开始。
Startup函数需要完成的工作:
①把CPU设置为合适的运行状态作(特权态,Supervisor Mode),这一状态下可以没有限制的访问内存和硬件。
②在CPU级别关闭所有中断。
③确保MMU和TLB都已经关闭。
④使Cache和Write Buffer失效。
⑤初始化内存控制器。
⑥初始化其它的片上设备,例如时钟。只需要做最基本的初始化。
⑦设置栈指针,后面C语言执行环境需要用到。
⑧设置并打开MMU进行物理和逻辑地址映射,并打开Cache。
⑨把EBoot的代码复制到RAM中,然后跳转到RAM中的EBoot代码。
⑩跳转到C语言的main函数。
2 跳转到C语言的main函数后,有八个函数需要执行。
main.c(/Src/Bootloader/Eboot/)中的五个函数:Main 函数,OEMDebugInit 函数,OEMPlatformInit 函数,OEMPreDownload 函数,OEMLaunch 函数和blcommon.C(/PUBLIC/COMMON/OAK/DRIVERS/ETHDBG/BLCOMMON/)中的三个函数:BootloaderMain 函数,KernelRelocate 函数, DownloadImage 函数
其中:
KernelRelocate():把Boot Loader中的全局变量重定位到RAM中。由描述了整个ROM的几乎所有信息的结构体的指针pTOC决定如何移动数据、移动多少数据。
OEMDebugInit():初始化调试输出用的硬件端口,Eboot后面的代码中就可以用OEMWriteDebugString()等函数输出调试信息。
OEMPlatformInit():初始化目标板上的设备,主要有以下作用.
①InitDisplay()——LCD初始化并显示一张图片
②InitUSB()——USB初始化
③Isr_Init()——USB和DMA ISR初始化,使能DMA中断
④BP_Init——初始化boot partition(flash)
⑤TOC_Read、TOC_Init——确认pTOC信息有效
⑥在规定时间内等待按键(空格或者回车)
⑦MainMenu——根据按键情况,决定是否打印选择菜单,并等待选择
⑧InitEthDevice——根据情况初始化以太网控制器
OEMPreDownload():完成以太网下载之前的一些准备工作,包括通过DHCP获得IP地址、初始化TFTP服务等
①OALKitlCreateName——为设备创建名字
②根据需要获取IP地址和初始化TFTP
DownloadImage():用来从远程开发机上下载操作系统映像。
OEMLaunch():跳转到操作系统映像。
①首先,EBoot会在这一步试图把下载的映像写入NAND Flash中。写Flash功能是调用FMD驱动程序实现的。
②接下来OEMLaunch()调用了EBoot库中的EbootWaitForHostConnect()函数来获得Platform Builder的一些用户配置信息,主要获得了KITL的启动方式(主动还是被动),并把它们记录下来。
③最后,把启动配置信息写入Flash之后,OEMLaunch()会调用Launch()函数进行实际的跳转。
三、NK
1 startup.s(Src/kernel/oal/)中的SartUp函数
先对硬件进行基本的初始化,,然后跳转到OAL的主控函数KernelStart()开始执行。
2 armtrap.s(WINCE500/PRIVATE/WINCEOS/COREOS/NK/KERNEL/ARM/)中的KrnelStart函数
① 初始化虚拟地址和物理地址的映射表,打开MMU和Cache。
② 设置异常向量跳转表。
3 mdarm.c(WINCE500/PRIVATE/WINCEOS/COREOS/NK/KERNEL/ARM/)中的ARMInit函数
①KernelRelocate(pTOC)——将全局变量定位到RAM
②OEMInitDebugSerial()——初始化调试端口(串口)
③OEMInit()——初始化硬件
⑴设置DrWatson的内存大小
⑵OALCacheGlobalsInit()——设置全局cache
⑶OALIntrInit()——中断初始化
a.OALIntrMapInit()——IRQ和SYSINTR映射初始化
b.屏蔽所有中断,清除中断标志,使能系统时钟中断(TIMER4)
⑷OALTimerInit——初始化系统时钟
⑸ConfigureGPIO()——配置GPIO
⑹InitDisplay()——LCD初始化并显示一张图片
⑺OALKitlStart()——初始化KITL连接
④KernelFindMemory()——将Ram分成对象存储和用户RAM
4 Kwin32.c(WINCE500/PRIVATE/WINCEOS/COREOS/NK/KERNEL/)中的KernelInit函数
KernelInit函数用来初始化操作系统。先初始化系统API函数调用表,然后KernelInit()会依次调用HeapInit()、InitMemoryPool()、ProcInit()和SchedInit()来初始化系统堆、内存池、第一个进程和线程。
5 mdarm.c中的HandleException函数
HandleException函数由FirstSchedule()调用,作用是让操作系统进行重新调度,这样就可以选择第一个在就绪态的线程上台执行。然后系统会依次加载FileSys.exe、Device.exe等等系统进程,然后是应用程序。