本文共 17813 字,大约阅读时间需要 59 分钟。
url : git@github.com:lisider/u-boot.gitbranch : ok6410acommit id : e63a4077ad3aea53107495b0b68b95e720fe6033config : ok6410a_mini_defconfig// 涉及的 .S .s .c 文件 有 223个
reset arch/arm/cpu/arm1176/start.S 39 lowlevel_init(108) board/samsung/ok6410a/lowlevel_init.S 72 _main(110) arch/arm/lib/crt0.S 91 board_init_f(117) common/board_f.c 954 initcall_run_list(init_sequence_f)(959) include/initcall.h 21 init_sequence_f common/board_f.c 818 board_init_r(177) common/board_r.c 901 initcall_run_list(init_sequence_r)(927) include/initcall.h 21 init_sequence_r common/board_f.c 695 run_main_loop(898) common/board_r.c 678 main_loop(685) common/main.c 39
// 入口 为 arch/arm/lib/vectors.S 中的 _start 标号处的 b resetreset lowlevel_init 时钟 串口 ddr _main // 从代码运行起始位置0x5FB00000 往下 找 gd 和栈 的位置 bl board_init_f_alloc_reserve // 设置栈 mov sp, r0 // 设置gd mov r9, r0 // 初始化gd bl board_init_f_init_reserve bl board_init_f 查找 设备树的地址 准备 early malloc 驱动模型的前期准备 定时器初始化,为delay做准备 env 初始化,为查找环境变量做准备 串口波特率环境变量的查找和串口波特率的设置,为printf做准备 从 ddr 顶端 0x5FFF FFFF 往下 找 空间 1. mmu 2. u-boot 3. malloc 4. new_gd 5. fdt 6. irq 栈 7. 栈 搬移 gd 搬移设备树(fdt) // 搬移 u-boot 并 fixloop b relocate_code // 搬移向量表 到 0x0000 0000 bl relocate_vectors CLEAR_BSS // 清.bss 段 , 这是u-boot阶段第一次清, relocate 之前没有清过 ldr pc,=board_init_r // 开 icache 和 dcache initr_caches // 为 full malloc 做准备 initr_malloc // 驱动模型的后期准备 initr_dm // 初始化 board ID board_init // 串口及控制台的初始化 stdio_init_tables serial_initialize stdio_add_devices console_init_r // 其他设备的初始化 initr_mmc initr_ethaddr initr_net // env 的后初始化 initr_env // 跳转表??? // the jump table contains pointers to exported functions. // A pointer to the jump table is passed to standalone applications. // 也就是 说 导出 让 standalone 应用用的 // u-boot 命令行 可以 加载 bin 文件,并执行 这些bin文件就是 standalone applications // 查看 doc/README.standalone initr_jumptable // 中断相关的初始化(开中断,相关变量) interrupt_init main_loop bootcmd以及cmdline
// common/init/board_init.c// register volatile gd_t *gd asm ("r9");// arch/arm/include/asm/global_data.h:112:#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r9")reset // 运行在 5FB0 0000// sdram : 0x5000_0000 0x5FFF_FFFF lowlevel_init spl_config_uart_baudrate ulong val = spl_uart_getclk(is_mpll) / 115200; _UBRDIV = val / 16 - 1; _UDIVSLOT = udivslot[val % 16]; mem_ctrl_asm_init // ddr初始化 _main board_init_f_alloc_reserve // 算出gd的地址为 0x5f9fff20 // 过程与数据和spl 完全一样 申请 struct global_data 个字节 用来存储 gd_t *gd 指向的 gd_t 结构体 // include/asm-generic/global_data.h 中 有 gd_t 的 定义 board_init_f_init_reserve // 根据 gd的地址 0x5f9fff20 算出结构体 // 过程与数据和spl 完全一样 初始化 gd_t *gd 指向的 gd_t 结构体 空间 为 0 初始化 gd_t *gd 指向的 gd_t 结构体 的 成员 malloc_base = 5F9F FFF0 // u-boot过程和 spl 过程用到的 gd 指针是同一个位置 // 但是 内容不同,因为在 初始化的时候,已经将 gd指针指向的位置全部 memset 0 了 // spl 加载 u-boot 的过程中, 就是 A加载B // A 加载 B 可以 通过 寄存器 来传值 // 但是 spl 加载 u-boot 的过程中可以说没有传递任何值 // 虽然 都用r9 保存了 gd的指针值,但是 r9 是算出来的,不是 spl 传过来的. /* 下面的这几行有两个目标 1. 设置sp 2. 存储gd指针变量并clear gd指针变量指向的空间,并设置 gd->malloc_base = 0x5f9f ff20; ldr r0, =((0x5FB00000 - 0x0C)) => r0 : 5FAF FFF4 bic r0, r0, #7 => r0 : 5FAF FFF0 mov sp, r0 => sp : 5FAF FFF0 bl board_init_f_alloc_reserve => r0 : 5f9f ff20 (5FAF FFF0 - 0x10 0000 - 0xD0) mov sp, r0 => sp : 5f9f ff20 ***** 设置了 栈指针 mov r9, r0 => r9 : 5f9f ff20 ***** 存储了 gd指针变量的值 bl board_init_f_init_reserve => 初始化 (5f9fff20 - 5f9fff20+0xD0) 的空间 */ /* // .code .rodata .data .bss .stack .heap 此时的内存分布 5FFF FFFF---------------------5FFF FFFF 5120KB(0x500000)大小,被512KB u-boot.bin占据 // 不管u-boot.bin有没有512KB,都会从mmc上拷贝512KB过来 // U-boot.bin实际大小 248K 内存中的u-boot.bin 中存在 .bss段,起始为5FB3 61F0,结束为5FB3 BAD4 内存中的u-boot.bin 也存在 .code .rodata .data 5FB0 0000--------------------- 16B(0x10)大小,空洞 5FAF FFF0--------------------- 1024KB(0x100000)大小,用于sys_malloc (.heap) 5F9F FFF0--------------------- 208B(0xD0)大小,用于gd (很特殊的一个全局变量) 5F9F FF20--------------------- 255999KB(约250MB)大小,用于栈 (.stack) 5000 0000---------------------5000 0000 */ board_init_f // 被调用的时候传递的参数为 0 ,用来设置flags. gd->flags = 0; gd->have_console = 0; setup_mon_len // 第一次使用栈,(sp) // 重要参考点1 gd->mon_len = (ulong)&__bss_end - (ulong)_start; // = 0x3bc4c // 为 reserve_uboot 做准备 fdtdec_setup // 为设备树的解析做准备 gd->fdt_blob = board_fdt_blob_setup(); return (ulong *)&_end; gd->fdt_blob = map_sysmem (env_get_ulong("fdtcontroladdr", 16, (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); // 解码fdtcontroladdr环境变量的值,16进制,如果为空则为gd->fdt_blob fdtdec_prepare_fdt // 检查gd->fdt_blob为空,则报错 fdtdec_board_setup // null initf_malloc // 为 early malloc 做准备 // 用于 early malloc // 此前 gd->malloc_base 已经被初始化为 5F9F FFF0 // base address of early malloc gd->malloc_limit = 0x100000; // limit address of early malloc gd->malloc_ptr = 0; // current address of early malloc log_init // null initf_bootstage bootstage_init(1) // null bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f") show_boot_progress(id); //null // TODO, 另一个路径大概率是 printf setup_spl_handoff // null initf_console_record // null arch_cpu_init // null mach_cpu_init // null initf_dm // dm 架构(driver-model),比较复杂,后续有空更新专题 // 为 驱动和设备的注册做准备 bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f"); // null dm_init_and_scan(1) dm_init(0) INIT_LIST_HEAD(&(((gd_t *)gd)->uclass_root)); list->next = list; list->prev = list; device_bind_by_name(0,0,&root_info, &(((gd_t *)gd)->dm_root))); lists_driver_lookup_name(info->name); device_bind_common(parent, drv, info->name, (void *)info->platdata, 0, ofnode_null(), platdata_size, devp); (((gd_t *)gd)->dm_root)->node = offset_to_ofnode(0) device_probe((((gd_t *)gd)->dm_root)) dm_scan_platdata(1) lists_bind_drivers((((gd_t *)gd)->dm_root), 1) dm_extended_scan_fdt(gd->fdt_blob, 1) dm_scan_fdt(gd->fdt_blob,1) dm_scan_fdt_node(gd->dm_root, blob, 0, 1); for_each_node dm_scan_fdt_ofnode_path(blob, nodes[i], 1); dm_scan_other(1) // null bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F); // null arch_cpu_init_dm // null timer_init // 为 delay 做准备 // 设置 s3c6410的 硬件timer gd->arch.timer_rate_hz = pre_freq/1; gd->arch.timer_rate_hz *= 1000; gd->arch.lastinc = timers->TCNTB4 = gd->arch.timer_rate_hz; gd->arch.timer_reset_value = 0; env_init env_driver_lookup env_get_location return env_locations[prio] ; // ENVL_MMC _env_driver_lookup n_ents = xxx in section .u_boot_list_2_env_driver ,根据 ENVL_MMC 找到对应的 驱动对应的结构体 struct env_driver drv->init // drv 为找到的结构体 struct env_driver _u_boot_list_2_env_driver_2_mmc 中没有 init 成员 env_set_inited(drv->location) gd->env_has_init |= (1UL << (location)); gd->env_addr = (ulong)&default_environment[0]; // 待研究 gd->env_valid = ENV_VALID; init_baud_rate gd->baudrate = env_get_ulong("baudrate", 10, 115200); const char *str = env_get(name); env_get_f env_get_char env_match return str ? simple_strtoul(str,0,10) : default_val; serial_init serial_find_console_or_panic serial_check_stdout str = fdtdec_get_chosen_prop(blob, "stdout-path"); node = fdt_path_offset_namelen(blob, str, namelen); lists_bind_fdt device_probe(&dev) gd->cur_serial_dev = dev; gd->flags |= GD_FLG_SERIAL_READY; serial_setbrg gd->cur_serial_dev->driver->ops->setbrg(gd->cur_serial_dev, gd->baudrate)// s3c_serial_setbrg s3c_serial_setbrg_internal((struct s3c64xx_uart * )CONFIG_DEBUG_UART_BASE, 0 /*CFG_SERIAL_ID*/,CONFIG_BAUDRATE); u32 uclk = get_uart_clk(id) s3c64xx_serial_baud(uart, uclk, baudrate); uart->UBRDIV = uclk / baudrate / 16 - 1; uart->UDIVSLOT = udivslot[val]; barrier(); // 内存顺序模型相关 console_init_f gd->have_console = 1; console_update_silent // null print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL); // null TODO // PRE_CONSOLE_BUFFER display_options // printf 可以使用 // 重要参考点2 display_options_get_banner(true, buf, sizeof(buf)); display_options_get_banner_priv snprintf printf("%s", buf); display_text_info bss_start = (ulong)&__bss_start; bss_end = (ulong)&__bss_end; text_base = 0x5FB00000; checkcpu // null print_cpuinfo printf("** Updated for OK6410A Board **\r\n"); show_board_info model = fdt_getprop(gd->fdt_blob, 0, "model", ((void *)0)); printf("Model: %s\n", model); // 实际打印 为 Model: Samsung SMDK6410 based on S3C6410 // 打印的字符串为 arch/arm/dts/s3c64xx-ok6410a.dts 中的 model 节点的属性 checkboard printf("Board: OK6410A\n"); announce_dram_init puts("DRAM: "); dram_init gd->ram_size += SDRAM_BANK_SIZE; // = 0x1000 0000 setup_dest_addr gd->ram_base = 0x50000000; gd->ram_top = gd->ram_base + get_effective_memsize(); // get_effective_memsize: gd->ram_size // = 0x6000 0000 gd->ram_top = board_get_usable_ram_top(gd->mon_len); // = gd->ram_top // = 0x6000 0000 gd->relocaddr = gd->ram_top; // = 0x6000 0000 reserve_round_4k gd->relocaddr &= ~(4096 - 1); // hex 后三位与0 // 0x6000 0000 arch_reserve_mmu arm_reserve_mmu gd->arch.tlb_size = (4096 * 4); // 0x4000 16K gd->relocaddr -= gd->arch.tlb_size; // 0x5FFF C000 gd->relocaddr &= ~(0x10000 - 1); // hex 后四位 与0 // 0x5fff 0000 gd->arch.tlb_addr = gd->relocaddr; // 0x5fff 0000 reserve_video // null reserve_trace // null reserve_uboot gd->relocaddr -= gd->mon_len; // = 5FFB 33B4 gd->relocaddr &= ~(4096 - 1); // hex 后三位与0 // 5FFB 3000 gd->start_addr_sp = gd->relocaddr; // 5FFB 3000 reserve_malloc gd->start_addr_sp = reserve_stack_aligned((1024*1024)); // 0x5feb3000 reserve_board // gd->bd 不为null , 什么都不做 setup_machine gd->bd->bi_arch_number = 1626; reserve_global_data gd->start_addr_sp = reserve_stack_aligned(sizeof(gd_t)); // 0x5feb2f30 gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t)); // 0x5feb2f30 reserve_fdt gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32); // 0xe80 gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size); // 0x5feb20b0 gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size); // 0x5feb20b0 reserve_bootstage // null reserve_bloblist // null reserve_arch // null reserve_stacks gd->start_addr_sp = reserve_stack_aligned(16); // 这16个字节应该用于 irq的栈 // 0x5feb20a0 arch_reserve_stacks gd->irq_sp = gd->start_addr_sp; // 0x5feb20a0 dram_init_banksize // 只有一个bank for_each_bank gd->bd->bi_dram[i].start = addr; // 0x50000000 gd->bd->bi_dram[i].size = (0x10000000); // 0x10000000 show_dram_config for_each_bank // 只有一个bank size += gd->bd->bi_dram[i].size; // 0x10000000 print_size(size, ""); // 实际打印 256 MiB board_add_ram_info(0); null putc('\n'); setup_bdinfo // null display_new_sp // null reloc_fdt gd->fdt_blob = gd->new_fdt; reloc_bootstage // null reloc_bloblist // null setup_reloc gd->reloc_off = gd->relocaddr - 0x5FB00000; // 004b4000 // 该值是 u-boot的code段 搬移目标地址 与 当前地址的差值 memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); clear_bss // null // 运行到此时,sp还没更改 // u-boot 还没搬运 // 此时,搬运了 gd和设备树 // 此时 r9里面存放的还是gd ldr r0, [r9, #72] // 72 是 start_addr_sp bic r0, r0, #7 // 与上0b1000 , 第三位清0 mov sp, r0 // 更改 sp ldr r9, [r9, #80] // 此时 r9 中存放的 是 new_gd adr lr, here // 存放 lr, 为 b(跳转) 做准备 ldr r0, [r9, #76] // 将 new_gd 中的 reloc_off 存放到r0,用作新的lr的计算 add lr, lr, r0 // 更改lr ,让 relocate_code 返回时,跳转到 已经 搬移好的代码 中去, ldr r0, [r9, #56] // 将 new_gd 中的 relocaddr存放到r0,作为第一个参数 b relocate_code // 搬移 u-boot的 code 段 arch/arm/lib/relocate.S +80 搬移,修复绝对地址??? // 此时已经在 搬移过后的代码 中 bl relocate_vectors // TODO // arch/arm/lib/relocate.S +28 ldr r0, [r9, #56] // 将 new_gd 中的 relocaddr存放到r0 mcr p15, 0, r0, c12, c0, 0 bl c_runtime_cpu_setup // null CLEAR_BSS // 问题,搬移过后,__bss_start的值有变化吗? // 宏汇编 // ldr r0, =__bss_start // ldr r3, =__bss_end // mov r1, #0x00000000 // subs r2, r3, r0 // bl memset bl coloured_LED_init // null bl red_led_on // null /* // .code .rodata .data .bss .stack .heap 此时的内存分布 5FFF FFFF---------------------5FFF FFFF mmu (0x4000B,16KB) 5FFF C000--------------------- 空洞 (0xC000B,48KB) 5FFF 0000--------------------- // 5FFF 0000 存放在 gd->arch.tlb_addr 中 u-boot.bin (包括.code .data .ro-data .bss) (0x3D000B,244KB) 5FFB 3000--------------------- // 5FFB 3000 存放在 new_gd->relocaddr 中 malloc (0x100000B,1024KB) 5FEB 3000--------------------- new_gd (0xD0B,208B) 5FEB 2F30--------------------- // 5FEB 2F30 存放在 r9中 fdt (0xE80B,3KB) 5FEB 20B0--------------------- 空洞 (0x10,16B) 5FEB 20A0--------------------- // 5FEB 20A0 存放在 start_addr_sp 中 栈 (254.695465MB) 5000 0000--------------------- */ mov r0, r9 // 将 new_gd 的地址 存放到r0,作为第一个参数 ldr r1, [r9, #56] // 将 new_gd 中的 relocaddr 存放到r1,作为第二个参数 ldr pc,=board_init_r gd->flags &= ~GD_FLG_LOG_READY; // 虽然这里用的是gd,但是和用new_gd 效果一样 // 因为 gd指针的值 是寄存器(r9中的值 // new_gd指针的值 也是寄存器(r9)中的值 initr_trace // null initr_reloc gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT; // 表示 code was relocated to RAM // 表示 full malloc() is ready initr_caches enable_caches icache_enable cache_enable((1 << 12)); reg = get_cr(); set_cr(reg | cache_bit); dcache_enable cache_enable((1 << 2)); if !mmu_enabled() mmu_setup(); reg = get_cr(); set_cr(reg | cache_bit); // 此时mmu 没有enable initr_reloc_global_data monitor_flash_len = _end - __image_copy_start // 计算出 monitor_flash_len // 之后用来填充 gd->bd->bi_flashoffset // reserved area for startup monitor // 不知道用来干什么的 // struct bd_info 定义在 include/asm-generic/u-boot.h initr_barrier // null initr_malloc malloc_start = gd->relocaddr - (1024*1024); // = 5FEB 3000 // malloc 的区域 在 5FEB 3000 - 5FFB 3000 , 有 1024KB mem_malloc_init((ulong)map_sysmem(malloc_start, (1024*1024)), (1024*1024)); mem_malloc_start = start; // 5FEB 3000 mem_malloc_end = start + size; // 5FFB 3000 mem_malloc_brk = start; memset((void *)mem_malloc_start, 0x0, size); malloc_bin_reloc(); // null log_init // null initr_bootstage bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r"); initr_console_record // null initr_of_live // null initr_dm gd->dm_root_f = gd->dm_root; gd->dm_root = 0; dm_init_and_scan(0); bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_R); board_init cs8900_pre_init // 这里不是cs8900,而是dm9000a // SROM 控制器的初始化 (*(vu_long *)(0x70000000 +0x0)) &= ~(0xf << 4); (*(vu_long *)(0x70000000 +0x0)) |= (1 << 7) | (1 << 6) | (1 << 4); (*(vu_long *)(0x70000000 +0x8)) = (((0x0) << 28) + ((0x4) << 24) + ((0xE) << 16) + ((0x1) << 12) + ((0x4) << 8) + ((0x6) << 4) + (0x0)); // 0x7000_0000 0x700F_FFFF SROM SFR gd->bd->bi_arch_number = 1626; // CONFIG_MACH_TYPE // unique id for this board gd->bd->bi_boot_params = (0x50000000 +0x100); // where this board expects params initr_binman // null initr_dm_devices // null stdio_init_tables INIT_LIST_HEAD(&devs.list); serial_initialize serial_init initr_announce // null power_init_board // null initr_mmc puts("MMC: "); mmc_initialize(gd->bd); initr_env env_set_default(0,0) image_load_addr = env_get_ulong("loadaddr", 16, image_load_addr); initr_secondary_cpu cpu_secondary_init_r // null stdio_add_devices drv_system_init serial_stdio_init initr_jumptable jumptable_init gd->jt = malloc(sizeof(struct jt_funcs)); gd->jt->get_version = get_version; gd->jt->getc = getchar; gd->jt->tstc = tstc; gd->jt->putc = putc; gd->jt->puts = puts; gd->jt->printf = printf; gd->jt->install_hdlr = dummy; gd->jt->free_hdlr = dummy; gd->jt->malloc = malloc; gd->jt->free = free; gd->jt->udelay = udelay; gd->jt->get_timer = get_timer; gd->jt->vprintf = vprintf; gd->jt->do_reset = do_reset; gd->jt->env_get = env_get; gd->jt->env_set = env_set; gd->jt->simple_strtoul = simple_strtoul; gd->jt->strict_strtoul = strict_strtoul; gd->jt->simple_strtol = simple_strtol; gd->jt->strcmp = strcmp; gd->jt->i2c_write = dummy; gd->jt->i2c_read = dummy; gd->jt->spi_setup_slave = dummy; gd->jt->spi_free_slave = dummy; gd->jt->spi_claim_bus = dummy; gd->jt->spi_release_bus = dummy; gd->jt->spi_xfer = dummy; gd->jt->ustrtoul = ustrtoul; gd->jt->ustrtoull = ustrtoull; gd->jt->strcpy = strcpy; gd->jt->mdelay = mdelay; gd->jt->memset = memset; console_init_r gd->flags |= GD_FLG_DEVINIT; print_pre_console_buffer(flushpoint); interrupt_init IRQ_STACK_START_IN = gd->irq_sp + 8; // gd->irq_sp 上面有16字节可用 // 现在IRQ_STACK_START_IN在 gd->irq_sp 上面8字节 // 且arm栈向下移动 // 所以irq栈应该只有8个字节可用 // 此举和 之前的 relocate_vectors有关 enable_interrupts // null initr_ethaddr eth_env_get_enetaddr("ethaddr", bd->bi_enetaddr); initr_net puts("Net: "); eth_initialize run_main_loop main_loop
转载地址:http://ibigi.baihongyu.com/