uclinux启动过程详细分析
ldr r3, =0x10000 /* 64K Bytes */
ldr r2, =0xc700000
ldr r1, =0
next :
ldr r0,[r1],#4
str r0,[r2],#4
cmp r1,r3
bne next
6)跳转到C代码执行(即Stage2阶段)
这个过程是直接给指令指针赋值于跳转的C代码的入口地址,在我们的试验中该入口地址是Main。
LDR pc,=Main
2.4 Stage2阶段
该阶段的代码主要使用C语言来实现的。该阶段的工作主要是建立开发板与宿主机之间的通信,加载uClinux内核映像文件和配置内核启动参数,并且启动内核。
嵌入式设备与宿主机的通讯方式有多种,最常用的是使用串口方式进行数据交换。本试验采用的S3C44B0微处理器提供了两个UART口,因此我们可以任选其中一个来初始化并且使用它来与宿主机交互。对于串口的初始化主要是波特率、奇偶校验、停止位、数据位等内容。
对于串口的波特率和波特因子的计算采用如下公式
Iubrd =((int(mclk/16 / baud + 0.5) – 1)
mclk是频率、baud为波特率
2.4.1 检测内存
该部分的功能主要是检测系统在进行硬件初始化的时候是否发生了内存映射错误,即是否物理地址是否被映射到不存在的地址空间。通常是使用读写方式来检测的,即以内存页为单位,在每个页头进行读写操作,比较读写结果。因为S3C44B0处理器并不支持内存映射,因此我们在Stage2过程中并没有包含该部分功能函数。
2.4.2 加载uClinux内核映像
该过程其实只是一个从Flash的指定位置(该位置是uClinux烧写的起始地址)拷贝到RAM中指定的地址空间里。在拷贝之前必须要为uClinux的全局变量结构,即启动参数、内核页表、RAM的页目录等信息预留一定的空间。如果我们将FLASH和RAM看成连在一起的线性地址,则系统的空间分配会如下图:
。..。..
Boot
初始化代码
uClinux
未用
中断向量表
初始化映像代码
启动参数
内核映像
未用
堆栈
2.4.3 配置内核启动参数
我们采用的uClinux是2.4.x内核版本,该版本的内核支持参数启动过程。在嵌入式系统中,启动参数的传入主要是依靠bootloader程序向标记列表(tagged list)的相关域中填写相应的值来完成的。
2.5 uClinux内核引导
当我们初始化完毕uClinux的启动参数之后,控制权就可以交给uClinux内核了,uClinux系统调用内核解压函数(decompress_kernel)来对上一个阶段拷贝的uClinux内核在RAM空间里进行解压(当然如果系统内核在建立的时候没有配置成压缩格式,则解压过程略去)。在解压完毕后,跳转到内核调用函数(call_kernel),该函数实际上执行的是start_kernel(),这个函数包含了有关处理器初始化、中断初始化、进程初始化等操作。最后,将控制权完全的交与uClinux操作系统来执行。
伪处理过程如下:
IF(启动参数正确)
CALL decmporess_kernel()
CALL call_kernel()
ELSE
启动失败
decompress_kernel()
{
解压内核映像
}
call_kernel()
{
。..
start_kernel()
。..。
}
3 总结
本文是对S3C44B0的启动过程进行了一次分析,启动部分的代码可以说是嵌入式设备开发比较重要的部分。而且该部分的处理工作往往又比较麻烦,因此在这里我只是想起到抛砖引玉的作用。因为成文时间比较仓促,难免有错误,请大家批评指正。
==========================================================
《ARM7 uClinux开发实验与实践》P130
Bootloader完成系统初始化工作后,将运行控制权交给uClinux内核。根据内核是否压缩以及内核是否在本地执行,uClinux通常有以下两种可选的启动方式:
(1)Flash本地运行方式。内核中未经压缩的可执行映像固化在Flash中,系统启动时,内核在Flash中开始逐句执行。
(2)压缩内核加载方式。内核的压缩映像固化在Flash上,系统启动时,由附加在压缩映像前的解压复制程序读取压缩映像,并在内存中解压后执行。这种方式相对复杂,但是运行速度更快。
首先介绍内核的Flash本地运行方式。
本地运行时,内核的启动包括特定体系结构设置和uClinux系统初始化两步,内核启动的入口文件是head-armv.s。
加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW
或用微信扫描左侧二维码