u-boot-2011.09
am335x启动流程:
1.rom code(详见芯片手册)
2.spl(Secondary Program Loader)
根据spl/u-boot-spl.lds<===arch/arm/cpu/armv7/omap-common/u-boot-spl.lds:
arch/arm/cpu/armv7/start.o (.text)
_start:
b reset
bl save_boot_params://arch/arm/cpu/armv7/ti81xx/lowlevel_init.S
#ifdef CONFIG_SPL_BUILD
ldr r4, =ti81xx_boot_device
ldr r5, [r0, #BOOT_DEVICE_OFFSET]//rom启动后,将一个BootParametersStructure的指针保存在r0,其中r0+8保存boot device(详见芯片手册)
and r5, r5, #BOOT_DEVICE_MASK//取低八位
str r5, [r4]//将boot device保存在变量ti81xx_boot_device
#endif
bx lr
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit//只有在spl中才执行,uboot中不执行
bl lowlevel_init//lowlevel_init.S,设置堆栈,跳转到c函数
bl s_init//evm.c
l2_cache_enable();//cache.S,cp15
//关看门狗
pll_init();***
preloader_console_init();//spl.c
//#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")//r8寄存器保存gd的地址
//static gd_t gdata __attribute__ ((section(".data")));
gd = &gdata;//spl阶段r8=gd=&gdata,位于sram (MLO的data段)
config_am335x_ddr();
#endif
bl board_init_f//spl.c
/*
* We call relocate_code() with relocation target same as the
* CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
* skipped. Instead, only .bss initialization will happen. That's
* all we need //设置重定向地址为sram基地址,故意跳过relocation,只清bbs段
*/
relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
relocate_code://start.S
mov r4, r0 /* save addr_sp */ //栈地址=CONFIG_SPL_STACK
mov r5, r1 /* save addr of gd */ //gd地址=&gdata(位于data段)
mov r6, r2 /* save addr of destination */ //重定位地址=CONFIG_SPL_TEXT_BASE
/* Set up the stack */
stack_setup:
mov sp, r4
/*
adr伪指令相对于pc(运行时确定)。adr的反汇编就是基于PC的add sub指令
位置无关,用于获得_start的真正运行地址(而不是链接地址)
*/
adr r0, _start// adr伪指令相对于pc(运行时确定),当前PC位于sram,所以r0=CONFIG_SPL_TEXT_BASE
cmp r0, r6 // r0=r6 说明在sram中运行
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */ //r9保存重定向地址的偏移地址,spl中不进行重定向,r9=0
beq clear_bss /* skip relocation */ //跳过relocation,以下代码在spl中没有执行。调用clear_bss
/************ skip relocation in spl ***********/
mov r1, r6 /* r1 <- scratch for copy_loop*/ //r1=sram_start
ldr r3, _image_copy_end_ofs //_image_copy_end_ofs=__image_copy_end - _start
add r2, r0, r3 /* r2 <- source end address */
copy_loop: //在spl中,这段代码是将自己copy给自己。实际上在spl中这段代码没有被调用,因为clear_bss没有返回
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
/************ skip relocation in spl ***********/
clear_bss:
#ifdef CONFIG_SPL_BUILD
/* No relocation for SPL */
ldr r0, =__bss_start
/*
*u-boot-spl.lds,sdram中的bss = CONFIG_SPL_BSS_START_ADDR = 0x80000000,即sdram起始地址
*CONFIG_SPL_BSS_MAX_SIZE = 0x80000,即MLO的BBS段位于sdram 0x80000000-0x80080000(512k),
*/
ldr r1, =__bss_end__
#endif
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
jump_2_ram:
/*
* If I-cache is enabled invalidate it
*/
#ifndef CONFIG_SYS_ICACHE_OFF
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
#endif
ldr r0, _board_init_r_ofs//r0=board_init_r - _start(board_init_r偏移地址)
adr r1, _start //r1=_start的运行地址
add lr, r0, r1 //lr=board_init_r的真正运行地址
add lr, lr, r9 //r9保存重定向偏移大小,spl中 r9 = 0
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */ //r0 = &gdata
mov r1, r6 /* dest_addr */ //r6=CONFIG_SPL_TEXT_BASE
/* jump to it ... */
mov pc, lr //跳转到board_init_r
_board_init_r_ofs:
.word board_init_r - _start
//确定board_init_r和_start差值。如果是spl,board_init_r位于spl.c。如果是uboot,board_init_r位于board.c
void board_init_r(gd_t *id, ulong dummy)//spl.c,这段代码仍然在sram中运行
timer_init();
i2c_init
spl_board_init();
boot_device = omap_boot_device() = ti81xx_boot_device;
spl_nand_load_image();
{
gpmc_init();****
nand_init();****//nand_spl_simple.c
board_nand_init//ti81xx_nand.c
/*use CONFIG_SYS_TEXT_BASE as temporary storage area */
header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);//临时保存image_header到CONFIG_SYS_TEXT_BASE
nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,//#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000//nand的第5块
CONFIG_SYS_NAND_PAGE_SIZE, (void *)header);//先读nand flash中uboot分区的第一页数据:image_header(64字节)
spl_parse_image_header(header);//解析 image_header,结果保存在spl_image.其内容由mkimage的参数决定。
nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,//再读整个uboot镜像到load_addr(sdram)
spl_image.size, (void *)spl_image.load_addr);//load_addr=0x80800000(entry_point) - 64(image_header_size) = 807FFFC0
nand_deselect();
}
jump_to_image_no_args();
{
typedef void (*image_entry_noargs_t)(void)__attribute__ ((noreturn));
image_entry_noargs_t image_entry =
(image_entry_noargs_t) spl_image.entry_point;
// image_entry_noargs_t image_entry =
// (image_entry_noargs_t) 0x80800000;
image_entry();
/*
在反汇编中,无论是使用blx还是ldr,最终从sram跳转到sdram中运行。
当使用spl_image.entry_point(运行时确定,保存在bss段),反汇编使用ldr pc,[0x8000000c](位于bss)(u-boot-spl.map)。
当使用0x80800000时,反汇编使用blx 0x80800000,超过了32M,具体实现细节由连接器实现
*/
}
//至此,第二阶段spl结束。PC跳转到0x80800000(CONFIG_SYS_TEXT_BASE)执行u-boot
3.u-boot
根据u-boot.lds<===arch/arm/cpu/armv7/u-boot.lds:
arch/arm/cpu/armv7/start.o (.text)//u-boot入口函数与spl相同,都是start.S中的_start
_start:
b reset
bl save_boot_params:
bx lr//直接返回
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance //8字节对齐*/
ldr r0,=0x00000000
bl board_init_f//board.c
//#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")//r8寄存器保存gd的地址
/* Pointer is writable since we allocated a register for it */
//r8=gd=CONFIG_SYS_INIT_SP_ADDR(位于sram尾部128字节),并且8字节对齐。
gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
memset((void *)gd, 0, sizeof(gd_t));//说明uboot阶段的gd和spl没有关系
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0)//遍历执行init_sequence数组中的函数,在这些函数中给gd的成员赋值
{
env_init, /* initialize environment */
}
}
/*
gd->mon_len = _bss_end_ofs;
整个u-boot镜像的大小,从_start到_bss_end(包括bss,不包括image_header)
每次修改代码后编译都不同
*/
gd->mon_len = _bss_end_ofs;//__bss_end__ - _start
//dram_init:gd->ram_size = PHYS_DRAM_1_SIZE;
//addr=CONFIG_SYS_SDRAM_BASE + PHYS_DRAM_1_SIZE=0xa0000000,sdram尾部
addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
/* reserve TLB table */
addr -= (4096 * 4);//addr=0xa0000000 - 16k = 0x9FFFC000
/* round down to next 64 kB limit */
addr &= ~(0x10000 - 1);//64k对齐,addr=0x9FFFC000 & ~ 0xFFFF=0x9FFF0000
gd->tlb_addr = addr;
#endif
addr &= ~(4096 - 1);// 4k对齐,addr=0x9FFF0000
/*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/
addr -= gd->mon_len;//addr=0x9FFF0000-0x4B6D70 = 0x9FB39290
addr &= ~(4096 - 1);// 4k对齐 addr = 0x9FB39000,uboot重定向地址addr
/*
* reserve memory for malloc() arena
*/
addr_sp = addr - TOTAL_MALLOC_LEN;//addr_sp=0x9FB39000 - 1048k = 0x9FA33000
/*
* (permanently) allocate a Board Info struct
* and a permanent copy of the "global" data
* 在sdram分配一个gd_t:id,用于拷贝gd(sram),最后在将id赋值给gd,之后的gd也指向0x9FA32F70
*/
addr_sp -= sizeof (bd_t);//addr_sp=0x9FA33000 - 24 = 0x9FA32FE8
bd = (bd_t *) addr_sp;//bd = 0x9FA32FE8
gd->bd = bd;
//sizeof (gd_t)=120 ?? 计算为116
addr_sp -= sizeof (gd_t);//addr_sp=0x9FA32FE8-120=0x9FA32F70
id = (gd_t *) addr_sp;//id=0x9FA32F70
/* leave 3 words for abort-stack */
addr_sp -= 12;//addr_sp=0x9FA32F70-12=0x9FA32F64
/* 8-byte alignment for ABI compliance */
addr_sp &= ~0x07;//add_sp=0x9FA32F60
gd->bd->bi_baudrate = gd->baudrate;//init_baudrate
/* Ram ist board specific, so move it to board code ... */
dram_init_banksize();
display_dram_config(); /* and display it */
gd->relocaddr = addr;//addr=0x9FB39000,uboot重定向地址addr
gd->start_addr_sp = addr_sp;//addr_sp=0x9FA32F60
gd->reloc_off = addr - _TEXT_BASE;//gd->reloc_off=0x9FB39000-CONFIG_SYS_TEXT_BASE=0x9FB39000-0x80800000=1F339000
memcpy(id, (void *)gd, sizeof(gd_t));//将gd(sram:CONFIG_SYS_INIT_SP_ADDR)内容付给id(sdram:0x9FA32F70)
relocate_code(addr_sp, id, addr);//addr_sp=0x9FA32F60;id=0x9FA32F70;addr=0x9FB39000
relocate_code://start.S
relocate_code:
mov r4, r0 /* save addr_sp */ //栈地址=0x9FA32F60
mov r5, r1 /* save addr of gd */ //id地址=0x9FA32F70
mov r6, r2 /* save addr of destination */ //重定位地址=0x9FB39000
/* Set up the stack */
stack_setup:
mov sp, r4
/*
adr伪指令相对于pc(运行时确定)。adr的反汇编就是基于PC的add sub指令
位置无关,用于获得_start的真正运行地址(而不是链接地址)
*/
adr r0, _start //r0 = 0x80800000
cmp r0, r6 // r0!=r6 需要重定向
/**** 不执行 ****/
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
/**** 不执行 ****/
/************ relocation ***********/
mov r1, r6 /* r1 <- scratch for copy_loop*/ //r1=0x9FB39000 重定向地址
ldr r3, _image_copy_end_ofs //_image_copy_end_ofs=__image_copy_end(u-boot.lds) - _start;表示需要copy的uboot镜像大小=0x64854(反汇编)
add r2, r0, r3 /* r2 <- source end address */ //r2=0x80800000+0x64854=0x80864854
copy_loop: //将uboot(从_start到___image_copy_end)从地址r0到地址r2 copy到 地址r1
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
/*
ldr pc, _undefined_instruction//位置无关,_undefined_instruction基于PC计算
_undefined_instruction: .word undefined_instruction//位置相关,undefined_instruction编译期间确定
Disassembly of section .text:
80800020 <_undefined_instruction>:
80800020: 808001a0 .word 0x808001a0
808001a0 <undefined_instruction>:
808001a0: e51fd154 ldr sp, [pc, #-340] ; 80800054 <IRQ_STACK_START_IN>
Disassembly of section .rel.dyn
808648dc: 80800020 addhi r0, r0, r0, lsr #32
修复代码重定向之后某些位置相关的代码不能执行问题。
uboot 在ld时,指定 -pie,生成的uboot会包含_rel_dyn段,
_rel_dyn段(808648dc)的作用就是保存“保存函数(text)、常量(rodata)绝对地址(808001a0:undefined_instruction)”的地址(80800020)
下面的代码就是遍历重定位的uboot的_rel_dyn段(还有dynsym段),
将_rel_dyn段(808648dc)中的每一个地址(80800020)所指向的地址(808001a0)加上relocation offset
80800020: 808001a0 .word 0x808001a0
变为
80800020: 808001a0+offset .word 0x808001a0
*/
#ifndef CONFIG_SPL_BUILD//uboot
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */ //r0=0x80800000
sub r9, r6, r0 /* r9 <- relocation offset */ //r9=0x9FB39000 - 0x80800000=1F339000
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */ //r10=0x6d104(反汇编)
add r10, r10, r0 /* r10 <- sym table in FLASH */ //r10=0x8086D104,_dynsym_start在sdram中的真实地址
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */ //r2=0x64854(反汇编)
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */ //r2=0x80864854,_rel_dyn_start在sdram中的真实地址
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ //r3=0x6d104(反汇编)
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ //r3=0x8086D104,_rel_dyn_end在sdram中的真实地址=_dynsym_start(u-boot.lds)
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
b clear_bss
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
_dynsym_start_ofs:
.word __dynsym_start - _start
#endif /* #ifndef CONFIG_SPL_BUILD */
clear_bss:
ldr r0, _bss_start_ofs//r0=0x64854
ldr r1, _bss_end_ofs//r1=0x4b6d70
mov r4, r6 /* reloc addr */ //r4=0x9FB39000 (重定向地址)
add r0, r0, r4 //r0=9FB9D854 (重定向后的bbs_start)
add r1, r1, r4 //r1=9FFEFD70 (重定向后的bbs_end)
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
jump_2_ram:
ldr r0, _board_init_r_ofs//r0=0x01a04(反汇编)
adr r1, _start //r1=0x80800000(adr基于pc的位置无关码,如果pc=当前链接地址,那么_start=_TEXT_BASE)
add lr, r0, r1 //lr=0x01a04 + 0x80800000 = 80801A04
add lr, lr, r9 //(r9 保存着 relocation offset;spl中 r9 = 0;uboot中 r9=1F339000)
//lr=80801A04+1F339000=1F33AA04(重定向后board_init_r的地址)
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */ //r0 = id地址 =0x9FA32F70
mov r1, r6 /* dest_addr */ //r6=重定位地址=0x9FB39000
/* jump to it ... */
mov pc, lr //跳转到1F33AA04(重定向后board_init_r的地址) 绝对跳转
board_init_r//board.c
{
gd = id;//r8=gd=id=0x9FA32F70
bd = gd->bd;//bd=gd->bd=0x9FA32FE8
board_init();//evm.c
{
gpmc_init();
board_evm_init();
{
gd->bd->bi_arch_number = MACH_TYPE_TIAM335EVM;//3589
/* address of boot parameters */
gd->bd->bi_boot_params = PHYS_DRAM_1 + 0x100;//0x80000100
}
}
nand_init();//nand.c
{
nand_init_chip
{
int board_nand_init(struct nand_chip *nand);//初始化nand_chip
{
ti81xx_nand_switch_ecc(NAND_ECC_HW, 2);
{
__ti81xx_nand_switch_ecc
{
nand->options |= NAND_OWN_BUFFERS;
ti81xx_hwecc_init_bch(nand, NAND_ECC_READ);
}
nand_scan_tail(mtd);
//初始化阶段,在这里调用的nand_scan_tail本质上没有作用,直接返回(因为在ti81xx_hwecc_init_bch设置了NAND_OWN_BUFFERS)
nand->options &= ~NAND_OWN_BUFFERS;
}
}
nand_scan
{
nand_scan_ident
{
nand_set_defaults
chip->cmdfunc = nand_command;//这时还是小页的nand_command
nand_get_flash_type
{
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);//READID
*maf_id = chip->read_byte(mtd);//1st MID
*dev_id = chip->read_byte(mtd);//2nd PID
nand_flash_detect_onfi//不支持onfi,直接返回0;
{
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);//READID,ONFI
read_byte //4个周期 O、N、F、I
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));//读nand_onfi_params结构体
}
nand_flash_detect_non_onfi//readid 3rd/4th个周期
chip->erase_cmd = single_erase_cmd;
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;//改为大页的nand_command_lp
}
}
nand_scan_tail
}
}
}
/* initialize environment */
env_relocate();//初始化环境变量
...
...
main_loop();
{
#if//超时,启动内核
s = getenv ("bootcmd");
run_command (s, 0);
#else//没有超时,进入命令行模式
run_command("menu", 0);
for (;;) {//uboot命令行模式的死循环
len = readline (CONFIG_SYS_PROMPT);//读命令行字符串到console_buffer
{
return readline_into_buffer(prompt, console_buffer);
}
flag = 0;
if (len > 0)//命令行敲入命令
{
strcpy (lastcommand, console_buffer);
if(strcmp(get_cmd,"00")==0 ... )如果是自定义的菜单命令
{
run_menu_command(get_cmd);
run_command(load_cmd, 0);
}
}else if (len == 0)//直接回车,重复上个命令
{
flag |= CMD_FLAG_REPEAT;
}
/*
* returns:
* 1 - command executed, repeatable
* 0 - command executed but not repeatable, interrupted commands are
* always considered not repeatable
* -1 - not executed (unrecognized, bootd recursion or too many args)
* (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
* considered unrecognized)
*/
rc = run_command (lastcommand, flag);
{
if (!cmd || !*cmd) {
return -1; /* empty command */
}
process_macros (token, finaltoken);//处理宏定义
{
envval = getenv (envname);
}
/* Extract arguments */
argc = parse_line (finaltoken, argv);//解析参数 argv argc
/* Look up command in command table */
cmdtp = find_cmd(argv[0]);//argv[0]=命令的名字
{
int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
}
(cmdtp->cmd) (cmdtp, flag, argc, argv);//执行函数
repeatable &= cmdtp->repeatable;
//run_command执行没有错误rc=0,返回repeatable
//run_command执行有错误rc=-1,返回rc=-1
return rc ? rc : repeatable;
}
/*
命令执行失败或者命令成功执行但不能重复执行,清除lastcommand;
下次循环如果直接回车,执行到run_command时直接返回-1;
*/
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
} else (rc == 1)
/*
命令执行成功并且可重复执行,
lastcommand保持为这次成功执行的可重复的命令;
下次循环如果直接回车,执行到run_command时和上次循环相同,实现了命令的重复执行;
*/
}
}
}
[UBOOT] AM335x 启动流程(u-boot-2011.09)
最新推荐文章于 2023-01-09 14:47:47 发布