环境:
cpu:3288
system:7.1
uboot启动kernel代码流程:
1.根据.lds链接脚本文件,是从__start开始,里面定义了各个段
start.S----> //进行reset,disable interrupt 设置向量表进cp15 etc
bl _main
crts0.S---->
初始化c运行时环境,初始化sp,global data结构体
bl board_init_f
{
gd->mon_len = (ulong)&__bss_end - (ulong)_start;
gd->env_addr = (ulong)&default_environment[0]; //保存cmdline
gd->arch.chiptype //保存cpu信息
gd->ram_size //ddr大小
gd->relocaddr //128M
gd->bd->bi_dram[0].size //128M
gd->bd->bi_dram[0].start //0
serial_init //初始化串口,主要是写寄存器
display_options, //显示Uboot信息---U-Boot 2014.10-RK3288-06 (Sep 22 2023 - 00:33:05)
display_text_info //设置bss段的开始和结束地址,text从0x00开始
print_cpuinfo //输出cpu信号,并获取到pll的rate
show_board_info //如果 dts中由model输出队 --- model = "Rockchip RK3126 bnd-d708 board";
dram_init //初始化dram
setup_dest_addr //设置ram_top为ram_size relocaddr 0x8000000(128M)
reserve_mmu, //TLB table设置rel地址
reserve_lcd, //fb base rel addr
reserve_global_buffers, //rk bootbuf fastboot log buf
reserve_uboot //保留了mon_size的大小,留给重定位后的uboot,对齐后的地址也是开始stack地址
reserve_malloc,
reserve_board, //保留board info结构体
reserve_global_data, //创建新的gd结构体,并将原来的复制过来
reserve_stacks,
setup_dram_config,
show_dram_config,
display_new_sp,
setup_reloc, //计算出reloc_off
}
/****此时执行完,reloc_addr=reloc_off(因为链接sys_text=0),此时的地址在uboot地址,sp在最后***/
开始uboot重定位:
回到crt0.S
ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
/***通过上述操作,会找到global data新的结构体位置之前有分析过,他在board info地址下面****/
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
adr lr, here //lr通常作为返回寄存器,执行完relocate_code返回here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off 将上述分配的uboot地址空间和链接地址结算出的偏移量复制给r0,[r9, #GD_RELOC_OFF]的含义就是gd结构体,GD_RELOC_OFF的偏移量,也就是reloc_off在gd中的位置*/
add lr, lr, r0 //计算出重定位之后here的地址
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr 调用relocate_code传递的参数*/
b relocate_code
#endif
/******************/
here:
....
ldr pc, =board_init_r //返回之后就是调用此函数正式进入c代码初始化
relocate.S------->
00000000 T __image_copy_start
00000000 T _start
//可以看到,其实这个也就是Uboot代码的最开始的位值
ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */
//r0就是上面传下来的参数,新uboot地址.r4就是新老uboot开头的地址偏移
subs r4, r0, r1 /* r4 <- relocation offset */
//如果地址相同就跳过,显然是不相同的
beq relocate_done /* skip relocation */
//r2保存__image_copy_end地址
ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */
copy_loop:
//开始进行copy,老地址到新地址
ldmia r1!, {r10-r11} /* copy from source address [r1] */
(1) stmia r0!, {r10-r11} /* copy to target address [r0] */
cmp r1, r2 /* until source end address [r2] */
blo copy_loop
/*
* fix .rel.dyn relocations
*/
//在__image_copy_end段下面的段
ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
fixloop:
//经过上述(1)操作,r0也到了新uboot的rel.syn段,开始复制rel.syn段
ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
and r1, r1, #0xff
cmp r1, #23 /* relative fixup? */
bne fixnext
/* relative fix: increase location by offset */
add r0, r0, r4
ldr r1, [r0]
add r1, r1, r4
str r1, [r0]
fixnext:
cmp r2, r3
blo fixloop
relocate_done:
board/rockchip/rk32xx/rk32xx.c
board_late_init------> //进行一些初始化
{
board_late_init--->
board_init_adjust_env(); //检查一些env,比如bootdelay
load_disk_partitions(); //解析分区表
rkimage_prepare_fdt(); //从boot,resource recovery里面获取fdt
key_init(); //初始化adc按键 RockusbKeyadc :0~30 FastbootKey adc:160~180 RecoveryKey adc:0~30
// power key从dts中获取
fixed_regulator_init(); //在dts中找到regulator-fixed的device,然后使能
pmic_init(0); //初始化pmic,传入参数为i2c bus
pwm_regulator_init(); //pwm初始化
}
load_disk_partitions-----> //rk解析parameter
board_fbt_preboot----->
board_fbt_key_pressed----->
board_fbt_low_power_check----->
is_power_extreme_low----->
get_power_bat_status----->
rkloader_run_misc_cmd------->
main_loop---->
1.获取"bootrk" cmd,并启动 autoboot_command("bootrk");=>run_command_list(s, -1, 0);
2.cmd_bootrk.c ==>
{
U_BOOT_CMD(
bootrk, 2, 1, do_bootrk, //执行do_bootrk函数
"boot rockchip android bootimg",
}
do_bootrk(NULL, 0, ARRAY_SIZE(boot_cmd), boot_cmd);
rk_load_image_from_storage/ram()------> //这里会去保存加载kernel内存地址
rkimage_load_image(hdr, ptn, get_disk_partition(KERNEL_NAME)----->
rkimg_load_image(kernel_ptn->start, (unsigned char *)(unsigned long)hdr->kernel_addr, &image_size)------->
rkloader_CopyFlash2Memory((uint32)(unsigned long) load_addr + RK_BLK_SIZE - head_offset, offset + 1, blocks - 1)----->//kernel加载到内存中
do_bootm_linux(0, 0, NULL, &images);------> //Image中保存这logo,,kernel,ramdisk等信息的加载地址
boot_jump_linux----->
kernel_entry(r0, 0, r2); //跳到kernel
rk是通过加载parameter文件来进行信息获取。在load_disk_partitions步骤中,代码会去读取解析parameter文件,经过些处理将所有信息存储在结构体中。
rk的parameter都保存在 PBootInfo 指针里面 cmd_mtd就是保存分区大小信息的字符串
typedef struct tagBootInfo {
uint32 magic_code;
uint16 machine_type;
uint16 boot_index; /* 0 - normal boot, 1 - recovery */
uint32 atag_addr;
uint32 misc_offset;
uint32 kernel_load_addr;
uint32 boot_offset; /* ÒÔSectorΪµ¥Î» */
uint32 recovery_offset; /* ÒÔSectorΪµ¥Î» */
uint32 ramdisk_offset; /* ÒÔSectorΪµ¥Î» */
uint32 ramdisk_size; /* ÒÔByteΪµ¥Î» */
uint32 ramdisk_load_addr;
uint32 is_kernel_in_boot;
uint32 check_mask; /* 00 - ²»Ð£Ñ飬 01 - check kernel, 10 - check ramdisk, 11 - both check */
char cmd_line[MAX_LINE_CHAR];
cmdline_mtd_partition cmd_mtd;
int index_misc;
int index_kernel;
int index_boot;
int index_recovery;
int index_system;
int index_backup;
int index_snapshot;
char fw_version[MAX_LINE_CHAR];
char fdt_name[MAX_LINE_CHAR];
} BootInfo, *PBootInfo;