[X]关闭

[米联客-XILINX-H3_CZ08_7100] LINUX基础篇连载-10 启动流程分析

文档创建者:LINUX课程
浏览次数:346
最后更新:2024-09-09
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 2_LINUX应用开发
本帖最后由 LINUX课程 于 2024-9-9 14:07 编辑

软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用XILINX Z7/ZU系列FPGA
登录“米联客”FPGA社区-www.uisrc.com视频课程、答疑解惑!

1 启动流程
Zynq的启动步骤,可以大致分为BootROM、FSBL、Uboot、Linux系统这四大板块,这四个环节环环相扣。流程图如下所示:
image.jpg
首先,电源管理单元(PMU)执行PMU ROM固化程序来初始化系统,重置和唤醒相关的进程。
接着,根据拨码开关从相应内存位置将引导加载程序(PS的FSBL代码)加载到芯片RAM (OCM)中并执行。
然后,运行ATF之后启动uboot第一阶段引导程序初始化内存等基础硬件,将uboot第二阶段和kernel加载到DDR中。
最后,从内存DDR中加载运行uboot第二阶段初始化相关设备,配置kernel启动的环境并引导kernel从而启动rootfs。
2 步骤分析
2.1 阶段0:BootROM
首先,boot这个词说明了这是一个启动程序,而ROM是Read-Only Memory的缩写,即只读存储。但是现在好多电子产品说自己ROM多大多大,为什么也可以写呢?这个只是叫法上的习惯罢了,其实这类产品的存储设备已经不能叫ROM了,但是我们今天要讲的BootROM是一个货真价实的ROM,因为这是固化在ZYNQ内部的程序。
正是因为它位置固定,不可擦写,所以每次上电才能从它开始运行。每次一上电,ARM核心就会前往BootROM完成一些基本的准备工作,就这样一个最开始的程序,需要完成以下几件事情:
  • 释放PMU,复位CSU。
  • 读取拨码开关,获取启动模式,从相应的内存中获取启动文件。
  • 从Boot image里面获取Boot Header信息。
以下图为例,芯片上一般会提供有几个固定的引脚来作为模式。我们通过GND低电平或者3.3V高电平来告知BootROM不同的启动模式。
image.jpg
而芯片手册上也会给出对应的电平所代表的含义:
image.jpg
一般我们采用JTAG、QSPI、SD卡、eMMC、USB这几种方式来启动。
在读取完拨码开关的值之前,BootROM也会完成对SD卡,eMMC等设备的初始化,以确保告诉ARM准确的启动位置后,ARM可以成功访问并使用这些外设。然后便会从指定的地方读取启动镜像,也就是BOOT.bin文件,将其加载到OCM中。OCM是On Chip Memory的缩写,即片上内存。到这里,BootROM的任务就基本完成了。
在上一段中,我们讲述了BootROM读取启动信息并写镜像到OCM中,在加载到OCM的过程,需要分为安全启动与不安全启动两种:
安全启动流程
在安全启动模式下,PMU释放CSU,并进入PMU服务器模式,同时在此模式下它监视电源。PMU释放CSU之后,CSU会检查以确定FSBL或用户应用程序是否需要身份验证。
CSU会执行以下操作:
  • 执行身份验证检查,只有在身份验证检查通过后才继续进行。然后检查映像中是否有任何加密分区。
  • 如果CSU检测到加密的分区,则CSU执行解密并将FSBL加载到OCM中。
非安全启动流程
在非安全启动模式下,PMU释放CSU,并进入PMU服务器模式,同时在该模式下监视电源。 在PMU释放CSU之后,将FSBL加载到OCM中。此时FSBL在APU或RPU上运行。FSBL引导APU / RPU和ATF运行。接着U-Boot和Linux在APU上运行。一些其他启动配置允许RPU完全独立于APU启动和运行,反之亦然。
  • 在APU上,FSBL释放ATF之后将执行ATF。ATF释放第二阶段的引导加载程序例如U-boot,它将执行并加载OS(例如Linux)。
  • 在RPU上,FSBL移交权限给软件应用程序。
  • Linux依次加载可执行软件。
2.2 阶段1:FSBL
从上一节我们就了解到BootROM会将执行权限交给FSBL。FSBL的全名为First Stage Boot Loader,即第一阶段引导加载程序。FSBL的任务比较重要,它需要完成以下的工作:
  • 初始化PS端。
  • 使用bit文件配置PL端。
  • 加载Uboot到内存中。
  • 移交执行权限给Uboot。
以下为fsbl的启动流程:
image.jpg
这个阶段需要完成一系列的初始化操作,首先会初始化PS端的内存与MIO接口等,然后读取bit文件配置好PL端,值得注意的是PL端需要在FSBL的阶段配置好,否则是无法直接配置的。接着加载Uboot到内存中,最后ARM会跳转到内存中执行Uboot程序。
2.3 阶段2:Uboot
接下来就是熟悉的ARM开发的流程了,Uboot最主要的功能就是将内核写入内存中,然后将执行权限移交给内核,但是Uboot需要完成的任务并不仅限于此:
  • 初始化运行环境。
  • 初始化内存。
  • 检查内存映射。
  • 将内核写入内存。
  • 设置启动参数。
  • 调用内核。
等内核起来后,Uboot就完成了它的工作,紧接着就是内核去完成自己的工作。
3 代码实例
因为FSBL的作用是引导SSBL,所以引导裸机和引导Uboot的FSBL没有什么区别,因此我们直接从Vitis查看FSBL的相关源码。这里使用的源码文件是由上一章生成的。
打开查看Cortex A53处理器的初始向量表,这里进行了一些初始化操作,其路径为zu_base\zynqmp_fsbl\zynqmp_fsbl_bsp\psu_cortexa53_0\libsrc\standalone_v7_3\src\asm_vectors.S
image.jpg
在向量表中可以看到,启动程序为_boot,为了查看其源码,我们需要找到_boot的实现,_boot的实现在boot.S文件中,打开同目录下的boot.S文件:
找到_boot,可以看到其首先在初始化处理器的各种模式,初始化C语言的执行环境:
image.jpg
这里会使能I cache、SP堆栈、caches、MMU,然后跳转至_startup函数启动。
image.jpg
同样的方法,我们需要找到_startup的实现,这个函数在同目录下的xil-crt0.S中,打开xil-crt0.S文件并找到_startup:
image.jpg
在_startup函数中,对bss进行了一系列的操作,然后清bss,构造全局结构体,重启定时器之后跳转到main函数开始执行。
main函数的位置为zu_base\zynqmp_fsbl\xfsbl_main.c,可以看到main函数的入口:
image.jpg
main函数会经历以下四个主要阶段:
  • 各种初始化。
  • 引导设备安装和image验证。
  • 加载并验证分区。
  • 执行完FSBL,往uboot第二阶段切换。
这四个阶段的详细流程如下:
各种初始化
image.jpg
这个函数包括了诸多软硬件的初始化操作,非常清楚地看到在switch中属于XFSBL_STAGE1也就是第一阶段,在其运行成功后,才会跳转到第二阶段继续执行,其位置为zu_base\zynqmp_fsbl\xfsbl_initialization.c:
这个函数的第一步便是获取复位的原因。
image.jpg
紧接着是系统初始化:
image.jpg
在这个函数的注释中,调用了psu_init()这个函数,该函数根据PS的类型进行MIO,PLL,CLOCK,DDR一系列参数的设定。
image.jpg
处理器初始化:
image.jpg
DDR初始化:
image.jpg
板卡初始化:
image.jpg
重置验证:
image.jpg
如果这些初始化操作均成功了,到这里整个初始化工作便可以告一段落了,接下来要运行第二阶段,也就是引导设备安装和image验证。
引导设备安装和image验证
image.jpg
这一段代码比较有趣,逻辑也比较清晰:首先运行初始化函数,然后根据返回参数来判断启动方式,分为错误、JTAG和普通启动模式。其中如果引导发现是JTAG模式就会直接跳转到第四步,这是因为第三步的任务是加载分区,而JTAG模式是不需要的。了解的初始化函数的返回值,我们再去查看其实现,同样还是在xfsbl_initialization.c文件中:
image.jpg
第一步为获取模式开关的参数,查看XFsbl_PrimaryBootDeviceInit函数:
image.jpg
其中一段就展示了获取模式开关的代码,注意此处不是读取模式开关,因为读取是由BootROM完成的,FSBL只是获取了BootROM的参数。这里以emmc启动方式为例,在读取到为XFSBL_EMMC_BOOT_MODE这个参数后,会进行如下的操作:
image.jpg
先是初始化设备(这里是eMMC),再从设备中读取BOOT.bin文件,最后关闭文件。
上一步完成后,紧接着就是读取验证头:
image.jpg
最后是设置第二启动设备,如果有第二启动设备,还要对其进行初始化操作:
image.jpg
加载并验证分区(可选)
部分启动方式可以跳过此部分,比如JTAG模式。
image.jpg
第三部分也是如出一辙,先加载分区,分为成功与失败两个情况,成功的情况下会继续验证分区。我们先来看XFsbl_PartitionLoad这个函数,它的定义在同目录xfsbl_partition_load.c这个文件里:
image.jpg
以上为XFsbl_PartitionLoad的核心代码,分为三步,先验证分区头,查验是不是对应的型号,如果是对应的型号则复制分区内容,最后是分区的验证。
回到xfsbl_main.c文件中,第三步还会对所有分区进行一次验证,保证所有分区均已加载完成:
image.jpg
这一步完成后,便会跳转至下个阶段。
转移执行权限
在第四阶段中,同样也是先运行移交权限的XFsbl_Handoff函数,然后处理各种返回的情况:
image.jpg
分为三种情况,为:分区未加载完全,会跳转到第三步继续执行。继续移交权限,主要出现在一个应用执行完,需要运行下一个应用时。失败的情况,移交权限失败。还有一种情况就如同注释写的那样,应该永远也不会被执行。
看完整体的构架,接下来要看看XFsbl_Handoff的定义,了解一下移交执行权限究竟经过了哪些步骤,这个函数的定义位于xfsbl_handoff.c文件中:
恢复SD卡检测信号:
image.jpg
解除PS-PL隔离以允许u-boot和linux访问PL:
image.jpg
刷新L1和L2数据缓存,禁用数据缓存
image.jpg
PM初始化:
image.jpg
保护配置:
image.jpg
切换到CPU运行:
image.jpg
到这里,FSBL阶段的工作全部完成,接下来就由Uboot来继续操作。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则