第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > Uboot启动分析--start.S启动分析(1)

Uboot启动分析--start.S启动分析(1)

时间:2019-05-04 04:51:43

相关推荐

Uboot启动分析--start.S启动分析(1)

总目录

NXP i.MX8M secure boot流程

Uboot链接脚本分析述

Uboot启动分析–start.S启动分析(1)

Uboot启动分析–start.S启动分析(2)

Uboot启动分析–start.S启动分析(3)

Uboot启动分析–__main分析(1)

Uboot启动分析–__main分析(2)

Uboot启动分析–启动kernel

Uboot分析–SPL跳转过程分析

Uboot中lpddr4的初始化(i.MX8M)

使用U_BOOT_CMD()自定义uboot命令

前面分析了spl-uboot lds的链接脚本,提到了_start符号是整个程序的入口,链接器在链接时会查找目标文件中的_start符号代表的地址,把它设置为整个程序的入口地址。并且我们也知道start.S的代码段也是位于整个spl-uboot代码段最开始的位置,而_start符号对于Armv8架构来说位于则位于 arch\arm\cpu\armv8\start.S文

start.s

.globl_start_start:breset

_start函数的第一步指令就是跳转到reset函数,这个待会儿再分析。先看看下面段定义。

对于i.MX8MP来说,CONFIG_SYS_TEXT_BASE是0x40200000。.quad在存储器中分配8个字节的数40200000,

紧接着定义了几个符号_end_ofs _bss_start_ofs 和_bss_end_ofs,他们的地址也都是位于.text段中,值则是根据之前lds脚本中提到的长度为0的字符数组的值减去_start符号所在的地址,也就是离_start符号的地址值的偏移。还记得上篇分析链接脚本里面提到的对于8mp,将bss段放在了外部存储sdram的0x96e000开始的8K空间内吗?所以,__bss_start的值即为0x96e000,而_start则是放在了.text段的最前面也就是内部sram空间0x920000处,所以对于_bss_start_ofs来说,其值便为0x04e000。

.align 3.globl_TEXT_BASE_TEXT_BASE:.quadCONFIG_SYS_TEXT_BASE //0x40200000//链接脚本定义了以下的段信息.globl_end_ofs_end_ofs:.quad_end - _start.globl_bss_start_ofs_bss_start_ofs:.quad__bss_start - _start.globl_bss_end_ofs_bss_end_ofs:.quad__bss_end - _start

对于_end_ofs,则根据_end-_start得到,而_end定义如下,也就是说,_end和__bss_start一样是个不占空间的字符数组变量,其存放在.__end段中

char _end[0] __attribute__((section(".__end")));

段定义,可以看到_end位于.__end段,而.__end段在.end中,由于和.image_copy_end一样,这两个段中的两个变量所占空间都为0,所以实际上这里_end的值和__image_copy_end的值是相等的。

.text : {. = ALIGN(8);*(.__image_copy_start)CPUDIR/start.o (.text*)*(.text*)} >.sram.rodata : {. = ALIGN(8);*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))} >.sram.data : {. = ALIGN(8);*(.data*)} >.sram.u_boot_list : {. = ALIGN(8);KEEP(*(SORT(.u_boot_list*)));} >.sram.image_copy_end : {. = ALIGN(8);*(.__image_copy_end)} >.sram.end : {. = ALIGN(8);*(.__end)} >.sram

reset函数

save_boot_params

stp指令存储一对 SIMD&FP 寄存器。该指令将一对 SIMD&FP 寄存器存储到内存中。用于存储的地址是根据基址寄存器值和立即偏移量计算得出的。(Depending on the settings in theCPACR_EL1,CPTR_EL2, andCPTR_EL3registers, and the current Security state and Exception level, an attempt to execute the instruction might be trapped.)

STP Xt1, Xt2, [Xn|SP], #imm ;

将Xt1和Xt2存入Xn|SP对应的地址内存中,然后,将Xn|SP的地址变更为Xn|SP + imm偏移量的新地址

首先开辟一段256byte的空白sram空间,将x1、x2寄存器的值保存到x0寄存器对应的地址内存(rom_pointer),然后将x0的地址变更为x0+16(这就是移动指针方便下面继续存储其他寄存器的值)。以此类推,保存x0到x30总计31个寄存器。由于是小端模式,保存完将sp指针指向x30寄存器即栈顶,保存sp指针的位置,指向x0+8位置。

.global rom_pointer//分配一个256byte的00000***000空间rom_pointer:.space 256adrx0, rom_pointerstpx1, x2, [x0], #16stpx3, x4, [x0], #16stpx5, x6, [x0], #16stpx7, x8, [x0], #16stpx9, x10, [x0], #16stpx11, x12, [x0], #16stpx13, x14, [x0], #16stpx15, x16, [x0], #16stpx17, x18, [x0], #16stpx19, x20, [x0], #16stpx21, x22, [x0], #16stpx23, x24, [x0], #16stpx25, x26, [x0], #16stpx27, x28, [x0], #16stpx29, x30, [x0], #16movx30, spstrx30, [x0], #8bsave_boot_params_ret

​ 保存结束,save_boot_params_ret跳转到_start重启系统。

save_boot_params_ret:#if CONFIG_POSITION_INDEPENDENT/* Verify that we're 4K aligned. *//*保存数据以后跳转到reset重新启动*/adrx0, _startandsx0, x0, #0xfffb.eq1f0:/** //失败,必须4K对齐* U-Boot needs to be loaded at a 4K aligned address.** We use ADRP and ADD to load some symbol addresses during startup.* The ADD uses an absolute (non pc-relative) lo12 relocation* thus requiring 4K alignment.*/wfib0b1://修复重定位的问题pie_fixup:adrx0, _start/* x0 <- Runtime value of _start */ldrx1, _TEXT_BASE/* x1 <- Linked value of _start */subsx9, x0, x1/* x9 <- Run-vs-link offset */beqpie_fixup_doneadrp x2, __rel_dyn_start/* x2 <- Runtime &__rel_dyn_start */addx2, x2, #:lo12:__rel_dyn_startadrp x3, __rel_dyn_end /* x3 <- Runtime &__rel_dyn_end */addx3, x3, #:lo12:__rel_dyn_endpie_fix_loop:ldpx0, x1, [x2], #16/* (x0, x1) <- (Link location, fixup) */ldrx4, [x2], #8/* x4 <- addend */cmpw1, #1027/* relative fixup? */bnepie_skip_reloc/* relative fix: store addend plus offset at dest location */addx0, x0, x9addx4, x4, x9strx4, [x0]pie_skip_reloc:cmpx2, x3b.lopie_fix_looppie_fixup_done:

reset:#ifdef CONFIG_SYS_RESET_SCTRLbl reset_sctrl#endif

首先根据是否配置CONFIG_SYS_RESET_SCTRL来决定是否需要跳转到reset_sctrl执行。一般的系统是不会使用这个定义的,但是我们来看看reset_sctrl里面做了什么。

reset_sctrl

首先调用switch_el宏,获取当前的异常等级,并跳转到相应的标签处。

#ifdef CONFIG_SYS_RESET_SCTRLreset_sctrl:switch_el x1, 3f, 2f, 1f3:mrsx0, sctlr_el3b0f2:mrsx0, sctlr_el2b0f1:mrsx0, sctlr_el10:ldrx1, =0xfdfffffaandx0, x0, x1switch_el x1, 6f, 5f, 4f6:msrsctlr_el3, x0b7f5:msrsctlr_el2, x0b7f4:msrsctlr_el1, x07:dsbsyisbb__asm_invalidate_tlb_allret#endif

加载CurrentEL寄存器的值到x1寄存器中,然后分别与0xc,0x8,0x4进行比较。x1=0xc则跳转到label3,x1=0x8则跳转到label2,x1=0x4则跳转到label1。CurrentEL寄存器的定义如下。

.macroswitch_el, xreg, el3_label, el2_label, el1_labelmrs\xreg, CurrentELcmp\xreg, 0xcb.eq\el3_labelcmp\xreg, 0x8b.eq\el2_labelcmp\xreg, 0x4b.eq\el1_label.endm

label定义如下

3:mrsx0, sctlr_el3b0f2:mrsx0, sctlr_el2b0f1:mrsx0, sctlr_el1

以异常等级EL3为例,此时跳转到label3。首先读取sctlr_el3寄存器数据到x0中,然后跳转到标号0:处。

sctlr_el3寄存器的EE位有两种值0和1,决定了EL3级别数据访问的大小端模式,也决定了EL3 在TLB进行虚实转换的stage1时的大小端格式。

WXN 位主要是用于控制可写内存区域是否是XN。当该bit置1时,在EL3 TLB转换表里所有的 writable 的 memory region 都会被视为 XNExecute-never ,也就意味着相应的 memory region 将无法执行 instructions,应该就是禁用了TLB。

I bit位则是用于控制i-cache的开关。

SA bit位则用与控制SP对齐检查,当置位1时,在EL3下使用load 或者store指令时,当用SP作为基址并且不是16字节对齐的话,则会产生一个SP非对齐异常。

C BIT:d-cache,数据cache使能位。

A BIT:对齐检查使能,

M BIT :是否使能MMU

我们继续往下走:

0:ldrx1, =0xfdfffffaandx0, x0, x1

在标号0中,将x0寄存器中保存的sctlr_el3里的值和x1寄存器中的值0xfdfffffa进行位与再写回到x0中,其实就是将bit2 和bit0还有bit 25 清0。再将x0寄存器的数据写回到sctlr_el3。此时的状态为:小端,MMU 关闭 i/d cache 都关闭(i cache bit控制位默认复位起来就是0,关闭icache的状态)。sctrl_el2和sctlr_el1的流程类似,此处无需赘述。

reset_sctrl的任务就完成了,由于涉及汇编和指令集比较难理解,所以我们下一节接着分析。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。