基于S3C44B0芯片的uClinux内核引导过程分析
存器*/
LDR a2, = Image_ZI_L imit /* 获取清零区域尾地址*/
CMP a1, a2
BEQ move_data
clear_loop: : /* 清零Image_ZI_Base到Image_ZI_Limit区域*/
STR a3, [ a1 ] , #4/* 清零4个字节,即一个字*/
CMP a1, a2 /* 判断是否到达清零区域尾部*/
BNE clear_loop /* 否则,继续清零循环*/
(4) 为运行C程序组织堆栈。由于在系统引导的下一阶段,通常会使用C语言来完成大部分(如建立主机通信、驱动外部端口的工作) ,故必须调整SP指针到堆栈顶,为C程序配置合适的堆栈环境。在具体实现过程中为避免堆栈数据被程序运行代码破坏,往往会把堆栈设置在RAM的高端地址,并把堆栈的生长方向设为向下生长,这样可以最大限度地利用RAM空间,同时可以避免上述问题发生。
(5)拷贝初始化阶段代码到RAM。由于在S3C44B0芯片中Flash和RAM是统一编址的,只需通过简单的循环来实现代码拷贝工作。
copy_code_to_ram :
LDR r3, = Flash_Sou/* Flash_Sou为Flash中代码首地址*/
LDR r2, =Ram_Dest /* Ram_Dest为Ram中代码首地址*/
LDR r1, = 0
next :
LDR r0, [ r1 ] , #4
STR r0, [ r2 ] , #4 /* 复制到ram*/
CMP r1, r3
BNE next
跳转到C程序入口:
LDR pc, =Main
系统初始化阶段
系统初始化阶段的主要工作是建立与主机间的通信、初始化定时器、检测内存映射、加载uClinux内核镜像和配置内核启动参数等。
与主机建立通讯
面向最终用户的嵌入式产品,其启动过程应该是不需要人工干预的,但对于大多数嵌入式开发平台而言,必须通过某种方式与主机间建立通讯联系,输出启动提示信息,以实现人工干预的系统启动过程,提供更加丰富的附加功能。一般情况下,最为廉价和简单的方式是通过串口实现嵌入式系统与主机间通讯( S3C44B0提供2个Uart口,建立通信前必须初始化至少一个),这种情况下就必须事先对串口进行初始化工作。
以本开发板为例,在系统初始化的初期,就进行了Uart口的初始化工作,并通过该端口与用户宿主机上的超级终端程序通信,从而提供了多种启动功能的选择,包括Demo程序下载、Flash重新编程等。Uart0口初始化过程可参看以下C代码,其中波特率因子的计算公式可以查阅S3C44B0芯片手册。
rULCON0 = 0x3;//设置Uart0 口线控寄存器,无奇偶效验, 8数据位, 0停止位
rUCON0 = 0x345;//设置Uart0控制寄存器
rUBRD IV0 = ( ( int) (mclk /16. /baud + 0.5) - 1 ) ;//设置波特率因子,其中mclk和baud为系统频率和波特率
初始化定时器
通过设置系统定时器相关的寄存器,实现为操作系统提供最基本的系统时钟支持。
检测内存映射
为防止发生内存映射错误,即系统映射到物理地址不存在的空间,必须对内存地址作读写一致性效验。通常做法是以内存页为单位,在每个页头进行读写操作,并比较读写结果。
加载uClinux内核镜像
加载uClinux内核工作实际上是完成将Flash中uClinux内核代码拷贝到RAM指定地址单元的工作,在拷贝前必须在第二阶段RAM启动代码和该部分代码之间预留一定的空间,用来存放uClinux的全局结构变量,如: 启动参数、内核页表、ARM的页目录等信息。全地址空间的分配情况可参看本开发板地址空间分配示意图1。
图1 地址空间分配示意图
配置内核启动参数
uClinux 内核启动过程中,支持参数传入。在嵌入式系统中,启动参数的传入主要靠bootloader程序向标记列表( tagged list)的相关域中填写对应的值来完成,常见的参数如有ATAG_CORE、ATAG_MEM、ATAG_CMDL INE、ATAG_RAMD ISK、ATAG_ IN ITRD等。
uClinux内核引导
在初始化阶段完成uClinux启动参数设置后,控制权交由uClinux内核接管,并调用解压内核函数( decomp ress_kernel) ,对拷贝到SDRAM的内核映像文件进行解压缩,然后跳转到内核调用函数( call_ kernel) ,该函数实际上是执行start_kernel ( ) ,其中包括了处理器结构的初始化、中断的初始化、进程相关的初始化以及内存初始化等重要工作。最后,将控制权交给解压后的uClinux系统,进而完成整个uClinux内核引导过程,参看以下伪码: If (启动参数配置正确)调用decomp ress_kernel ( )调用call_kernel ( )else提示启动失败decomp ress_kernel( ){解压内核镜像文件}call_kernel ( ){ start_kernel( ) ;}
小 结
对于嵌入式系统开发人员来说,针对某一特定的嵌入式硬件平台,移植开发基于uClinux操作系统的应用产品时,往往需要自己动手编写或修改已有的启动代码,而为uClinux内核启动准备合适的工作环境,占据了大部分工作量。至于uClinux引导,在设置好启动参数后则是由编
引导 过程 分析 内核 uClinux S3C44B0 芯片 基于 相关文章:
- 基于JTAG的DSP外部FLASH在线编程与引导技术(01-22)
- DSP芯片TMS320C6712的外部内存自引导功能的实现(08-30)
- WinCE启动失败原因与解决办法(03-01)
- MCU+DSP嵌入式平台的i机接口与引导设计 (06-25)
- ARM系统预引导固件的新机遇- UEFI(07-12)
- BLOB启动流程分析及引导程序可移植性研究(07-25)