WINCE60+S3C2443系统启动过程.docx

上传人:b****0 文档编号:18112849 上传时间:2023-08-13 格式:DOCX 页数:20 大小:412.97KB
下载 相关 举报
WINCE60+S3C2443系统启动过程.docx_第1页
第1页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第2页
第2页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第3页
第3页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第4页
第4页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第5页
第5页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第6页
第6页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第7页
第7页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第8页
第8页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第9页
第9页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第10页
第10页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第11页
第11页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第12页
第12页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第13页
第13页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第14页
第14页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第15页
第15页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第16页
第16页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第17页
第17页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第18页
第18页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第19页
第19页 / 共20页
WINCE60+S3C2443系统启动过程.docx_第20页
第20页 / 共20页
亲,该文档总共20页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

WINCE60+S3C2443系统启动过程.docx

《WINCE60+S3C2443系统启动过程.docx》由会员分享,可在线阅读,更多相关《WINCE60+S3C2443系统启动过程.docx(20页珍藏版)》请在冰点文库上搜索。

WINCE60+S3C2443系统启动过程.docx

WINCE60+S3C2443系统启动过程

WINCE6.0+S3C2443系统启动过程-

********************************LoongEmbedded********************************

作者:

LoongEmbedded(kandi)

时间:

2010.11.12

类别:

WINCEbootloader开发

********************************LoongEmbedded********************************

我们知道是NBOOT用来引导EBOOT,继而EBOOT加载并引导WinCE操作系统(NK)。

那么,WinCE6.0是如何启动的呢?

在前面文章我们知道eboot的OEMLaunch函数通过调用下面函数来跳转到dwPhysLaunchAddr处执行

Launch(dwPhysLaunchAddr)

我们先来看看NK.bin的imagestart等一些信息吧

图1

上图的startaddress=0x80245c50,这个地址经过OALVAtoPA()函数转换之后获得的对应的物理地址0x30245C50就是dwPhysLaunchAddr地址,那么这个地址对应的是NK.bin中哪个文件的哪个函数呢?

通过命令viewbin–onk.bin>output.txt输出output.txt到release目录下,下面看这个文件的下面内容:

图2

也可以通过PB6.0中浏览NK.bin的功能来查看这个地址(file->open->file,选择WindowsEmbeddedCERun-TimeImage类型,然后选择NK.bin)

图3

从图2或图3startaddress=0x80245c50对应的是NK.exe入口地址,而NK.exe就是OAL.exe,为什么呢?

我们看看release目录下ce.bib的如下内容

图4

由图4可知,NK.exe就是OAL.exe,那么OAL.exe的入口地址是哪个函数呢?

看\Src\Oal\Oalexe下面的source文件

图5

这样我们就知道eboot跳转到OAL.exe的startup函数中执行了。

1.Statup函数的主要部分

Startup入口

图6

因为EBOOT中已经初始化了相关硬件,所以OAL的启动代码就可以省去这部分工作,接着执行下面部分

图7

图7tst指令先用r0来和0x8进行与运算,结果为0,所以设置标志位Zero=1,后面的beq指定在zero=1的时候,跳转到下面标号4的地方,下面的链接是ARM汇编beq和bne的介绍

图8

图8的是将g_oalAddressTable保存到r0,作为参数传递给kernelStart函数,以便KernelStart函数中初始化MMU地址映射(g_oalAddressTable就是地址映射表的地址)。

我们怎么来理解

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

这条指令呢?

我们知道PC总是指向取指的指令,而不是指向正在执行的指令或是正在译码的指令,一般情况下,人们总是习惯把正在执行的指令作为参考点,称为当前第一条指令,因此,PC总是指向第3条指令。

对于ARM指令,有:

PC的值=当前指令所在的存储地址+8;对于Thumb指令,则有:

PC的值=当前指令所在的存储地址+4,下图是ARM系列的流水线图

图9

(.+8)这个表达式的.(+之前的点)是在MS的ARM编译器在预处理时决定的,其代表它所在的指令的地址(也即这条指令的存储地址)。

这里还要知道一点,就是ARM架构的特点,一条指令从加载到执行主要分为预取、译码、执行三个阶段。

结合上面提到的“PC的值=当前指令所在的存储地址+8”,因此有恒等式.+8=pc,上面语句可以理解为

r0=pc+g_oalAddressTable-(.+8)=g_oalAddressTable+(pc-(.+8))=g_oalAddressTable

也可以这样理解

r0=pc+g_oalAddressTable-(.+8)=pc-(.+8)+g_oalAddressTable=当前指令所在的存储地址+8-(.+8)+g_oalAddressTable=.+8--(.+8)+g_oalAddressTable=g_oalAddressTable

为什么要采用这样的方式给r0赋值,而不采用下面的语句呢

Ldrr0,g_oalAddressTable(我试过用这条语句,就不能成功跳转,系统无法正常启动)

为什么startup函数中不能直接把g_oalAddressTable符号的值赋值给r0来作为KernelStart函数的参数呢?

因为在调用KernelStart函数的时候MMU单元还处于关闭的状态,CPU访问外部物理存储器仍然使用的是系统物理地址,而g_oalAddressTable符号记录的是g_oalAddressTable数组的起始存储位置在0x80000000~0x9FFFFFFF范围内的虚拟内存地址。

之所以g_oalAddressTable符号记录的是虚拟内存地址而不是物理地址,并且落在了0x80000000~0x9FFFFFFF虚拟内存地址范围内,因为在汇编源代码中使用的用来表达程序地址的字符串在程序链接阶段要接受地址重定位的处理,而地址重定位的依据是config.bib,其中对系统物理存储的使用分配作出安排所使用的全部是0x80000000~0x9FFFFFFF范围内的虚拟内存地址

我们接下来看看从startup函数跳转到KernelStart函数的语句

blKernelStart;CalltheWinCEkernel.

首先我们要知道arm指令集与X86不同,不是通过栈空间来传递参数,而是通过寄存R0,R1,R2,R3来传递,而前面的语句就是把g_oalAddressTable的物理存储地址赋值给r0后传递给KernelStart函数的,到此,硬件平台初始化完成后,oal.exe的启动任务基本完成,余下的启动工作由内核相关且独立于内核的OAL层实现体kernel.dll接管

2.KernelStart函数

这个函数在\WINCE600\PRIVATE\WINCEOS\COREOS\NK\LDR\ARM\armstart.s中定义,这个函数的主要任务就是为WINCE操作系统设置页表并且启用MMU,先看KernelStart入口处

图10

设置页表的部分就不介绍了,下面看启动MMU和caches部分

图11

图11启用了MMU和caches部分之后,WINCE操作系统后面就使用虚拟内存地址而不是物理地址来访问了。

接着KernelStart函数为ABORT、IRQ、FIQ、UNDEF和supervisor这5个CPU的特权级状态设置堆栈

图12

这些工作完成之后KernelStart函数就会调用ARMInit函数,下面看是如何调用ARMIint函数的

图13

这样在调用ARMIint之前,r0就保存了KDataSrtuct这块数据区域的指针,也即r0指向了KDataSrtuct这块数据区域,这就是传递给ARMIint函数的参数,这个函数这个函数在\WINCE600\PRIVATE\WINCEOS\COREOS\NK\LDR\ARM\armint.c下面定义

图14

ARMIint函数有三个主要的任务:

是调用KernelRelocate()函数进行内核全局变量重定位。

图15

在ARMInit函数执行之前,系统仍无法使用全局变量,因为系统的全局还在ROM区域,对于操作系统而言,出于安全的考虑,只有XIP程序才有读取ROM区域数据的权利,对于大部分WINCE操作系统,只有将数据拷贝到RAM区域才能进行读写,ARMInit函数通过调用KernelRelocate函数对pTOC全局变量重新定位之后,才能读写。

对内核启动所需要的

全局变量重新定位之后,对内核启动所需要的KDataStruct结构体(它是内核数据结构,简单理解成共享内存好了,oal和kernel都可访问)进行初始化,是将位于OAL的OEMinitGlobals()函数指针赋值到pKdata的成员变量dwOEMInitGlobalsAddr,这个在后面的内核NKStartup函数将会用到,OEMInitGlobals便是交换oal.exe和kernel.dll之间的全局指针,下图是OEMInitGlobals函数体

图16

是调用函数FindKernelEntry通过TOC找到kernel.dll的入口点函数地址,是如何找到的呢?

先看FindKernelEntry函数体

图17

图17具体是如何找到kernel.dll的入口函数的呢?

我们通过viewbin–onk.bin>output.txt输出NK.bin的相关信息中的kernel.dll部分信息如下

图18

我们看kernel.map文件

图19

再来看下图

图20

结合图18,图19和图20我们可以知道kernel.dll的入口函数是NKStartup,这样通过调用函数ARMInit函数就返回NKStartup,那么我们回到KernelStart函数来看看是如何跳转到NKStartup函数执行的

图21

就这样跳转到NKStartup函数执行了。

3.NKStartup函数

这个函数在\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\mdram.c中定义,我们先看看NKStartup函数头的注释吧

图22

NKstartup函数的主要工作如下:

从NKLoader传递过来的KDataStruct结构体数据中获取到供自身启动所需要的数据信息,如下图所示,其中

图23

定位对WINCE6.0特有的OEMGLOBAL结构体的初始化函数OEMInitGlobals地址,该结构体构建了内核和OAL层之间进行通信的桥梁。

在OEMGLOBAL结构体定义了OAL层所必须的函数,该结构体在oemglobal.c文件中被初始化,并被编译在OEMMain.lib和OEMMain_StaticKITL.lib两个库中,如果OAL链接这两个库,则必须要有该结构体中函数实现体;

图24

这里涉及到一个很重要的全局变量g_pOemGlobal,它指向结构体OEMGLOBAL全局变量OemGlobal,而OemGlobal在oemglobal.c定义并对其成员函数赋值,下图是其中一部分

图25

在这里,我们看到了一个很重要的函数OEMInit,这些OEM函数就是被内核用来和OAL部分通信的。

调用函数ARMSetup为操作系统内核进程填充虚拟内存0XA0000000~0XBFFFFFFF范围的uncachable静态映射区域,在前面的KernelStartup函数中,依据g_oalAddressTable数组的数据内容将所有的系统物理地址单元(包括所有类型的CPU可直接寻址访问的物理存储设备和各类外设的控制与状态寄存器、数据缓冲区而后I/O端口)映射到虚拟内存的0x80000000~0x9FFFFFFF地址范围。

这是WINCE操作系统的一个约束,正是由于这个缘故,在基于WINCE操作系统中所有的系统物理地址单元总容量不得超过512MB,在ARMSetup函数中再一次将全部的物理存储映射到虚拟地址的0xA0000000~0xBFFFFFFF地址范围。

图26

另外ARMSetup函数还设置中断向量表,如下

图27

如果系统启用了KITL调试功能,则加载KITL模块

图28

至于kitl.dll的入口函数值如何确定的呢?

这个办法可以参考上面介绍到如何定位kernel.dll的入口函数一样,我们可以找到kitl.dll的入口函数是KitlDllMain()。

当在编译选项(BuildOptions)中选中EnableKITL时,编译器就会将kitl.dll动态链接库链接到到内核中,在OEMGLOBAL结构体定义了利用KITLOEM宏将kitl.dll的入口函数KitlDllMain编译到系统中条件,这是系统链接的库为oemmain_statickitl.lib,下面为OEMGLOBAL结构体中KITL的定义部分,我们看OemGlobal全局数组中的pfnKITLGlobalInit成员的初始化

图29

调用OAL函数执行对目标平台板级硬件的初始化动作。

图30

图30注释中的OEMInit是OAL中用来实现对板级硬件进行初始化的一个很重要的OEM函数,其主要的任务是初始化cache全局变量,初始化LCD控制器,初始化中断,初始化系统时钟和初始化KITL等,其他OAL函数也是通过这样的方式被内核调用来和OAL层通信的。

清楚TLB,分隔RAM区域和跳转到KernelStartup函数执行。

图31

KernelFindMemory()是查找系统可用内存并且分隔,在WINCE操作系统中,RAM空间主要分为存储内存和程序内存,存储内存主要为文件的存储空间,包括内核文件和复制到系统中所有目标文件,程序内存为运行程序时所需要的存储空间,见相关的博文

NKStartup函数完成自己的工作之后跳转到第二个KernelStart函数,这里的KernelStart函数与前面的KernelStart函数的属于两个完全不同的函数,NKStartup函数中调用的KernelStart函数为\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\armtrap.s文件中的KernelStart函数,主要完成调用内核初始化函数KernelInit,并跳转到操作系统的第一个启动的任务,这个KernelStartup函数与NKstartup函数同属一个静态库及同一个kernel.dll模块,而上一个KernelStartup函数所属的nkldr.lib库被链接进了WINCE系统模块oal.exe中。

4.第二个KernelStart函数

图32

这个函数的主要工作有两部分:

调用KernelInit函数来初始化内核

图33

在目标设备上的硬件初始化结束后,下一步就是调用KernelInit内核初始化函数来初始化WINCE操作系统本身,WINCE6.0的内核初始化函数同其他版本的内核初始化函数基本相近,主要完成在启动第一个线程前对内核进行初始化,主要包括API函数集初始化、堆的初始化、初始化内存池、进程初始化、线程初始化和文件映射初始化等操作。

下面来看THRDIint函数体最重要的一部分,THRDInit()初始化了第一个线程是SystemStartupFunc。

图34

⑵FirstSchedule

FirstSchedule函数为WindowsCE操作系统启动过程中最后无条件跳转的一个函数,FirstSchedule调用HandleException函数来让系统进行重新调度,这样就选择了第一个就绪的线程(也就是SystemStartupFunc)来执行,下面接着看线程处理函数SystemStartupFunc

图35

接着看RunApps线程

图36

RunApps线程处理函数主要是启动filesys.dll,启动后等待其执行的情况,在完成了文件系统的相应的初始化之后,这里继续初始化MUI和系统设置,完成后再通知filesys这边的工作已经完成,filesys继续启动,filesys会完成WinCE的最后启动过程,包括设备管理device.dll,窗体图像子系统gews.dll和shell程序explore.exe,这样,WINCE6.0的启动就完成了。

备注:

对于fiesys文件系统的启动过程,可以看MSDN的描述

图35

参考文档

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2