总目录

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:b    reset

_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:.quad    CONFIG_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 the CPACR_EL1, CPTR_EL2, and CPTR_EL3 registers, 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 256adr x0, rom_pointerstp  x1, x2, [x0], #16stp    x3, x4, [x0], #16stp    x5, x6, [x0], #16stp    x7, x8, [x0], #16stp    x9, x10, [x0], #16stp   x11, x12, [x0], #16stp  x13, x14, [x0], #16stp  x15, x16, [x0], #16stp  x17, x18, [x0], #16stp  x19, x20, [x0], #16stp  x21, x22, [x0], #16stp  x23, x24, [x0], #16stp  x25, x26, [x0], #16stp  x27, x28, [x0], #16stp  x29, x30, [x0], #16mov  x30, spstr  x30, [x0], #8b  save_boot_params_ret

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

save_boot_params_ret:#if CONFIG_POSITION_INDEPENDENT/* Verify that we're 4K aligned.  *//*保存数据以后跳转到reset重新启动*/adr   x0, _startands  x0, x0, #0xfffb.eq  1f
0:/** //失败,必须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.*/wfib    0b
1://修复重定位的问题
pie_fixup:adr   x0, _start      /* x0 <- Runtime value of _start */ldr   x1, _TEXT_BASE      /* x1 <- Linked value of _start */subs   x9, x0, x1      /* x9 <- Run-vs-link offset */beq    pie_fixup_doneadrp    x2, __rel_dyn_start     /* x2 <- Runtime &__rel_dyn_start */add     x2, x2, #:lo12:__rel_dyn_startadrp    x3, __rel_dyn_end       /* x3 <- Runtime &__rel_dyn_end */add     x3, x3, #:lo12:__rel_dyn_end
pie_fix_loop:ldp    x0, x1, [x2], #16   /* (x0, x1) <- (Link location, fixup) */ldr  x4, [x2], #8        /* x4 <- addend */cmp    w1, #1027       /* relative fixup? */bne    pie_skip_reloc/* relative fix: store addend plus offset at dest location */add  x0, x0, x9add   x4, x4, x9str   x4, [x0]
pie_skip_reloc:cmp  x2, x3b.lo  pie_fix_loop
pie_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_SCTRL
reset_sctrl:switch_el x1, 3f, 2f, 1f
3:mrs   x0, sctlr_el3b  0f
2:mrs   x0, sctlr_el2b  0f
1:mrs   x0, sctlr_el10:ldr  x1, =0xfdfffffaand x0, x0, x1switch_el x1, 6f, 5f, 4f
6:msr   sctlr_el3, x0b  7f
5:msr   sctlr_el2, x0b  7f
4:msr   sctlr_el1, x07:dsb  syisbb  __asm_invalidate_tlb_allret
#endif

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

.macro   switch_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:mrs    x0, sctlr_el3b  0f
2:mrs   x0, sctlr_el2b  0f
1:mrs   x0, 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:ldr    x1, =0xfdfffffaand x0, 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的任务就完成了,由于涉及汇编和指令集比较难理解,所以我们下一节接着分析。

Uboot启动分析--start.S启动分析(1)相关推荐

  1. uboot启动之BL2阶段的分析1:宏观分析

    对uboot启动的BL2阶段的主体代码的分析 BL2阶段从BL1阶段调用start_armboot函数完成远跳转至此阶段继续,start_armboot函数与其中调用的函数一起组成了我们BL2阶段的实 ...

  2. 开发板与虚拟机组网、uboot源码makefile分析、uboot安全启动与非安全启动方式、uboot源码配置与编译流程、制作TF启动盘

    开发板与虚拟机组网. 局面:开发板.PC(Ubuntu系统).网线直连PC:设置Ubuntu系统:1.设置桥接模式,桥接到PC的有线网卡上:2.手动配置IP V4的地址信息,注意和开发板保持在同一网段 ...

  3. 第4阶段——制作根文件系统之分析init_post()如何启动第1个程序(1)

    本章学习如何启动第一个应用程序 1.在前面的分析中我们了解到,在init进程中内核挂接到根文件系统之后,会开始启动第一个应用程序: kernel_init函数代码如下: static int __in ...

  4. 低温linux内核启动readl,Linux内核启动流程分析(一)

    很久以前分析的,一直在电脑的一个角落,今天发现贴出来和大家分享下.由于是word直接粘过来的有点乱,敬请谅解! S3C2410 Linux 2.6.35.7启动分析(第一阶段) 1.依据arch/ar ...

  5. 分析arm linux启动打印信息

    ===================================================== arm linux系统启动相关文章列表: arm linux系统启动流程 http://bl ...

  6. linux内核参数分析,linux内核启动第一阶段分析

    linux内核启动第一阶段分析 http://blog.csdn.net/aaronychen/article/details/2838341 本文的很多内容是参考了网上某位大侠的文章写的<&l ...

  7. 从linux启动到rootfs的挂载分析 https://blog.csdn.net/kevin_hcy/article/details/17663341

    从linux启动到rootfs的挂载分析   2012-05-02 15:50:49|  分类:默认分类 |  标签:|字号大中小 订阅 简单的来说,根文件系统包括虚拟根文件系统和真实根文件系统.在K ...

  8. 高通芯片刷机过程---分析理解(启动分析故障分析)

    高通芯片刷机过程---分析理解(启动分析故障分析) 参考链接:高通芯片刷机我的分析理解(启动分析故障分析)_sishibin的博客-CSDN博客_高通firehose引导文件   高通芯片手机是市面上 ...

  9. DM365启动之—RBL、UBL分析

    原文地址:http://arlen.opcom.blog.163.com/blog/static/33775037201182855648785/ 这段时间项目刚刚完成,下个项目还在等公司的安排,希望 ...

最新文章

  1. linux给普通用户sudo权限
  2. MATLAB作图方法与技巧(二)
  3. Flex-iframe在SWF中嵌入网页的组件(推荐)
  4. 基于COM的矢量图像控件VectorDraw
  5. spark学习:org.apache.spark.SparkException: A master URL must be set in your config
  6. dw显示云服务器的数据库,dw如何读取服务器数据库
  7. matlab中关于统计的函数
  8. Lucene 如何热备份
  9. 脑电数据预处理,eeglab预处理采集的SSVEP数据
  10. 14-循环队列实现(C语言)
  11. Word批量删除空白行
  12. 社交媒体运营_在社交媒体上确定投诉相关帖子
  13. 说一说android:persistent=true保活
  14. 哪些知乎收藏夹关注数超过一万?
  15. 用python写一元二次方程_使用Python解一元二次方程!
  16. 华为服务器开机显示选择一个选项,win10系统频繁出现“选择一个选项”界面的解决方法...
  17. 水果店开业活动,水果店开业活动策划
  18. 企业级监控系统zabbix---通过qqmail发送告警信息
  19. maven 程序包不存在 https://repo.maven.apache.org/maven2 was cac hed in the local repository
  20. 姚期智:为了中国计算机科学的腾飞(zz)

热门文章

  1. php生成订单 调微信支付,PHP后台微信支付使用方法
  2. html两个自然段怎么写,观后感分别每个自然段写什么
  3. 避免刷新页面时重复提交表单数据
  4. Docker---(7)Docker安装启动RabbitMQ
  5. 今天出门你查老黄历了吗?包括万年历在内的超多免费可用 API 推荐(一)
  6. Qt开发——网络编程UDP网络广播软件之服务器端
  7. 基于STM32的ESP8266模块控制多路继电器
  8. 如何基于 RISC-V CPU 集成一个 RISC-V SoC 呢?(下)
  9. JavaScript实现淘宝商品展示(鼠标放在小图片上,上面会出现相应的大图片)
  10. oracle怎么判断逻辑读,如何查看Oracle数据库物理读、逻辑读前10的sql?