您的位置:首页 > 移动开发 > Objective-C

基于ARM的Windows CE内核启动分析

2009-12-09 16:44 405 查看
基于ARM的Windows CE内核启动分析    
 

基于ARM的Windows CE内核启动分析

移植或者创建一个BSP,也许需要先熟悉Windows CE的内核启动过程.
 

 

目录
基于ARM的Windows CE内核启动分析................................................................................. 1

1.startup.s....................................................................................................................... 2

2.KernelStart................................................................................................................... 2

2.1 ARMInit()............................................................................................................ 3

2.1.1 OALIntrInit............................................................................................. 3

2.1.2 OALTimerInit........................................................................................... 4

2.1.2.1 Variable Tick Scheduler................................................................. 4

2.2 KernelInit()...................................................................................................... 4

2.3 FirstSchedule.................................................................................................... 5

 

 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

1.startup.s 

内核入口点startup.S,内核从这里启动.因为内核经过bootloader加载,内核运行时候,已经由bootloader完成了硬件的基本初始化(关闭watchdog, pll设置等等)所以,startup.S的任务比较简单,只是将oemaddrtab_cfg.inc里面的g_oalAddressTable数组地址作为参数,传递给KernelStart,这个数组用来描述和实现物理地址到虚拟地址的映射.

 

        add     r0, pc, #g_oalAddressTable - (. + 8)

        bl      KernelStart

 
 
 

 

 

(. + 8)是流水线处理.KernelStart()位于

PRIVATE/WINCEOS/COREOS/NK/KERNEL/ARM/armtrap.s

 

 

 

 

2.KernelStart

初始化页表,打开mmu,cache
初始化中断向量表,
初始化各个模式的堆栈
CALL ARMInit
CALL KernelInit
    B FirstSchedule

 
 

                                           
 
 
 
 
 
 
ARMInit()位于本目录的mdram.c文件.
KernelInit()位于PRIVATE/WINCEOS/COREOS/NK/KERNEL/kwin32.c中.
FirstSchedule()位于armtrap.s的一个label.
主要关注ARMInit()和KernelInit(),前一个进行目标板的初始化,后一个负责内核的初始化.FirstSchdule()开始调度第一个程序.
 
 
 
 

2.1 ARMInit()

先看看ARMInit()它的几个关键性动作如下:
 

KernelRelocate(pTOC);
OEMInitDebugSerial();
OEMInit();
KernelFindMemory();
 

 
 
 
 
 
 
 

KernelRelocate()是进行重定位.KernelFindMemory()是查找系统可用内存,并分成应用内存和object store两部分.这2个函数都已由MS自己实现.我们需要添加的函数是名字以OEM开头的函数.
OEMInitDebugSerial()初始化一个调试口,我们一般使用一个串口来作为调试口,这个函数需要自己实现,在 PLATFORM/SMDK2440A/Src/Kernel/Oal/debug.c中定义这个函数.比如可以将串口0设置为调试口,在这个函数中对串口0进行初始化.
 
OEMInit()是一个比较重要的函数,

OALCacheGlobalsInit();
OALIntrInit();
OALTimerInit(1, 17, 0);
    ConfigureGPIO();
    InitDisplay();
    OALKitlStart();

 
 
 
 
 
 
 
 
 

OALCacheGlobalsInit()在PLATFORM/COMMON/SRC/ARM/COMMON/CACHE/init.s中实现,这部分代码以PQOAL的形式提供.
OALIntrInit()初始化中断.
OALTimerInit()初始化定时器TIMER4,作为系统时钟(tick),
configGPIO()初始化gpio口,设置相关寄存器.
InitDisplay()初始化LCD.有时候,我们希望在oal启动和内核加载期间显示一副等待图片或者显示LOGO,为达到这个目的,需要先初始化LCD.
OALKitlStart()准备启动KITL.
此外,在ARMInit还会通过调试口打印一些基本信息,开始时候打印”Windows CE Kernel for ARM….”字样, 中间打印处理器类型等等信息.结束时候打印” ARMInit done.”
 

2.1.1 OALIntrInit

调用OALIntrMapInit()初始化2个数组g_oalSysIntr2Irq,g_oalIrq2SysIntr,这2个数组表征irq和逻辑中断SysIntr的映射关系.
然后初始化中断寄存器,
最后,留一个接口给oem: BSPIntrInit(),如果oem需要在这个阶段初始化一些中断,可以定义这个函数并实现.
 
 
 
 

2.1.2 OALTimerInit

这个函数比较重要. 都知道所有WinCE系统都需要一个定时器来提供一个heartbeat,
 

初始化OAL层变量g_oalTimer,
初始化内核变量curridlehigh, curridlelow, idleconv,
初始化内核函数指针,
初始化硬件时钟定时器。
 

 
 
 
 
 
 
 

g_oalTimer包含各种系统时钟相关的变量.
 
curridlehigh, curridlelow,这2个32位的DWORD变量合起来实现一个64位的计数器,反映了系统处于空闲模式(Idle mode)的时间。一般在OEMIdle()函数内更新。用户程序通过调用GetIdleTime()函数可以得到这个值。
 
初始化内核函数指针:pQueryPerformanceFrequency, pQueryPerformanceCounter.通过这两个函数实现高精度的计时器. 这两个函数的原型也已经由PQOAL实现.
 
初始化TIMER4作为系统时钟.TIMER4是一个16bit的定时器.此函数将TIMER4设置成为自动转载模式.
 

2.1.2.1 Variable Tick Scheduler

 

可变的系统时钟节拍,这个是WinCE5.0中增加的新的性能.
每一次定时器中断时候,内核分析所有线程后决定切换到哪个线程运行.假如所有线程都在等待状态,系统将进入idle状态.在这个状态的时候,任何中断都会唤醒系统重新开始调度.一般系统大部分时间是处于idle状态的,内核会调用OEMIdle()进入idle状态,我们已经知道这个状态会被任何中断唤醒. 在以前的版本中,系统中断(即上面的TIMER4中断)每毫秒产生一次,查看系统是否需要重新调度. 为了节电,不希望中断那么频繁.于是WinCE5.0中,在调用OEMIdle()之前会先调用pOEMUpdateRescheduleTime().通过这个函数重新设置侠义次系统时钟中断的时间.

2.2 KernelInit()

再看看KernelInit()函数
 
 
 

初始化系统的api表;
    HeapInit();//初始化堆
    InitMemoryPool();//初始化内存池
    ProcInit();//初始化第一个进程
    SchedInit();//初始化调度器

 
 
 
 
 
 
 
 
 
 
 

    不过多关注KernelInit().

2.3 FirstSchedule

位于armtrap.s的一个label.开始第一个线程调度.整个内核开始运行.
 
原文地址: http://groups.google.com/group/wince_cn/web/armwindows-ce?hl=zh-CN&version=10
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息