本文主要是介绍OK6410A 开发板 (三) 12 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
url : git@github.com:lisider/u-boot.git
branch : ok6410a
commit id : e63a4077ad3aea53107495b0b68b95e720fe6033
config : ok6410a_mini_defconfig
// 涉及的 .S .s .c 文件 有 223个
reset arch/arm/cpu/arm1176/start.S 39lowlevel_init(108) board/samsung/ok6410a/lowlevel_init.S 72_main(110) arch/arm/lib/crt0.S 91board_init_f(117) common/board_f.c 954initcall_run_list(init_sequence_f)(959) include/initcall.h 21init_sequence_f common/board_f.c 818board_init_r(177) common/board_r.c 901initcall_run_list(init_sequence_r)(927) include/initcall.h 21init_sequence_r common/board_f.c 695run_main_loop(898) common/board_r.c 678main_loop(685) common/main.c 39
- 解析概要
// 入口 为 arch/arm/lib/vectors.S 中的 _start 标号处的 b reset
resetlowlevel_init时钟串口ddr_main// 从代码运行起始位置0x5FB00000 往下 找 gd 和栈 的位置bl board_init_f_alloc_reserve// 设置栈mov sp, r0// 设置gd mov r9, r0// 初始化gdbl board_init_f_init_reserve bl board_init_f 查找 设备树的地址准备 early malloc驱动模型的前期准备定时器初始化,为delay做准备env 初始化,为查找环境变量做准备串口波特率环境变量的查找和串口波特率的设置,为printf做准备从 ddr 顶端 0x5FFF FFFF 往下 找 空间1. mmu2. u-boot3. malloc4. new_gd5. fdt6. irq 栈7. 栈搬移 gd搬移设备树(fdt)// 搬移 u-boot 并 fixloopb relocate_code// 搬移向量表 到 0x0000 0000bl relocate_vectorsCLEAR_BSS// 清.bss 段 , 这是u-boot阶段第一次清, relocate 之前没有清过ldr pc,=board_init_r// 开 icache 和 dcacheinitr_caches// 为 full malloc 做准备initr_malloc// 驱动模型的后期准备initr_dm// 初始化 board IDboard_init// 串口及控制台的初始化stdio_init_tablesserial_initialize stdio_add_devicesconsole_init_r// 其他设备的初始化initr_mmcinitr_ethaddrinitr_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.standaloneinitr_jumptable// 中断相关的初始化(开中断,相关变量)interrupt_initmain_loopbootcmd以及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_FFFFlowlevel_initspl_config_uart_baudrateulong val = spl_uart_getclk(is_mpll) / 115200;_UBRDIV = val / 16 - 1;_UDIVSLOT = udivslot[val % 16];mem_ctrl_asm_init// ddr初始化_mainboard_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. 设置sp2. 存储gd指针变量并clear gd指针变量指向的空间,并设置 gd->malloc_base = 0x5f9f ff20;ldr r0, =((0x5FB00000 - 0x0C)) => r0 : 5FAF FFF4bic r0, r0, #7 => r0 : 5FAF FFF0mov sp, r0 => sp : 5FAF FFF0bl 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 FFFF5120KB(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 .data5FB0 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) // 重要参考点1gd->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_blobfdtdec_prepare_fdt // 检查gd->fdt_blob为空,则报错fdtdec_board_setup// nullinitf_malloc // 为 early malloc 做准备// 用于 early malloc// 此前 gd->malloc_base 已经被初始化为 5F9F FFF0 // base address of early mallocgd->malloc_limit = 0x100000; // limit address of early mallocgd->malloc_ptr = 0; // current address of early malloclog_init// nullinitf_bootstagebootstage_init(1)// nullbootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f")show_boot_progress(id);//null // TODO, 另一个路径大概率是 printfsetup_spl_handoff// nullinitf_console_record// nullarch_cpu_init// nullmach_cpu_init// nullinitf_dm // dm 架构(driver-model),比较复杂,后续有空更新专题 // 为 驱动和设备的注册做准备bootstage_start(BOOTSTAGE_ID_ACCUM_DM_F, "dm_f");// nulldm_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)// nullbootstage_accum(BOOTSTAGE_ID_ACCUM_DM_F);// nullarch_cpu_init_dm// nulltimer_init // 为 delay 做准备// 设置 s3c6410的 硬件timergd->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_initenv_driver_lookupenv_get_locationreturn env_locations[prio] ; // ENVL_MMC_env_driver_lookupn_ents = xxxin section .u_boot_list_2_env_driver ,根据 ENVL_MMC 找到对应的 驱动对应的结构体 struct env_driverdrv->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_rategd->baudrate = env_get_ulong("baudrate", 10, 115200);const char *str = env_get(name);env_get_fenv_get_charenv_matchreturn str ? simple_strtoul(str,0,10) : default_val;serial_initserial_find_console_or_panicserial_check_stdoutstr = fdtdec_get_chosen_prop(blob, "stdout-path");node = fdt_path_offset_namelen(blob, str, namelen);lists_bind_fdtdevice_probe(&dev)gd->cur_serial_dev = dev;gd->flags |= GD_FLG_SERIAL_READY;serial_setbrggd->cur_serial_dev->driver->ops->setbrg(gd->cur_serial_dev, gd->baudrate)// s3c_serial_setbrgs3c_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_fgd->have_console = 1;console_update_silent// nullprint_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);// null TODO// PRE_CONSOLE_BUFFERdisplay_options // printf 可以使用 // 重要参考点2display_options_get_banner(true, buf, sizeof(buf));display_options_get_banner_privsnprintfprintf("%s", buf);display_text_infobss_start = (ulong)&__bss_start;bss_end = (ulong)&__bss_end;text_base = 0x5FB00000;checkcpu// nullprint_cpuinfoprintf("** Updated for OK6410A Board **\r\n");show_board_infomodel = 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 节点的属性checkboardprintf("Board: OK6410A\n");announce_dram_initputs("DRAM: ");dram_initgd->ram_size += SDRAM_BANK_SIZE; // = 0x1000 0000setup_dest_addrgd->ram_base = 0x50000000;gd->ram_top = gd->ram_base + get_effective_memsize();// get_effective_memsize: gd->ram_size// = 0x6000 0000gd->ram_top = board_get_usable_ram_top(gd->mon_len);// = gd->ram_top // = 0x6000 0000gd->relocaddr = gd->ram_top;// = 0x6000 0000reserve_round_4kgd->relocaddr &= ~(4096 - 1);// hex 后三位与0// 0x6000 0000arch_reserve_mmuarm_reserve_mmugd->arch.tlb_size = (4096 * 4);// 0x4000 16Kgd->relocaddr -= gd->arch.tlb_size;// 0x5FFF C000gd->relocaddr &= ~(0x10000 - 1);// hex 后四位 与0// 0x5fff 0000gd->arch.tlb_addr = gd->relocaddr;// 0x5fff 0000reserve_video// nullreserve_trace// nullreserve_ubootgd->relocaddr -= gd->mon_len;// = 5FFB 33B4gd->relocaddr &= ~(4096 - 1);// hex 后三位与0// 5FFB 3000gd->start_addr_sp = gd->relocaddr;// 5FFB 3000reserve_mallocgd->start_addr_sp = reserve_stack_aligned((1024*1024));// 0x5feb3000reserve_board// gd->bd 不为null , 什么都不做setup_machinegd->bd->bi_arch_number = 1626;reserve_global_datagd->start_addr_sp = reserve_stack_aligned(sizeof(gd_t));// 0x5feb2f30gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));// 0x5feb2f30reserve_fdtgd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob), 32);// 0xe80gd->start_addr_sp = reserve_stack_aligned(gd->fdt_size);// 0x5feb20b0gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);// 0x5feb20b0reserve_bootstage// nullreserve_bloblist// nullreserve_arch// nullreserve_stacksgd->start_addr_sp = reserve_stack_aligned(16);// 这16个字节应该用于 irq的栈// 0x5feb20a0arch_reserve_stacksgd->irq_sp = gd->start_addr_sp;// 0x5feb20a0dram_init_banksize // 只有一个bankfor_each_bankgd->bd->bi_dram[i].start = addr;// 0x50000000gd->bd->bi_dram[i].size = (0x10000000);// 0x10000000show_dram_configfor_each_bank // 只有一个banksize += gd->bd->bi_dram[i].size;// 0x10000000print_size(size, "");// 实际打印 256 MiBboard_add_ram_info(0);nullputc('\n');setup_bdinfo// nulldisplay_new_sp// nullreloc_fdtgd->fdt_blob = gd->new_fdt;reloc_bootstage// nullreloc_bloblist// nullsetup_relocgd->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里面存放的还是gdldr r0, [r9, #72] // 72 是 start_addr_spbic r0, r0, #7 // 与上0b1000 , 第三位清0mov sp, r0 // 更改 spldr r9, [r9, #80] // 此时 r9 中存放的 是 new_gdadr 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 +28ldr r0, [r9, #56] // 将 new_gd 中的 relocaddr存放到r0mcr p15, 0, r0, c12, c0, 0bl c_runtime_cpu_setup// nullCLEAR_BSS// 问题,搬移过后,__bss_start的值有变化吗?// 宏汇编// ldr r0, =__bss_start // ldr r3, =__bss_end // mov r1, #0x00000000 // subs r2, r3, r0 // bl memsetbl coloured_LED_init// nullbl red_led_on// null/*// .code .rodata .data .bss .stack .heap此时的内存分布5FFF FFFF---------------------5FFF FFFFmmu(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_rgd->flags &= ~GD_FLG_LOG_READY;// 虽然这里用的是gd,但是和用new_gd 效果一样// 因为 gd指针的值 是寄存器(r9中的值// new_gd指针的值 也是寄存器(r9)中的值initr_trace// nullinitr_relocgd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;// 表示 code was relocated to RAM// 表示 full malloc() is readyinitr_cachesenable_cachesicache_enablecache_enable((1 << 12));reg = get_cr();set_cr(reg | cache_bit);dcache_enablecache_enable((1 << 2));if !mmu_enabled() mmu_setup();reg = get_cr();set_cr(reg | cache_bit);// 此时mmu 没有enableinitr_reloc_global_datamonitor_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.hinitr_barrier// nullinitr_mallocmalloc_start = gd->relocaddr - (1024*1024);// = 5FEB 3000// malloc 的区域 在 5FEB 3000 - 5FFB 3000 , 有 1024KBmem_malloc_init((ulong)map_sysmem(malloc_start, (1024*1024)), (1024*1024));mem_malloc_start = start;// 5FEB 3000mem_malloc_end = start + size;// 5FFB 3000mem_malloc_brk = start;memset((void *)mem_malloc_start, 0x0, size);malloc_bin_reloc();// nulllog_init// nullinitr_bootstagebootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");initr_console_record// nullinitr_of_live// nullinitr_dmgd->dm_root_f = gd->dm_root;gd->dm_root = 0;dm_init_and_scan(0);bootstage_accum(BOOTSTAGE_ID_ACCUM_DM_R);board_initcs8900_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 SFRgd->bd->bi_arch_number = 1626;// CONFIG_MACH_TYPE// unique id for this board gd->bd->bi_boot_params = (0x50000000 +0x100);// where this board expects paramsinitr_binman// nullinitr_dm_devices// nullstdio_init_tablesINIT_LIST_HEAD(&devs.list);serial_initialize serial_initinitr_announce// nullpower_init_board// nullinitr_mmcputs("MMC: ");mmc_initialize(gd->bd);initr_envenv_set_default(0,0)image_load_addr = env_get_ulong("loadaddr", 16, image_load_addr);initr_secondary_cpucpu_secondary_init_r// nullstdio_add_devicesdrv_system_initserial_stdio_initinitr_jumptablejumptable_initgd->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_rgd->flags |= GD_FLG_DEVINIT;print_pre_console_buffer(flushpoint);interrupt_initIRQ_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// nullinitr_ethaddreth_env_get_enetaddr("ethaddr", bd->bi_enetaddr);initr_netputs("Net: ");eth_initializerun_main_loopmain_loop
这篇关于OK6410A 开发板 (三) 12 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!