启动流程分析

   在介绍了 Linux 内核之后,该花点时间来考虑 Linux 启动过程,也就是当一个Linux嵌入式系统上电的时候,在屏幕背后所发生的事情的顺序了。我们会从一台 Linux 台机的启动过程的高层概述开始,进而考虑启动的各个阶段。然后我们要通过用于 Zynqmp 的 Linux 的启动过程来看嵌入式 Linux 的启动过程

一、 引导 Zynq
  起点是上电时初始化,根据拨码开关引导ROM,定义FSBL 从哪个接口装载 ——JTAG、NAND Flash、NOR Flash、QSPI Flash 还是 SD 卡 ,读入引导头和给定的配置参数,验证了这个 FSBL 映像之后,把它从指定的接口装载到 OCM 中。一旦映像装入到 OCM 中,CPU的控制就转交给 FSBL了
  

二、启动流程:
  PMU电源管理单元 CSU安全启动管理管理单元(加密安全启动和非加密非安全启动)
  上电PMU释放,CSU复位
  读取拨码开关,获取启动模式,从相应的内存中获取启动文件
  从Boot image里面获取Boot header信息
  验证FSBL身份信息及是否加密
  将FSBL加载到OCM中
  确认相关的配置文件是否PS和PL相匹配
  加载RPU和APU
   在这里插入图片描述

引导过程
  ①、电源管理单元(PMU)执行PMU ROM固化程序来初始化系统,重置和唤醒相关的进程,
  ②、根据拨码开关从相应内存位置将引导加载程序(PS的FSBL代码)加载到芯片RAM (OCM)中并执行、
  ③、运行ATF之后启动uboot第一阶段引导程序初始化内存等基础硬件,将uboot第二阶段和kernel加载到DDR中
  ④、从内存DDR中加载运行uboot第二阶段初始化相关设备,配置kernel启动的环境并引导kernel从而启动rootfs
  在这里插入图片描述
  在这里插入图片描述

  FSBL负责安全的加载arm、固件ATF、u-boot和PL端的bistream文件,EL3上执行的FSBL负责的所有安全检查,以及分区的实际身份验证或者解密, PS 用了可编程逻辑中的硬件模块来做 AES-256 和 HMAC(SHA-256)解密和认证,在安全引导过程中 PL 必须被加电。芯片加密认证是用户可选择的,或者是用片内的 eFUSE 单元,或者是用带有备用电池的 RAM (Battery Backup RAM,BBRAM)。

三、启动模式
  将FSBL、U-Boot、A53 Image(.elf)、KEY、.bif文件通过Bootgen制作成Boot.bin文件,将它同kernel Image、DeviceTree file文件放入SD卡的Fat32格式的分区中,文件系统放入SD卡另外一个分区EXT4中,片上Rom程序根据拨码开关,选择从SD卡加载启动文件(安全启动模式)
  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述
  先捋一下流程,FSBL取代传统的uboot第一阶段SPL,当执行完成之后我们需要调用u-boot.lds链接整个uboot文件,uboot文件的入口start.S

四、FSBL启动流程
  1、在zynq上运行程序的时候,加载过程中肯定需要用到一个文件,那就是fsbl,fsbl的全称为first stage boot loader,从字面上就能够看出这是zynq启动第一阶段的加载程序,经过了fsbl这一阶段,后面系统才能够运行裸奔程序或者是引导操作系统的u-boot。启动过程如下图:
    在这里插入图片描述

  2、在上图中,Boot Rom是直接固化在zynq硬件中的,开发者无法更改,fsbl.elf可以在Xilinx的SDK中进行修改。打开z_dts/zynqmp_fsbl/zynqmp_fsbl_bsp/
psu_cortexa53_0/libsrc/standalone_v7_1/src/asm_vectors.S文件夹,里面有一个asm_vector.S文件,这个文件声明了一个代码段,位于地址0处。开机之后,PS自动执行地址0处的指令,其第一句话就是一个跳转:B _boot。如下:

┌───────────────────────┐
│     向量表入口          │
│ (0x00000000开始)       │
└──────────┬────────────┘
           │
           ▼
┌───────────────────────┐
│ 异常类型判断            │
│ (通过向量表偏移跳转)     │
└──────────┬────────────┘
           │
           ├────────────────┬─────────────┬──────────────┬────────────────┐
           ▼                ▼             ▼              ▼                ▼
┌───────────────────┐ ┌───────────┐ ┌───────────┐  ┌─────────────┐  ┌────────────┐
│      Reset        │ │ Undefined │ │  SVC调用   │ │PrefetchAbort│   │ DataAbort  │
│    (跳转_boot)     │ │ 异常处理   │ │ 处理       │ │ 处理         │   │ 处理       │
└───────────────────┘ └─────┬─────┘ └─────┬─────┘ └─────┬────────┘  └─────┬──────┘
           │                │             │             │                 │
           ├────────────────┴─────────────┴─────────────┴─────────────────┘
           ▼
┌───────────────────────┐
│   IRQ/FIQ中断处理      │
└──────────┬────────────┘
           │
           ▼
┌───────────────────────┐
│ 公共处理流程            │
├───────────────────────┤
│ 1. 保存现场            │
│   (r0-r3,r12,lr入栈)  │
├───────────────────────┤
│ 2. FPU状态保存         │
│   (如果启用FPU)        │
├───────────────────────┤
│ 3. 调用C处理函数        │
│   (如IRQInterrupt)    │
├───────────────────────┤
│ 4. FPU状态恢复         │
│   (如果启用FPU)        │
├───────────────────────┤
│ 5. 恢复现场            │
│   (寄存器出栈)          │
├───────────────────────┤
│ 6. 异常返回地址调整      │
│   (PC ← LR - 偏移量)   │
└───────────────────────┘

关键特性说明:

异常向量表结构:

  8个32位入口分别对应:

    Reset

    Undefined Instruction

    SVC

    Prefetch Abort

    Data Abort

    Reserved

    IRQ

    FIQ

  在这里插入图片描述

  3、将vitis.zip解压到当前目录并创建工程ctags –R
  vim ./z_dts/zynqmp_fsbl/zynqmp_fsbl_bsp/psu_cortexa53_0/libsrc/standalone_v7_1/src/asm_vectors.S
  在这里插入图片描述
  跳转到boot.S里面,初始化处理器的各种模式,初始化C语言执行的环境
  在这里插入图片描述
  使能I cache、MMU、SP堆栈之后跳入start
  在这里插入图片描述
  清bss,构造全局结构体,重启定时器之后跳转到main函数开始执行
  在这里插入图片描述
  跳入./z_dts/zynqmp_fsbl/xfsbl_main.c主要做下面四个阶段
  在这里插入图片描述
4.1FsblStatus = XFsbl_Initialize(&FsblInstance);
  4.1a、得到复位的原因
  FsblInstancePtr - > ResetReason = XFsbl_GetResetReason ();
  
  4.1b、系统初始化
  Status = XFsbl_SystemInit(FsblInstancePtr);
    ——》Status = XFsbl_HookPsuInit();
    ——》Status = (u32)psu_init();
    调用了psu_init()函数,该函数根据PS的类型进行MIO,PLL,CLOCK,DDR一系列参数的设定
    在这里插入图片描述
  4.1c、处理器初始化
  Status = XFsbl_ProcessorInit (FsblInstancePtr);

  4.1d、DDR初始化
  Status = XFsbl_DdrEccInit();

  4.1e、板初始化
  Status = XFsbl_BoardInit();

  4.1f、重置验证
  Status = XFsbl_ResetValidation();

  4.2、引导设备安装和image验证
  u32 XFsbl_BootDeviceInitAndValidate(XFsblPs * FsblInstancePtr)
  
  4.2a 主要引导设备初始化
  Status = XFsbl_PrimaryBootDeviceInit(FsblInstancePtr);
  在这里插入图片描述

  ./z_dts/zynqp_fsbl/xfsbl_initialization.c中switch描述怎么去不同引导设备获取FSBL
  在这里插入图片描述

  读取引导模式的值,即拨码开关选择的启动模式
  在这里插入图片描述

  根据不同的引导模式选择不同的操作方式,例如SD卡模式启动,通过XFsbl_SdInit初始化SD卡和XFsbl_SdCopy拷贝SD卡中的数据内容
  在这里插入图片描述

  先看XFsbl_SdInit函数
  ①先通过XFsbl_MakeSdFileName 函数将SD卡中的BOOT.BIN文件名通过字符串指针传入boot_file中
  ②在通过f_open去打开BOOT.BIN
  在这里插入图片描述

  XFsbl_SdCopy函数
  ①通过f_read将文件读到DestAddress中
  在这里插入图片描述

  这里根据启动设备读取FSBL中的文件到OCM中,并验证eFUSE RSA
  在这里插入图片描述
  4.2b header验证
  Status = XFsbl_ValidateHeader(FsblInstancePtr);
  
   4.2c 二次启动设备初始化
   FsblInstancePtr - > SecondaryBootDevice =FsblInstancePtr - >ImageHeader.ImageHeaderTable.PartitionPresentDevice;

4.3、加载并验证分区
    FsblStatus = XFsbl_PartitionLoad(&FsblInstance,PartitionNum);
  4.3a 分区头验证
    Status = XFsbl_PartitionHeaderValidation(FsblInstancePtr, PartitionNum)
  4.3b 分区复制
    Status = XFsbl_PartitionCopy(FsblInstancePtr, PartitionNum);
4.4、 执行完FSBL,往uboot第二阶段切换
  FsblStatus = XFsbl_Handoff(&FsblInstance, PartitionNum, EarlyHandoff);
  恢复SD卡检测信号
  XFsbl_Out32(IOU_SLCR_SD_CDN_CTRL, 0X0U);
  删除PS-PL隔离以允许u-boot和linux访问PL
   在这里插入图片描述
  刷新L1和L2缓存,禁用数据缓存
  Xil_DCacheDisable();
  4.4a PM 初始化
  Status = XFsbl_PmInit();
  
  4.4b 配置
   Status = XFsbl_ProtectionConfig();
  4.4c 切换到CPU
  Status = XFsbl_HookBeforeHandoff(EarlyHandoff);

五、uboot启动流程
  上面的FSBL取代传统的SPL,运行了uboot在ocm里面第一阶段所需要做的工作,初始化C运行环境将uboot加载到DDR中并运行,
  1、先运行uboot中的链接脚本arch/arm/cpu/armv8/u-boot.lds,链接起始文件start.S的起始代码段
  在这里插入图片描述

  2、进入arch\arm\cpu\armv8\start.S汇编文件中
  提到了_start符号是整个程序的入口,链接器在链接时会查找目标文件中的_start符号代表的地址,把它设置为整个程序的入口地址。并且我们也知道start.S的代码段也是位于整个spl-uboot代码段最开始的位置,而_start符号对于Armv8架构来说位于则位于 arch\arm\cpu\armv8\start.S文件内 ,接下来我们将重点分析start.S都做了些什么。
  上面这部分内容注释的很清楚,对于某些芯片需要特殊的一些初始配置的话,可以通过配置CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK并执行相应boot0.h中的代码来进行一些boot之前的操作。对于绝大多数CPU来说,这部分都是不需要的。
  在这里插入图片描述

  3、_start 符号后紧跟的第一条指令指令为跳转指令,跳转到reset标号处,暂时接下往下看。
随后进行2^3 也就是8字节对齐。并声明若干个全局符号,这些符号的地址也是位于代码段中,后续反汇编便可以看到。我们先看下
_TEXT_BASE,该符号地址处存放的是一个8字节(.quad定义的是一个8字节的数据)的数 CONFIG_SYS_TEXT_BASE, 而CONFIG_SYS_TEXT_BASE对于zynqmp cpu来说定义如下:
  在这里插入图片描述
  在这里插入图片描述

  接下来重点分析上面提到的b reset后执行的代码:
  在这里插入图片描述

  跟进save_boot_params里面
  在这里插入图片描述

  CONFIG_POSITION_INDEPENDENT和CONFIG_SYS_RESET_SCTRL都没定义,这里不执行,往下走
  在这里插入图片描述

  继续往下走,最后根进_main中
  在这里插入图片描述

  _main在arch/arm/lib/crto_64.s中,主要设置初始的C运行时环境并调用board_init_f(0)
前面判断都是不执行,直接运行CONFIG_SYS_INIT_SP_ADDR
  在这里插入图片描述

  uboot链接基地址在这里定义为0x8000000
  在这里插入图片描述

  设置一下16字节对齐及gd全局数据结构体之外直接调用board_init_f
  在这里插入图片描述

  board_init_f在common/board_f.c中,主要功能是设置初始环境,这个环境只提供了一个堆栈和一个存储的地方
  在这里插入图片描述

  继续往下走,我们进入init_sequence_f这个函数指针数组中,运行init_sequense_f里得函数指针进行uboot前半段初始化动作
  在这里插入图片描述

  继续往下走,我们可以看到这个函数指针数组里面有个show_board_info
  在这里插入图片描述

  继续往下走,先打印Model在进入checkboard函数中打印Board

  在这里插入图片描述
  在这里插入图片描述

  继续往下看,init_sequence_f中有show_dram_config中打印DRAM:4 GiB
  在这里插入图片描述

  继续往下看,在board/xilinx/zynqmp/zynqmp.c文件board_early_init_f函数打印PMUFW:
  在这里插入图片描述
  在这里插入图片描述

  执行完board_init_f后返回执行,b relocate_code代码重定向
  在这里插入图片描述

  进入arch/arm/lib/relocate_64.S中,拷贝代码到ARM的内存中去
  在这里插入图片描述

  设置最终完整的环境,继续往下走,跳进board_init_r中
  在这里插入图片描述

  继续往下走进入common/board_r.c中的board_init_r函数中,CONFIG_NEEDS_MANUAL_RELOC没有定义,运行initcall_run_list函数,调用init_sequense_r里得函数指针进行部分硬件得初始化动作,跟进去往下走
  在这里插入图片描述

  我们在init_sequence_r函数指针数组的每个成员中添加打印logo
  在这里插入图片描述

  保存退出,运行编译脚本,进行重新编译
  在这里插入图片描述

  将BOOT.bin装载到SD卡中,上电查看logo
  在这里插入图片描述

  继续往下走执行在U-Boot初始化并准备好处理命令之后,运行run_main_loop
  在这里插入图片描述

  继续往下走,进入到main_loop函数中
  在这里插入图片描述

  bootstage_mark_name函数调用了show_boot_progress,利用它显示启动进程(progress),此处为空函数
  在这里插入图片描述
  在这里插入图片描述
  在这里插入图片描述

  cli_init用来初始化hush shell使用的一些变量
  在这里插入图片描述

  函数从环境变量中获取"preboot"的定义,该变量包含了一些预启动命令,一般环境变量中不包含该项配置。
  在这里插入图片描述

  一般定义在每块板卡自己的头文件中,我的在u-boot-xlnx/include/configs/xilinx_zynqmp.h文件中,如果是sd卡启动preboot就是sdboot
  在这里插入图片描述

  网络相关的设备定义
  在这里插入图片描述

  bootdelay_process从环境变量中取出"bootdelay"和"bootcmd"的配置值
  将取出的"bootdelay"配置值转换成整数,赋值给全局变量stored_bootdelay 最后返回"bootcmd"的配置值
  bootdelay为u-boot的启动延时计数值,计数期间内如无用户按键输入干预,那么将执行"bootcmd"配置中的命令
  在这里插入图片描述

  autoboot_command,倒数计时实现,计时到-1前,按下了执行menu_main()
  在这里插入图片描述

  进入启动菜单界面,q退出菜单界面,进入uboot操作界面
  在这里插入图片描述

  若没有按下通过run_command_list运行s环境变量
  在这里插入图片描述

  最后在arch/arm/lib/bootm.c中announce_and_cleanup函数是uboot阶段的最后时刻,后面将Image解压到内存里面去
  在这里插入图片描述
  在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值