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 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 reset
reset
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 **rn");
show_board_info
model = fdt_getprop(gd->fdt_blob, 0, "model", ((void *)0));
printf("Model: %sn", model);
// 实际打印 为 Model: Samsung SMDK6410 based on S3C6410
// 打印的字符串为 arch/arm/dts/s3c64xx-ok6410a.dts 中的 model 节点的属性
checkboard
printf("Board: OK6410An");
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
上一篇:OK6410A 开发板 (三) 13 u-boot-2021.01 boot 解析 SPL 镜像运行部分 boot 详细解析
下一篇:OK6410A 开发板 (三) 11 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 命令的执行
推荐阅读最新更新时间:2024-11-09 11:28
设计资源 培训 开发板 精华推荐
- 基于SI3241 8位HC08 MCU的8位微控制器电路
- 用于汽车照明的 80 个 LED 高亮度 LED 驱动器
- LD39130S 300mA极低静态电流可调线性稳压IC的典型应用,具有自动绿色模式
- MPU9250 低成本 十轴传感器(磁力计 陀螺仪 加速度计)
- 使用 Silicon Labs 的 CP2112 的参考设计
- SY88212L EV、SY88212L 评估板允许检查 SY88212 的性能
- 具有一致跟踪和 6V 输入 UVLO 的 LTC3633AIFE-1 1.2V/1.8V 降压稳压器的典型应用电路
- S6SAE101A00SA1002,太阳能物联网设备开发套件为开发具有 BLE 无线连接的太阳能物联网设备提供了一个易于使用的平台
- AM1D-1515DH30-RZ ±15V 1 瓦 DC/DC 转换器的典型应用
- DJS-08 电子计算机