U-Boot移植(三) 启动流程详解

1、链接脚本 u-boot.lds 详解       

 通过链接脚本可以找到程序的入口,如果没有编译过 uboot 的话链接 脚本为

arch/arm/cpu/u-boot.lds。

最终的链接脚本是在这个 链接脚本的基础上生成的。编译一下 uboot,编译完成以后就会在 uboot 根目录下生成 u-boot.lds 文件。

ENTRY(_start)          _start 在文件 arch/arm/lib/vectors.S 中有定义
“变量”值可以在 u-boot.map 文件中查找,
除了 __image_copy_start 以外,其他的变量值每次编译的时候可能会变化
u-boot.lds 中我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start
_start 在 arch/arm/cpu/armv7/start.S 中实现

_start -> save_boot_params -> save_boot_params_ret

读取 cpsr 寄存器值,提取 bit0~bit4 数值。此五位数据设置处理器的工作模式

1、设置工作模式是 svc

2、关闭 FIQ 与 IRQ

cpu运行模式
M[4:0]        模式
10000        User(usr)
10001FIQ(fiq)
10010        iRQ(irq)
10011                Supervisor(svc)
10110Monitor(mon)
10111        Abort(abt)
11010Hyp(hyp)
11011Undefined(und)
11111System(sys)

3、 设置向量表重定向

读取 CP15 SCTLR 寄存器值

CR_V arch/arm/include/asm/system.h 中有如下所示定义
#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
因此这一行的目的就是清除 SCTLR 寄存器中的 bit13
bit13 V 位,此位是向量表控制位
当为 0 的时候向量表基地址 为 0X00000000
1 的时候向量表基地址为 0XFFFF0000 软件不能 重定位向量表。
这里将 V 清零,目的就是为了接下来的向量表重定位

4、函数 cpu_init_cp15 用来设置 CP15 相关的内容,比如关闭 MMU

        Invalidate L1 I/D

        disable MMU stuff and caches

5、函数  cpu_init_crit 

        执行函数 lowlevel_init  在文件 arch/arm/cpu/armv7/lowlevel_init.S 中定义

        设置 sp 指向 CONFIG_SYS_INIT_SP_ADDRCONFIG_SYS_INIT_SP_ADDR 在 include/configs/mx6ullevk.h 文件中,在 mx6ullevk.h 中有如下所示定义。

#define CONFIG_SYS_SDRAM_BASE		PHYS_SDRAM
#define CONFIG_SYS_INIT_RAM_ADDR	IRAM_BASE_ADDR
#define CONFIG_SYS_INIT_RAM_SIZE	IRAM_SIZE

#define CONFIG_SYS_INIT_SP_OFFSET \
	(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
#define CONFIG_SYS_INIT_SP_ADDR \
	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)

IRAM_BASE_ADDR 和 IRAM_SIZE 在文件 arch/arm/include/asm/arch-mx6/imx-regs.h。
IMX6UL/IM6ULL 内 部 ocram 的首地址和大小
71 #define IRAM_BASE_ADDR 0x00900000
...
408 #if !(defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL) || \
409 defined(CONFIG_MX6SLL) || defined(CONFIG_MX6SL))
410 #define IRAM_SIZE 0x00040000
411 #else
412 #define IRAM_SIZE 0x00020000
413 #endif
.config 中定义了 CONFIG_MX6UL
因此 IRAM_SIZE=0X20000=128KB
CONFIG_SYS_INIT_RAM_ADDR = IRAM_BASE_ADDR = 0x00900000
CONFIG_SYS_INIT_RAM_SIZE = 0x00020000 =128KB
GENERATED_GBL_DATA_SIZE 的值,在文件 include/generated/generic-asm-offsets.h
中有定义
1 #ifndef __GENERIC_ASM_OFFSETS_H__
2 #define __GENERIC_ASM_OFFSETS_H__
3 /*
4 * DO NOT MODIFY.
5 * 6 * This file was generated by Kbuild
7 */
8 
9 #define GENERATED_GBL_DATA_SIZE 256
10 #define GENERATED_BD_INFO_SIZE 80
11 #define GD_SIZE 248
12 #define GD_BD 0
13 #define GD_MALLOC_BASE 192
14 #define GD_RELOCADDR 48
15 #define GD_RELOC_OFF 68
16 #define GD_START_ADDR_SP 64
17
18 #endif
综上所述,CONFIG_SYS_INIT_SP_ADDR 值如下:
CONFIG_SYS_INIT_SP_OFFSET = 0x00020000 – 256 = 0x1FF00。
CONFIG_SYS_INIT_SP_ADDR = 0x00900000 + 0X1FF00 = 0X0091FF00

0X20000

128K

0x00900000IRAM_BASE_ADDR 
0x0091FF00CONFIG_SYS_INIT_SP_ADDR
0x0091FFFFGENERATED_GBL_DATA_SIZE  256
此时 sp 指向 0X91FF00 ,这属于 IMX6UL/IMX6ULL 的内部 ram

6、s_init 函数 s_init 函数定义在文件 arch/arm/cpu/armv7/mx6/soc.c 中

808 void s_init(void)
809 {
810 struct anatop_regs *anatop = (struct anatop_regs 
*)ANATOP_BASE_ADDR;
811 struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
812 u32 mask480;
813 u32 mask528;
814 u32 reg, periph1, periph2;
815
816 if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||
817 is_cpu_type(MXC_CPU_MX6ULL) || is_cpu_type(MXC_CPU_MX6SLL))
818 return;
819
820 /* Due to hardware limitation, on MX6Q we need to gate/ungate 
821 * all PFDs to make sure PFD is working right, otherwise, PFDs 
822 * may not output clock after reset, MX6DL and MX6SL have added 
823 * 396M pfd workaround in ROM code, as bus clock need it
824 */
825
826 mask480 = ANATOP_PFD_CLKGATE_MASK(0) |
827 ANATOP_PFD_CLKGATE_MASK(1) |
828 ANATOP_PFD_CLKGATE_MASK(2) |
829 ANATOP_PFD_CLKGATE_MASK(3);
830 mask528 = ANATOP_PFD_CLKGATE_MASK(1) |
831 ANATOP_PFD_CLKGATE_MASK(3);
832
833 reg = readl(&ccm->cbcmr);
834 periph2 = ((reg & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK)
835 >> MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET);
836 periph1 = ((reg & MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)
837 >> MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET);
838
839 /* Checking if PLL2 PFD0 or PLL2 PFD2 is using for periph clock */
840 if ((periph2 != 0x2) && (periph1 != 0x2))
841 mask528 |= ANATOP_PFD_CLKGATE_MASK(0);
842
843 if ((periph2 != 0x1) && (periph1 != 0x1) &&
844 (periph2 != 0x3) && (periph1 != 0x3))
845 mask528 |= ANATOP_PFD_CLKGATE_MASK(2);
846
847 writel(mask480, &anatop->pfd_480_set);
848 writel(mask528, &anatop->pfd_528_set);
849 writel(mask480, &anatop->pfd_480_clr);

     

u-boot.lds 

        .globl _start

_start:

        b reset

start.S

        .globl reset

        .globl save_boot_params_ret

reset:

        b save_boot_params    

save_boot_params :

        b    save_boot_params_ret        #设置向量表重定向)

        bl    cpu_init_cp15                      #初始化 cache 关闭 MMU     

        bl    cpu_init_crit                        # 设置 pll mux memory

        bl    _main

cpu_init_crit :

        b    lowlevel_init

lowlevel_init.S

        ENTRY(lowlevel_init)        # 设置栈地址

        bl s_init                              # 芯片是 6ULL 函数为空操作

        

_start -> reset -> save_boot_params -> save_boot_params_ret -> 

cpu_init_cp15 -> cpu->init_crit -> lowlevel_init -> s_init -> _main-> board_init_f_alloc_reserve -> board_init_f_init_reserve -> board_init_f

-> relocate_code -> relocate_vectors -> c_runtime_cpu_setup -> board_init_r

7、_main 函数定义在文件 arch/arm/lib/crt0.S

sp = CONFIG_SYS_INIT_SP_ADDR

board_init_f_alloc_reserve 此函数有一个参数,参数为 r0 中的值,也 就是 0X0091FF00 此函数定义在文件 common/init/board_init.c 中 : 主要是留出早期的 malloc 内存区域和 gd 内存区域,返回值为新的sp指针地址:0x0091FA00

56 ulong board_init_f_alloc_reserve(ulong top)
57 {
58 /* Reserve early malloc arena */
59 #if defined(CONFIG_SYS_MALLOC_F)
60 top -= CONFIG_SYS_MALLOC_F_LEN;
61 #endif
62 /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
63 top = rounddown(top-sizeof(struct global_data), 16);
64
65 return top;
66 }
 

0x00900000       0x20000
(128k)
gloabal_data(16字节对齐)0x0091FA00

248B+8B

(+8字节对齐)

CONFIG_SYS_MALLOC_F_LEN

                early malloc

0x0091FB000x400
CONFIG_SYS_INIT_SP_ADDR0x0091FF00256B
0x0091FFFF

r9 寄存器存放着全局变量 gd 的地址: 0x0091FA00

uboot 中定义了一个指向 gd_t 的指针 gd gd 存放在寄存器 r9 里面 的,因此 gd 是个全局变量, 在 include/asm-generic/global_data.h 里面有定义 也就是 gd 指向 0X0091FA00.

8、board_init_f_init_reserve
此函数在文件 common/init/board_init.c 中有定义
1) 初始化gd结构体(清零) 
2) malloc_base 被赋值为  gd 基地址 +gd 大小=0X0091FA00+248=0X0091FAF8 再做16字节对齐,
        gd->malloc_base=0X0091FB00
9、board_init_f  ,此函数定义在文件 common/board_f.c
        1) 初始化 gd 的所有成员变量,分配重定向之后 uboot 各部分的内存区域
        2) 初始化一系列外设,比如串口、定时器,或者打印一些消息等
        3) 主要在于  initcall_run_list() 包含一系列初始化函数
        
setup_mon_len
设置 gd mon_len 成员变量,__bss_end -_start
0X878A8E74-0x87800000=0XA8E74
initf_malloc
初始化 gd 中跟 malloc 有关的成员变量,比如 malloc_limit
gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN=0X400
表示 malloc 内存池大小
initf_console_record
imx6u未定义相关宏,函数未调用
arch_cpu_init
cpu 架构初始化
initf_dm
驱动模型的一些初始化
arch_cpu_init_dm
函数未实现
mark_bootstage
board_early_init_f
板子相关的早期的一些初始化设置, I.MX6ULL 用来初始化串口的 IO 配置
timer_init
初始化定时器, Cortex-A7 内核有一个定时器。
通过这个定时器来为 uboot 提供时间
board_postclk_init
对于 I.MX6ULL 来说是设置 VDDSOC 电压
get_clocks
I.MX6ULL 获取的是 sdhc_clk 时钟,也就
SD 卡外设的时钟
env_init
设置 gd 的成员变量 env_addr ,也就是环境变
量的保存地址
init_baud_rate
初始化波特率
serial_init
初始化串口
console_init_f
gd->have_console 1 ,表示有个控制台
display_options
display_text_info
如果开启 UBOOT DEBUG 功能的话就
会输出 text_base bss_start bss_end
print_cpuinfo
函数用于打印 CPU 信息
show_board_info
函数用于打印板子信息
INIT_FUNC_WATCHDOG_INIT
初始化看门狗,对于 I.MX6ULL 来说是空函数
INIT_FUNC_WATCHDOG_RESET
复位看门狗,对于 I.MX6ULL 来说是空函数
init_func_i2c
初始化 I2C
announce_dram_init
输出字符串“ DRAM:
dram_init
并非真正的初始化 DDR ,只是设置 gd->ram_size 的值
对于正点原 子 I.MX6ULL 开发板 EMMC 版本核心板来说就是 512MB
post_init_f
此函数用来完成一些测试,初始化 gd->post_init_f_time
testdram
测试 DRAM,空函数
setup_dest_addr
设置目的地址,设置 gd->ram_size gd->ram_top gd->relocaddr
这三个的值
reserve_round_4k
函数用于对 gd->relocaddr 4KB 对 齐
reserve_mmu
留出 MMU TLB 表的位置
分配 MMU TLB 表内存以后会
gd->relocaddr 64K 字节对齐。完成以后
/MMU TLB 表大小
gd->arch.tlb_size  = 0x400        
//MMU TLB 表起始地址, 64KB 对齐以后
gd->arch.tlb_addr = 0x9FFF0000
//relocaddr 地址
gd->relocaddr       = 0x9FFF0000
reserve_trace 函数
留出跟踪调试的内存, I.MX6ULL 没有用到!
reserve_uboot
留出重定位后的 uboot 所占用的内存区域
uboot 所占用大小由
gd->mon_len 所指定,留出 uboot 的空间以后还要对 gd->relocaddr 4K 字节对齐,并且重新设
gd->start_addr_sp
gd->mon_len          = 0xA8EF4
gd->start_addr_sp  = 0x9FF47000
gd->relocaddr         = 0x9FF47000
reserve_malloc
留出 malloc 区域, 
TOTAL_MALLOC_LEN = 
CONFIG_SYS_MALLOC_LEN(16M)  + 
CONFIG_ENV_SIZE(8K)  =
0x1000000 +0x2000 = 0x1002000
gd->start_addr_sp -= TOTAL_MALLOC_LEN
= 0x9FF4700 - 0x1002000
= 0x9EF4500
reserve_board
留出板子 bd 所占的内存区
bd 是结构体 bd_t
bd_t 大小为 80 字节
gd->bd  = 0x9EF44FB0
gd->start_addr_sp -= 0x50
= 0x9EF44FB0
setup_machine
设置机器 ID linux 启动的时候会和这个机器 ID 匹配,如果匹
配的话 linux 就会启动正常
但是!! I.MX6ULL 不用这种方式了,这是以前老版本的 uboot
linux 使用的,新版本使用设备树了,因此此函数无效
reserve_global_data
保留出 gd_t 的内存区域, gd_t 结构体大小为 248B
gf->new_gd = 0x9EF44EB8
gd->start_addr_sp -= 0XF8(248B)
= 0x9EF44EB8
reserve_fdt
留出设备树相关的内存区域, I.MX6ULL uboot 没有用到,因此
此函数无效
reserve_arch
空函数
reserve_stacks
先对 gd->start_addr_sp 减去 16 ,然后做 16 字节对齐,使能 IRQ 的话还要留出 IRQ 相应的内存本,  uboot 中并没有使用到 IRQ
gd->start_addr_sp=0X9EF44E90
setup_dram_config
设置 dram 信息
设置
gd->bd->bi_dram[0].start = 0x80000000
gd->bd->bi_dram[0].size  = 0x20000000
show_dram_config 函数
显示 DRAM 的配置
display_new_sp
显示新的 sp 位置,也就是 gd->start_addr_sp
reloc_fdt
用于重定位 fdt
setup_reloc
设置 gd 的其他一些成员变量,供后面重定位的时候使用,
并且将以前的 gd 拷贝到 gd->new_gd 处.
可以看出, uboot 重定位后的偏移为 0X18747000 ,重定位后的新地址为
0X9FF4700 ,新的 gd 首地址为 0X9EF44EB8 ,最终的 sp 0X9EF44E90

ldr    sp, [r9, #GD_START_ADDR_SP]    /* sp = gd->start_addr_sp = 0X9EF44E90*/
1) 将sp指针更新, GD_START_ADDR_SP=64
0X9EF44E90 DDR 中的地址,说明新的 sp gd 将会存
放到 DDR 中,而不是内部的 RAM 了,sp 执行8字节对齐
2)  获取 gd->bd 的地址赋给 r9 ,此时 r9 存放的是老的 gd ,这里通过获取 gd->bd
地址来计算出新的 gd 的位置。 GD_BD=0。
3) adr    lr, here
      ldr    r0, [r9, #GD_RELOC_OFF]        /* r0 = gd->reloc_off */
      add    lr, lr, r0
设置 lr 为当前数值,r0 获取重定位偏移, lr = 当前值 + 重定位偏移
4) 读取重定位的地址,作为参数传进 relocate_code, 0X9FF47000。
10、relocate_code    此函数定义在文件 arch/arm/lib/relocate.S
11、relocate_vectors   此函数定义在文件 arch/arm/lib/relocate.S 对中断向量表做重定位
12、c_runtime_cpu_setup ,此函数定义在文件  arch/arm/cpu/armv7/start.S
        初始化 Icache
13、清除 bss 段
14、board_init_r (gd_t *id, ulong dest_addr) r0 gd地址,r1 重载目的地址
       此函数定义在文件 common/board_r.c
        调用 initcall_run_list 函数来执行初始化序列 init_sequence_r
        init_sequence_r 也定义在文件 common/board_r.c
1 init_fnc_t init_sequence_r[] = { 2 initr_trace, 
3 initr_reloc, 
4 initr_caches, 
5 initr_reloc_global_data, 
6 initr_barrier, 
7 initr_malloc, 
8 initr_console_record, 
9 bootstage_relocate, 
10 initr_bootstage, 
11 board_init, /* Setup chipselects */ 
12 stdio_init_tables, 
13 initr_serial, 
14 initr_announce, 
15 INIT_FUNC_WATCHDOG_RESET
16 INIT_FUNC_WATCHDOG_RESET
17 INIT_FUNC_WATCHDOG_RESET
18 power_init_board, 
19 initr_flash, 
20 INIT_FUNC_WATCHDOG_RESET
21 initr_nand, 
22 initr_mmc, 
23 initr_env, 
24 INIT_FUNC_WATCHDOG_RESET
25 initr_secondary_cpu, 
26 INIT_FUNC_WATCHDOG_RESET
27 stdio_add_devices, 
28 initr_jumptable, 
29 console_init_r, /* fully init console as a device */
30 INIT_FUNC_WATCHDOG_RESET 
31 interrupt_init, 
32 initr_enable_interrupts, 
33 initr_ethaddr, 
34 board_late_init, 
35 INIT_FUNC_WATCHDOG_RESET 
36 INIT_FUNC_WATCHDOG_RESET
37 INIT_FUNC_WATCHDOG_RESET
38 initr_net, 
39 INIT_FUNC_WATCHDOG_RESET
40 run_main_loop, 
41 };
第 2 行,initr_t
run_main_loop 行,主循环,处理命令。
uboot 启动以后会进入 3 秒倒计时,如果在 3 秒倒计时结束之前按下按下回车键,那么就
会进入 uboot 的命令模式,如果倒计时结束以后都没有按下回车键,那么就会自动启动 Linux
核 , 这 个 功 能 就 是 由 run_main_loop 函 数 来 完 成 的 。 r un_main_loop 函 数 定 义 在 文 件
common/board_r.c
bootstage_mark_name 函数,打印出启动进度。
autoboot_command 函数,此函数就是检查倒计时是否结束?倒计时结束之前有
没有被打断?此函数定义在文件 common/autoboot.c
main_loop

bootstage_mark_name

cli_init

run_preboot_environment_command

bootdelay_process

autoboot_command

cli_loop

cli_loop 函数是 uboot 的命令行处理函数,我们在 uboot 中输入各种命令,进行各种操作就
是有 cli_loop 来处理的,此函数定义在文件 common/cli.c
用于在uboot 启动 linux 前的延时 3s(环境变量可修改) 中触发信号,处理相关的输入命令。
parse_file_outer 处理指令
parse_stream        解析指令
run_list ->run_list_real->run_pipe_real->cmd_process                  根据不同的指令执行对应的函数
cmd_process
cmd_call 来执行具体的命令

bootz启动linux流程
不管是 bootz 还是 bootm 命令,在启动 Linux 内核的时候都会用到一个重要的全局变量:
images images 在文件 cmd/bootm.c 中有如下定义
bootm_headers_t images
do_bootz 函数
bootz 命令的执行函数为 do_bootz ,在文件 cmd/bootm.c 中有如下定义
调用 bootz_start 函数, bootz_start 函数执行过程参考 32.3.3 小节。
调用函数 bootm_disable_interrupts 关闭中断。
do_bootm_states  调用函数 do_bootm_states 来执行不同的 BOOT 阶段
这里要执行的 BOOT
段有: BOOTM_STATE_OS_PREP BOOTM_STATE_OS_FAKE_GO BOOTM_STATE_OS_GO
bootz_start 函数
bootz_srart 函数也定义在文件 cmd/bootm.c
bootz_srart -> do_bootm_states->bootz_setup->bootm_find_images
,调用函数 do_bootm_states ,执行 BOOTM_STATE_START 阶段
设置 images ep 成员变量,也就是系统镜像的入口点,使用 bootz 命令启动
系统的时候就会设置系统在 DRAM 中的存储位置
调用 bootz_setup 函数,此函数会判断当前的系统镜像文件是否为 Linux 的镜
像文件,并且会打印出镜像相关信息
调用函数 bootm_find_images 查找 ramdisk 和设备树 (dtb) 文件
do_bootm_states
bootz 最 后 调 用 的 就 是 函 数 do_bootm_states ,而且 在 bootz_start 中 也 调 用 了
do_bootm_states 函数
BOOTM_STATE_OS_PREP
BOOTM_STATE_OS_FAKE_GO
BOOTM_STATE_OS_GO
BOOTM_STATE_START
!通过
函数 bootm_os_get_boot_func 来查找系统启动函数,参数 images->os.os 就是系统类型,根据这
个系统类型来选择对应的启动函数,在 do_bootz 中设置 images.os.os= IH_OS_LINUX 。函数返
回值就是找到的系统启动函数,这里找到的 Linux 系统启动函数为 do_bootm_linux
处理 BOOTM_STATE_OS_PREP 状态,调用函数 do_bootm_linux do_bootm_linux
也是调用 boot_prep_linux 来完成具体的处理过程。 boot_prep_linux 主要用于处理环境变量
bootargs bootargs 保存着传递给 Linux kernel 的参数
调用函数 boot_selected_os 启动 Linux 内核,此函数第 4 个参数为 Linux 系统镜像头,第 5 个参数就是 Linux 系统启动函数 do_bootm_linux
boot_selected_os 函数定义在文件 common/bootm_os.c 中
调用 boot_fn 函数,也就是 do_bootm_linux 函数来启动 Linux 内核
do_bootm_linux 函数
经过前面的分析,我们知道了 do_bootm_linux 就是最终启动 Linux 内核的函数,此函数定 义在文件 arch/arm/lib/bootm.c
如果参数 flag 等于 BOOTM_STATE_OS_GO 或者 BOOTM_STATE_OS_FAKE_GO
的话就执行 boot_jump_linux 函数。 boot_selected_os 函数在调用 do_bootm_linux 的时候会将 flag
设置为 BOOTM_STATE_OS_GO
执行函数 boot_jump_linux ,此函数定义在文件 arch/arm/lib/bootm.c

do_bootz()
{
    boot_strat();
    bootm_disable_interrupts();
    do_bootm_states();
}

boot_strat()
{
    do_bootm_states(BOOT_STATE_START);
    images->ep = load_addr;    // 获取linux镜像(zImage),保存在 images 成员变量 ep 中
    bootm_find_images();
}

do_bootm_states(BOOT_STATE_START)
{
    bootm_start();
}

bootm_find_images()
{
   boot_get_fdt();            // 获取设备树,设备树首地址保存在 images 成员变量 ft_addr 中
}

do_bootm_states()
{
    bootm_os_get_boot_func();    // 获取 linux 系统启动函数:do_bootm_linux()
    boot_selected_os();
}

boot_selected_os()
{
    boot_fn();            // 实际运行:do_bootm_linux
    boot_prep_linux();    // 启动 linux 之前做一些其他处理,比如在设备树的 closen 节点下添加                    
                          // 子节点 bootargs, bootargs 子节点存放 bootargs 环境变量
    boot_jump_linux();    
}

boot_jump_linux()
{
    announce_and_cleanup();    // 输出 "Strating kernel" 并且做一些清理工作
    kernel_entry();            // 启动 linux 内核
}
变量                数值描述
__image_copy_start
0x87800000
uboot 拷贝的首地址
__image_copy_end
0x8785dd54
uboot 拷贝的结束地址
__rel_dyn_start
0x8785dd54
.rel.dyn 段起始地址
__rel_dyn_end
0x878668f4
.rel.dyn 段结束地址
_image_binary_end
0x878668f4
镜像结束地址
__bss_start
0x8785dd54
.bss 段起始地址
__bss_end
0x878a8e74.bss 段结束地址

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值