第三期 第6讲 Uboot启动流程详解

第6讲 Uboot启动流程详解

一、连接脚本u-boot.lds详解

1、从u-boot.lds可知,uboot入口地址为_start

__image_copy_start -》 0x87800000

.vetcors -> 0x87800000 存放中断向量表

arch/arm/cpu/armv7/start.o start.c

__image_copy_end -》 0x8785dc6c

__rel_dyn_start -> 0x8785dc6c rel段

__rel_dyn_end -> 0x878668a4

__end -》 0x878668a4

_image_binary_end -》 0x878668a4

__bss_start -》 0x8785dc6c bss段。

__bss_end -》 0x878a8d74

二、uboot启动流程

1、reset函数

bicne=bic + ne

①、reset函数目的是将处理器设置为SVC模式,并且关闭FIQ和IRQ.

②、设置中断向量。

③、初始化CP15

④、

2、lowlevel_init函数

CONFIG_SYS_INIT_SP_ADDR

#define CONFIG_SYS_INIT_SP_ADDR \

(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)

#define CONFIG_SYS_INIT_SP_OFFSET \

(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)

#define CONFIG_SYS_INIT_RAM_SIZE IRAM_SIZE

#define IRAM_SIZE 0x00020000

#define CONFIG_SYS_INIT_RAM_ADDR IRAM_BASE_ADDR

#define IRAM_BASE_ADDR 0x00900000 6ULL内部OCRAM

#define GENERATED_GBL_DATA_SIZE 256

0x00900000 + CONFIG_SYS_INIT_SP_OFFSE =>

0x00900000 + CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE =>

0x00900000 *+* 0x00020000 – 256 = 0x0091ff00

设置SP指针、R9寄存器

3、s_init函数

空函数。

4、_main函数

5、board_init_f函数

initcall_run_lis此函数会调用一系列的函数,这些函数保存在init_sequence_f数组里面,

version_string[] = U_BOOT_VERSION_STRING

#define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \

U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING

U_BOOT_VERSION = U-Boot 2016.03

TOTAL_MALLOC_LEN (CONFIG_SYS_MALLOC_LEN + CONFIG_ENV_SIZE)

CONFIG_SYS_MALLOC_LEN (16 * SZ_1M)

CONFIG_ENV_SIZE SZ_8K

mx6ullevk.c mx6ullevk.h这两个文件长打交道

6、relocate_code函数

relocate_code函数有一个参数,r0=gd->relocaddr=0X9FF47000,uboot重定位后的首地址。

r1=0X87800000 源地址起始地址。

r4=0X9FF47000-0X87800000=0X18747000 偏移。

r2=0x8785dc6c

当简单粗暴的将uboot从0X87800000拷贝到其他地方以后,关于函数调用、全局变量引用就会出问题。Uboot对于这个的处理方法就是采用位置无关码,这个就需要借助于.rel.dyn段。

8785dcf8 <rel_a>:

8785dcf8: 00000000 andeq r0, r0, r0

878042b4 <rel_test>:

878042b4: e59f300c ldr r3, [pc, #12] ; 878042c8 <rel_test+0x14>

878042b8: e3a02064 mov r2, #100 ; 0x64

878042bc: e59f0008 ldr r0, [pc, #8] ; 878042cc <rel_test+0x18>

878042c0: e5832000 str r2, [r3]

878042c4: ea00d64c b 87839bfc <printf>

878042c8: 8785dcf8 ; <UNDEFINED> instruction: 0x8785dcf8

878042cc: 87842aaf strhi r2, [r4, pc, lsr #21]

设置r3为878042b4+8+12=878042c8的值,r3=8785dcf8。这里并没有直接去读取rel_a的地址,而是借助了878042c。

878042c8叫做Label。

重定位以后

9ffa4cf8 <rel_a>:

9ffa4cf8: 00000000 andeq r0, r0, r0

9ff4b2b4<rel_test>:

9ff4b2b4: e59f300c ldr r3, [pc, #12] ; 878042c8 <rel_test+0x14>

9ff4b2b8: e3a02064 mov r2, #100 ; 0x64

9ff4b2bc: e59f0008 ldr r0, [pc, #8] ; 878042cc <rel_test+0x18>

9ff4b2c0: e5832000 str r2, [r3]

9ff4b2c4: ea00d64c b 87839bfc <printf>

9ff4b2c8: 8785dcf8 ; <UNDEFINED> instruction: 0x8785dcf8

9ff4b2cc: 87842aaf strhi r2, [r4, pc, lsr #21]

Label中的值还是原来的!必须要将8785dcf8换为重定位后的rel_a地址。读取9ff4b2c8里面的数据,也就是老的rel_a的地址=8785dcf8+0x18747000=0x9ffa4cf8

重定位以后,需要对所有的Label保存的数据加上偏移!!

8785dcec: 87800020 strhi r0, [r0, r0, lsr #32]

8785dcf0: 00000017 andeq r0, r0, r7, lsl r0

……

8785e2fc: 878042c8 strhi r4, [r0, r8, asr #5]

8785e300: 00000017 andeq r0, r0, r7, lsl r0

878042c8+offset = 读取新的Label处的数据+offset

完成这个功能在连接的时候需要加上”-pie”

7、relocate_vectors函数

设置VBAR寄存器为重定位后的中断向量表起始地址。

8、board_init_r函数

Board_init_r函数和board_init_f函数很类似。board_init_r也是执行init_sequence_r初始化序列。

9、run_main_loop函数

run_main_loop

-> main_loop

-> bootdelay_process 获取bootdelay的值,然后保存到stored_bootdelay

全局变量里面,获取bootcmd环境变量值,并且将其

返回

-> autoboot_command 参数是bootcmd的值。

-> abortboot 参数为boot delay,此函数会处理倒计时

-> abortboot_normal 参数为boot delay,此函数会处理倒计时

-> cli_loop uboot命令模式处理函数。

-> parse_file_outer

-> parse_stream_outer

-> parse_stream 解析输入的字符,得到命令

-> run_list 运行命令

-> run_list_real

-> run_pipe_real

-> cmd_process 处理命令,也就是执行命令

10、cli_loop函数

11、cmd_process函数

Uboot使用U_BOOT_CMD来定义一个命令。CONFIG_CMD_XXX来使能uboot中的某个命令。

U_BOOT_CMD最终是定义了一个cmd_tbl_t类型的变量,所有的命令最终都是存放在.u_boot_list段里面。cmd_tbl_t的cmd成员变量就是具体的命令执行函数,命令执行函数都是do_xxx。

cmd_process

->find_cmd 从.u_boot_list段里面查找命令,当找到对应的命令以后以返回值的

形式给出,为cmd_tbl_t类型

->cmd_call

->cmdtp->cmd 直接引用cmd成员变量

三、bootz启动Linux内核过程

Uboot启动Linux内核使用bootz命令,bootm。。bootz是如何启动Linux内核?uboot的生命是怎么终止的呢?linux又是怎么启动的呢?

1、image全局变量

bootm_headers_t images;

2、do_bootz函数

tftp 80800000 zImage

tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb

bootz 80800000 - 83000000

bootz命令的执行函数,do_xxxx,do_bootz是bootz的执行函数。

do_bootz

-> bootz_start

-> do_bootm_states 阶段为BOOTM_STATE_START

-> bootm_start 对images全局变量清零,

-> images->ep = 0X80800000

->bootz_setup 判断zImage是否正确

-> bootm_find_images

· -> boot_get_fdt 找到设备树,然后将设备树起始地址和长度,写入到images

的ft_addr和ft_len成员变量中。

-> bootm_disable_interrupts 关闭中断相关

-> images.os.os = IH_OS_LINUX; 表示要启动Linux系统

-> do_bootm_states 状态BOOTM_STATE_OS_PREP 、BOOTM_STATE_OS_FAKE_GO 、

BOOTM_STATE_OS_GO,

-> bootm_os_get_boot_func 查找Linux内核启动函数。找到Linux内核启动函数

do_bootm_linux,赋值给boot_fn。

-> boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); 就是do_bootm_linux。

-> boot_prep_linux 启动之前的一些工作,对于使用设备树来说,他会将

Bootargs传递给Linux内核,通过设备树完成。也就是向

Linux内核传参。

-> boot_selected_os BOOTM_STATE_OS_GO, do_bootm_linux

-> do_bootm_linux,BOOTM_STATE_OS_GO

-> boot_jump_linux

-> machid= gd->bd->bi_arch_number;

-> void (*kernel_entry)(int zero, int arch, uint params);

-> kernel_entry = (void (*)(int, int, uint))images->ep; 0X80800000。

-> announce_and_cleanup 输出Starting kernel……

-> kernel_entry(0, machid, r2); 启动Linux内核。Uboot的最终使命,启动Linux内核。

zimage_header 的zi_magic为zimage的幻数,魔术数。应该为0x016f2818。前面有9个32位的数据,那么9*4=36,0~35,第36个字节的数据开始就是zimage的幻数。

3、do_bootm_states函数

4、bootm_os_get_boot_func函数

5、do_bootm_linux函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值