Uboot启动流程.docx
- 文档编号:5654591
- 上传时间:2022-12-30
- 格式:DOCX
- 页数:40
- 大小:210.81KB
Uboot启动流程.docx
《Uboot启动流程.docx》由会员分享,可在线阅读,更多相关《Uboot启动流程.docx(40页珍藏版)》请在冰豆网上搜索。
Uboot启动流程
U-Boot启动过程
(国嵌)
开发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。
看一下board/smdk2410/u-boot.lds这个脚本,可以知道目标程序的各部分顺序。
第一个要的是cpu/arm920t/start.o,那么U-Boot的入口指令一定位于这个程序中。
下面分两阶段介绍启动流程:
第一阶段
1.cpu/arm920t/start.S
这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。
_start:
breset//复位向量
ldrpc,_undefined_instruction
ldrpc,_software_interrupt
ldrpc,_prefetch_abort
ldrpc,_data_abort
ldrpc,_not_used
ldrpc,_irq//中断向量
ldrpc,_fiq//中断向量
…
/*theactualresetcode*/
reset:
//复位启动子程序
/*设置CPU为SVC32模式*/
mrsr0,cpsr
bicr0,r0,#0x1f
orrr0,r0,#0xd3
msrcpsr,r0
/*关闭看门狗*/
…………
relocate:
/*把U-Boot重新定位到RAM*/
adrr0,_start/*r0是代码的当前位置*/
ldrr1,_TEXT_BASE/*_TEXT_BASE是RAM中的地址*/
cmpr0,r1/*比较r0和r1,判断当前是从Flash启动,还是RAM*/
beqstack_setup/*如果r0等于r1,跳过重定位代码*/
/*准备重新定位代码*/
ldrr2,_armboot_start
ldrr3,_bss_start
subr2,r3,r2/*r2得到armboot的大小*/
addr2,r0,r2/*r2得到要复制代码的末尾地址*/
copy_loop:
/*重新定位代码*/
ldmiar0!
{r3-r10}/*从源地址[r0]复制*/
stmiar1!
{r3-r10}/*复制到目的地址[r1]*/
cmpr0,r2/*复制数据块直到源数据末尾地址[r2]*/
blecopy_loop
/*初始化堆栈等*/
stack_setup:
ldrr0,_TEXT_BASE/*上面是128KiB重定位的u-boot*/
subr0,r0,#CFG_MALLOC_LEN/*向下是内存分配空间*/
subr0,r0,#CFG_GBL_DATA_SIZE/*然后是bdinfo结构体地址空间*/
#ifdefCONFIG_USE_IRQ
subr0,r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
subsp,r0,#12/*为abort-stack预留3个字*/
clear_bss:
ldrr0,_bss_start/*找到bss段起始地址*/
ldrr1,_bss_end/*bss段末尾地址*/
movr2,#0x00000000/*清零*/
clbss_l:
strr2,[r0]
/*bss段地址空间清零循环...*/
addr0,r0,#4
cmpr0,r1
bneclbss_l
/*跳转到start_armboot函数入口,_start_armboot字保存函数入口指针*/
ldrpc,_start_armboot
_start_armboot:
.wordstart_armboot//start_armboot函数在lib_arm/board.c中实现
第二阶段
2.lib_arm/board.c
start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。
3.init_sequence[]
init_sequence[]数组保存着基本的初始化函数指针。
init_fnc_t*init_sequence[]={
cpu_init,/*基本的处理器相关配置--cpu/arm920t/cpu.c*/
board_init,/*基本的板级相关配置--board/smdk2410/smdk2410.c*/
interrupt_init,/*初始化中断处理--cpu/arm920t/s3c24x0/interrupt.c*/
env_init,/*初始化环境变量--mon/cmd_flash.c*/
init_baudrate,/*初始化波特率设置--lib_arm/board.c*/
serial_init,/*串口通讯设置--cpu/arm920t/s3c24x0/serial.c*/
console_init_f,/*控制台初始化阶段1--mon/console.c*/
display_banner,/*打印u-boot信息--lib_arm/board.c*/
dram_init,/*配置可用的RAM--board/smdk2410/smdk2410.c*/
display_dram_config,/*显示RAM的配置大小--lib_arm/board.c*/
NULL,
};
voidstart_armboot(void)
{
/*顺序执行init_sequence数组中的初始化函数*/
for(init_fnc_ptr=init_sequence;*init_fnc_ptr;++init_fnc_ptr){
if((*init_fnc_ptr)()!
=0){
hang();
}
}
/*配置可用的Flash*/
size=flash_init();
display_flash_config(size);
/*_armboot_start在u-boot.lds脚本中定义*/
mem_malloc_init(_armboot_start-CFG_MALLOC_LEN);
/*配置环境变量*/
env_relocate();
/*从环境变量中获取IP地址*/
gd->bd->bi_ip_addr=getenv_IPaddr("ipaddr");
/*以太网接口MAC地址*/
……
devices_init();/*获取列表中的设备*/
jumptable_init();
console_init_r();/*完整地初始化控制台设备*/
enable_interrupts();/*使能中断处理*/
/*通过环境变量初始化*/
if((s=getenv("loadaddr"))!
=NULL){
load_addr=simple_strtoul(s,NULL,16);
}
/*main_loop()循环不断执行*/
for(;;)
{
main_loop();/*主循环函数处理执行用户命令--mon/main.c*/
}
命令实现
U-Boot作为Bootloader,具备多种引导内核启动的方式。
常用的go和bootm命令可以直接引
导内核映像启动。
U-Boot与内核的关系主要是内核启动过程中参数的传递。
1.go命令的实现
/*mon/cmd_boot.c*/
intdo_go(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[])
{
ulongaddr,rc;
intrcode=0;
if(argc<2){
printf("Usage:
\n%s\n",cmdtp->usage);
return1;
}
addr=simple_strtoul(argv[1],NULL,16);
printf("##Startingapplicationat0x%08lX...\n",addr);
rc=((ulong(*)(int,char[]))addr)(--argc,&argv[1]);/*运行程序*/
if(rc!
=0)rcode=1;
printf("##Applicationterminated,rc=0x%lX\n",rc);/*如果是运行linux,这条指令是否能运行?
*/
returnrcode;
}
go命令调用do_go()函数,跳转到某个地址执行的。
如果在这个地址准备好了自引导的内核映像,就可以启动了。
尽管go命令可以带变参,实际使用时不用来传递参数。
2.bootm命令的实现
/*mon/cmd_bootm.c*/
intdo_bootm(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[])
{
…………
/*检查头部*/
if(crc32(0,(uchar*)data,len)!
=checksum){
puts("BadHeaderChecksum\n");
SHOW_BOOT_PROGRESS(-2);
return1;
}
…………
/*解压缩*/
switch(hdr->ih_p){
caseIH_P_NONE:
if(ntohl(hdr->ih_load)==addr){
printf("XIP%s...",name);
}else{
#ifdefined(CONFIG_HW_WATCHDOG)||defined(CONFIG_WATCHDOG)
size_tl=len;
void*to=(void*)ntohl(hdr->ih_load);
void*from=(void*)data;
printf("Loading%s...",name);
while(l>0){
size_ttail=(l>CHUNKSZ)?
CHUNKSZ:
l;
WATCHDOG_RESET();
memmove(to,from,tail);
to+=tail;
from+=tail;
l-=tail;
}
#else/*!
(CONFIG_HW_WATCHDOG||CONFIG_WATCHDOG)*/
memmove((void*)ntohl(hdr->ih_load),(uchar*)data,len);
#endif/*CONFIG_HW_WATCHDOG||CONFIG_WATCHDOG*/
}
break;
caseIH_P_GZIP:
printf("Unpressing%s...",name);
if(gunzip((void*)ntohl(hdr->ih_load),unc_len,
(uchar*)data,&len)!
=0){
puts("GUNZIPERROR-mustRESETboardtorecover\n");
SHOW_BOOT_PROGRESS(-6);
do_reset(cmdtp,flag,argc,argv);
}
break;
#ifdefCONFIG_BZIP2
caseIH_P_BZIP2:
printf("Unpressing%s...",name);
/*
*Ifwe'vegotlessthan4MBofmalloc()space,
*useslowerdepressionalgorithmwhichrequires
*atmost2300KBofmemory.
*/
i=BZ2_bzBuffToBuffDepress((char*)ntohl(hdr->ih_load),
&unc_len,(char*)data,len,
CFG_MALLOC_LEN<(4096*1024),0);
if(i!
=BZ_OK){
printf("BUNZIP2ERROR%d-mustRESETboardtorecover\n",i);
SHOW_BOOT_PROGRESS(-6);
udelay(100000);
do_reset(cmdtp,flag,argc,argv);
}
break;
#endif/*CONFIG_BZIP2*/
default:
if(iflag)
enable_interrupts();
printf("Unimplementedpressiontype%d\n",hdr->ih_p);
SHOW_BOOT_PROGRESS(-7);
return1;
}
}
………………
switch(hdr->ih_os){
default:
/*handledby(original)Linuxcase*/
caseIH_OS_LINUX:
do_bootm_linux(cmdtp,flag,argc,argv,
addr,len_ptr,verify);
break;
caseIH_OS_NETBSD:
do_bootm_netbsd(cmdtp,flag,argc,argv,
addr,len_ptr,verify);
break;
caseIH_OS_RTEMS:
do_bootm_rtems(cmdtp,flag,argc,argv,
addr,len_ptr,verify);
break;
caseIH_OS_VXWORKS:
do_bootm_vxworks(cmdtp,flag,argc,argv,
addr,len_ptr,verify);
break;
caseIH_OS_QNX:
do_bootm_qnxelf(cmdtp,flag,argc,argv,
addr,len_ptr,verify);
break;
}
bootm命令调用do_bootm函数。
这个函数专门用来引导各种操作系统映像,可以支持引导Linux、vxWorks、QNX等操作系统。
引导Linux的时候,调用do_bootm_linux()函数。
3.do_bootm_linux函数的实现
/*lib_arm/armlinux.c*/
voiddo_bootm_linux(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[],
ulongaddr,ulong*len_ptr,intverify)
{
theKernel=(void(*)(int,int,uint))ntohl(hdr->ih_ep);
…………
/*weassumethatthekernelisinplace*/
printf("\nStartingkernel...\n\n");
…………
theKernel(0,bd->bi_arch_number,bd->bi_boot_params);/*启动内核,传递启动参数*/
}
do_bootm_linux()函数是专门引导Linux映像的函数,它还可以处理ramdisk文件系统的映像。
这里引导的内核映像和ramdisk映像,必须是U-Boot格式的。
U-Boot格式的映像可以通过mkimage工具来转换,其中包含了U-Boot可以识别的符号。
U-Boot启动过程完全分析
1.1U-Boot工作过程
U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:
(1)第一阶段的功能
Ø硬件设备初始化
Ø加载U-Boot第二阶段代码到RAM空间
Ø设置好栈
Ø跳转到第二阶段代码入口
(2)第二阶段的功能
Ø初始化本阶段使用的硬件设备
Ø检测系统内存映射
Ø将内核从Flash读取到RAM中
Ø为内核设置启动参数
Ø调用内核
1.1.1U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/start.S和board/samsung/mini2440/lowlevel_init.S。
U-Boot启动第一阶段流程如下:
图2.1U-Boot启动第一阶段流程
根据cpu/arm920t/u-boot.lds中指定的连接方式:
ENTRY(_start)
SECTIONS
{
.=0x00000000;
.=ALIGN(4);
.text:
{
cpu/arm920t/start.o(.text)
board/samsung/mini2440/lowlevel_init.o(.text)
board/samsung/mini2440/nand_read.o(.text)
*(.text)
}
……
}
第一个的是cpu/arm920t/start.o,因此u-boot.bin的入口代码在cpu/arm920t/start.o中,其源代码在cpu/arm920t/start.S中。
下面我们来分析cpu/arm920t/start.S的执行。
1.硬件设备初始化
(1)设置异常向量
cpu/arm920t/start.S开头有如下的代码:
.globl_start
_start:
bstart_code/*复位*/
ldrpc,_undefined_instruction/*未定义指令向量*/
ldrpc,_software_interrupt/*软件中断向量*/
ldrpc,_prefetch_abort/*预取指令异常向量*/
ldrpc,_data_abort/*数据操作异常向量*/
ldrpc,_not_used/*未使用*/
ldrpc,_irq/*irq中断向量*/
ldrpc,_fiq/*fiq中断向量*/
/*中断向量表入口地址*/
_undefined_instruction:
.wordundefined_instruction
_software_interrupt:
.wordsoftware_interrupt
_prefetch_abort:
.wordprefetch_abort
_data_abort:
.worddata_abort
_not_used:
.wordnot_used
_irq:
.wordirq
_fiq:
.wordfiq
.balignl16,0xdeadbeef
以上代码设置了ARM异常向量表,各个异常向量介绍如下:
表2.1ARM异常向量表
地址
异常
进入模式
描述
0x00000000
复位
管理模式
复位电平有效时,产生复位异常,程序跳转到复位处理程序处执行
0x00000004
未定义指令
未定义模式
遇到不能处理的指令时,产生未定义指令异常
0x00000008
软件中断
管理模式
执行SWI指令产生,用于用户模式下的程序调用特权操作指令
0x0000000c
预存指令
中止模式
处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常
0x00000010
数据操作
中止模式
处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常
0x00000014
未使用
未使用
未使用
0x00000018
IRQ
IRQ
外部中断请求有效,且CPSR中的I位为0时,产生IRQ异常
0x0000001c
FIQ
FIQ
快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常
在cpu/arm920t/start.S中还有这些异常对应的异常处理程序。
当一个异常产生时,CPU根据异常号在异常向量表中找到对应的异常向量,然后执行异常向量处的跳转指令,CPU就跳转到对应的异常处理程序执行。
其中复位异常向量的指令“bstart_code”决定了U-Boot启动后将自动跳转到标号“start_code”处执行。
(2)CPU进入SVC模式
start_code:
/*
*setthecputoSVC32mode
*/
mrsr0,cpsr
bicr0,r0,#0x1f/*工作模式位清零*/
orrr0,r0,#0xd3/*工作模式位设置为“10011”(管理模式),并将中断禁止位和快中断禁止位置1*/
msrcpsr,r0
以上代码将CPU的工作模式位设置为管理模式,并将中断禁止位和快中断禁止位置一,从而屏蔽了IRQ和FIQ中断。
(3)设置控制寄存器地址
#ifdefined(CONFIG_S3C2400)
#definepWTCON0x15300000
#defineINTMSK0x14400008
#defineCLKDIVN0x14800014
#else/*s3c2410与s3c2440下面4个寄存器地址相同*/
#definepWTCON0x53000000/*WATCHDOG控制寄存器地址*/
#defineINTMSK0x4A000008/*INTMSK寄存器地址*/
#defineINTSUBMSK0x4A00001C/*INTSUBMSK寄存器地址*/
#defineCLKDIVN0x4C000014/*CLKDIVN寄存器地址*/
#endif
对与s3c2440开发板,以上代码完成了WATCHDOG,INTMSK,INTSUBMSK,CLKDIVN四个寄存器的地址的设置。
各个寄存器地址参见参考文献[4]。
(4)关闭看门狗
ldrr0,=pWTCON
movr1,#0x0
strr1,[r0]/*看门狗控制器的最低位为0时,看门狗不输出复位信号*/
以上代码向看门狗控制寄存器写入0,关闭看门狗。
否则在U-Boot启动过程中,CPU将不断重启。
(5)屏蔽中断
/*
*maskallIRQsbysettingallbitsintheINTMR-default
*/
movr1,#0xffffffff/*某位被
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Uboot 启动 流程
![提示](https://static.bdocx.com/images/bang_tan.gif)