searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

u-boot启动内存分配

2025-06-27 02:42:42
2
0
  1. _main

u-boot完成前期准备后,从_main(crt0_64.S)开始执行,_main接口一共分为三部分,第一部分初始化串口、看门狗、DDR以及为代码重定向做准备,相关接口为board_init_f;第二部分执行的代码重定向,相关接口为relocate_code;第三部分从重定向后的代码开始执行初始化吗,相关接口为board_init_r;调用board_init_f之前会先分配gload_data内存并初始化;

ldr x0, =(SYS_INIT_SP_ADDR)
bic sp, x0, #0xf
mov x0, sp
bl board_init_f_alloc_reserve /*为global data分配空间,从sp往low address分配*/
mov sp, x0 /* set up gd here, outside any C code */
mov x18, x0
bl board_init_f_init_reserve /*初始化global data,设置malloc起始address为SYS_INIT_SP_ADDR*/

mov x0, #0
bl board_init_f
...
ldr x9, [x18, #GD_RELOC_OFF] /* x9 <- gd->reloc_off */
add lr, lr, x9 /* new return address after relocation */
ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd->relocaddr */
b relocate_code

/*
* Clear BSS section
*/
ldr x0, =__bss_start /* this is auto-relocated! */
ldr x1, =__bss_end /* this is auto-relocated! */
clear_loop:
str xzr, [x0], #8
cmp x0, x1
b.lo clear_loop

/* call board_init_r(gd_t *id, ulong dest_addr) */
mov x0, x18 /* gd_t */
ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */
b board_init_r

2. board_init_f阶段

boar_init_f阶段的工作有初始化堆,scan部分设备树,初始化串口,初始化DDR,设置重定向address并分配重定向后的gd内存、堆内存、设备树和栈等;设置完成后会将当前global_data拷贝到重定向后的位置即new_gd;

setup_mon_len //计算uboot size  gd->mon_len = (ulong)__bss_end - (ulong)_start
fdtdec_setup  //设置设备树
initf_malloc  //初始化malloc
initf_dm  //scan fdt设备并绑定驱动,只操作设置了DM_FLAG_PRE_RELOC的驱动,dts node配置了"bootph-all"也会scan
serial_init  //初始化串口
dram_init  //根据dts配置设置ddr size  (ddr初始化已经在spl中完成)
setup_dest_addr  //设置ram_base和ram_top
reserve_uboot  //预留uboot 代码段内存 gd->relocaddr -= gd->mon_len
reserve_malloc  //预留malloc堆内存,size为CONFIG_SYS_MALLOC_LEN
reserve_global_data  //预留新的gd内存
reserve_fdt  //预留设备树内存
reserve_stacks  //预留栈内存
dram_init_banksize  //初始化dram bank信息
reloc_fdt  //拷贝设备树到ddr
setup_reloc //计算代码段重定向偏移,拷贝gd到new_gd

board_init_f阶段的内存分配如下,uboot_text段的起始address和stack的起始address是可配置的,gload_data相当于是在栈顶开辟了一会儿空间;

3. board_init_r阶段

board_init_r阶段的工作有堆初始化、设备树完整初始化、再次初始化串口和看门狗、然后根据配置初始化各个外设,最后进入主循环;

initr_malloc  //计算malloc 堆内存起始address,设置堆大小
initr_dm  //scan所有设备,并绑定驱动,如果驱动设置了DM_FLAG_PROBE_AFTER_BIND,则自动初始化设备
serial_initialize //再次初始化串口
initr_watchdog //初始化看门狗
... //按配置初始化各种外设
run_main_loop //进入主循环

board_init_r阶段内存分配如下,代码段会拷贝到可用DDR的top address,接下来从高到低依次是堆内存空间、gload_data、设备树、栈内存;

4. 为什么要重定向?

设备前期初始化时运行在sram中,通常这部分内存比较小,在DDR初始化完成之前,只能没有太多内存可用,通常bss段不会分配到sram address段,因此board_init_f中无法使用全局变量;当DDR可用后,再将代码段拷贝到DDR,重新构建堆和栈,此时整个地址空间可用,可以执行完整初始化;

0条评论
0 / 1000
c****8
4文章数
0粉丝数
c****8
4 文章 | 0 粉丝
c****8
4文章数
0粉丝数
c****8
4 文章 | 0 粉丝
原创

u-boot启动内存分配

2025-06-27 02:42:42
2
0
  1. _main

u-boot完成前期准备后,从_main(crt0_64.S)开始执行,_main接口一共分为三部分,第一部分初始化串口、看门狗、DDR以及为代码重定向做准备,相关接口为board_init_f;第二部分执行的代码重定向,相关接口为relocate_code;第三部分从重定向后的代码开始执行初始化吗,相关接口为board_init_r;调用board_init_f之前会先分配gload_data内存并初始化;

ldr x0, =(SYS_INIT_SP_ADDR)
bic sp, x0, #0xf
mov x0, sp
bl board_init_f_alloc_reserve /*为global data分配空间,从sp往low address分配*/
mov sp, x0 /* set up gd here, outside any C code */
mov x18, x0
bl board_init_f_init_reserve /*初始化global data,设置malloc起始address为SYS_INIT_SP_ADDR*/

mov x0, #0
bl board_init_f
...
ldr x9, [x18, #GD_RELOC_OFF] /* x9 <- gd->reloc_off */
add lr, lr, x9 /* new return address after relocation */
ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd->relocaddr */
b relocate_code

/*
* Clear BSS section
*/
ldr x0, =__bss_start /* this is auto-relocated! */
ldr x1, =__bss_end /* this is auto-relocated! */
clear_loop:
str xzr, [x0], #8
cmp x0, x1
b.lo clear_loop

/* call board_init_r(gd_t *id, ulong dest_addr) */
mov x0, x18 /* gd_t */
ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */
b board_init_r

2. board_init_f阶段

boar_init_f阶段的工作有初始化堆,scan部分设备树,初始化串口,初始化DDR,设置重定向address并分配重定向后的gd内存、堆内存、设备树和栈等;设置完成后会将当前global_data拷贝到重定向后的位置即new_gd;

setup_mon_len //计算uboot size  gd->mon_len = (ulong)__bss_end - (ulong)_start
fdtdec_setup  //设置设备树
initf_malloc  //初始化malloc
initf_dm  //scan fdt设备并绑定驱动,只操作设置了DM_FLAG_PRE_RELOC的驱动,dts node配置了"bootph-all"也会scan
serial_init  //初始化串口
dram_init  //根据dts配置设置ddr size  (ddr初始化已经在spl中完成)
setup_dest_addr  //设置ram_base和ram_top
reserve_uboot  //预留uboot 代码段内存 gd->relocaddr -= gd->mon_len
reserve_malloc  //预留malloc堆内存,size为CONFIG_SYS_MALLOC_LEN
reserve_global_data  //预留新的gd内存
reserve_fdt  //预留设备树内存
reserve_stacks  //预留栈内存
dram_init_banksize  //初始化dram bank信息
reloc_fdt  //拷贝设备树到ddr
setup_reloc //计算代码段重定向偏移,拷贝gd到new_gd

board_init_f阶段的内存分配如下,uboot_text段的起始address和stack的起始address是可配置的,gload_data相当于是在栈顶开辟了一会儿空间;

3. board_init_r阶段

board_init_r阶段的工作有堆初始化、设备树完整初始化、再次初始化串口和看门狗、然后根据配置初始化各个外设,最后进入主循环;

initr_malloc  //计算malloc 堆内存起始address,设置堆大小
initr_dm  //scan所有设备,并绑定驱动,如果驱动设置了DM_FLAG_PROBE_AFTER_BIND,则自动初始化设备
serial_initialize //再次初始化串口
initr_watchdog //初始化看门狗
... //按配置初始化各种外设
run_main_loop //进入主循环

board_init_r阶段内存分配如下,代码段会拷贝到可用DDR的top address,接下来从高到低依次是堆内存空间、gload_data、设备树、栈内存;

4. 为什么要重定向?

设备前期初始化时运行在sram中,通常这部分内存比较小,在DDR初始化完成之前,只能没有太多内存可用,通常bss段不会分配到sram address段,因此board_init_f中无法使用全局变量;当DDR可用后,再将代码段拷贝到DDR,重新构建堆和栈,此时整个地址空间可用,可以执行完整初始化;

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0