Xilinx ZYNQ FSBL解读:LoadBootImage()
篇首
最近突发奇想,Xilinx 的集成开发环境已经很好了,很多必要的代码都直接生成了,这给开发者带来了巨大便利的同时,也让人错过了很多代码的精彩,可能有很多人用了很多年了,都还无法清楚的理解其中过程。博主准备以FSBL为例,与大家深入探讨一番,从而加深对ZYNQ的加载过程的理解,以便大家作出更精彩的设计!
LoadBootImage() 解读
本文以Zynq7000 FSBL工程代码为基础,分析启动流程核心函数 L o a d B o o t I m a g e ( ) LoadBootImage() LoadBootImage()的执行逻辑与关键技术细节。
一、函数调用框架
int LoadBootImage(void) {FsblHookBeforeBitstreamDdr(); // 钩子函数Status = XFsbl_LoadPartitions(...); // 核心加载FsblHookBeforeHandoff(); // 移交前预处理return Status;
}
二、 函数执行全流程分解
** 函数入口与预处理**
int LoadBootImage(void) {u32 Status = XFSBL_SUCCESS;XTime tStart, tEnd; // 64位计时器(若启用性能分析)
- 硬件依赖:
- 依赖
psu_init.c
完成的PS端基础初始化(时钟、MIO、SLCR锁等) - DDR物理层已通过
Xil_DDRInit()
完成训练(psu_ddr_phyinit.c
)
- 依赖
** F s b l H o o k B e f o r e B i t s t r e a m D d r ( ) FsblHookBeforeBitstreamDdr() FsblHookBeforeBitstreamDdr() 钩子函数**
#ifdef FSBL_PERFXTime_GetTime(&tStart); // 记录TSC起始值(AXI Timer 0)
#endif
/* 用户自定义扩展点:可插入DDR重配置代码 */
- 关键寄存器操作:
- DDRC控制:通过
Xil_Out32(0xFD070000, 0x00040010)
设置DDRC_ADDRMAP0
调整地址映射 - OCM重映射:关闭OCM缓存(
SLCR.OCM_CFG
寄存器位3置1)
- DDRC控制:通过
X F s b l L o a d P a r t i t i o n s ( ) XFsbl_LoadPartitions() XFsblLoadPartitions() 核心加载
阶段1:Boot Header解析
XFsblPs_BootHdr Header;
XFsbl_CheckBootHeader(ImageAddr, &Header); // 从QSPI/NAND读取头部
- 头部结构体(
xfsbl_ps_boothdr.h
):typedef struct {u32 ImageID; // 魔数0xAA995566u32 NumPartitions; // 分区总数(含PL比特流+应用)u32 AuthType; // 加密类型:0=None, 1=RSA-2048u32 Checksum; // 头部的CRC32校验// ... 其他字段(分区表偏移、证书偏移等) } XFsblPs_BootHdr;
阶段2:安全认证(以RSA-2048为例)
XSecure_Sha3Init(&Sha3Instance); // 初始化SHA-3引擎
XSecure_Sha3Update(&Sha3Instance, (u8*)ImageAddr, Header.HashLength);
XSecure_Sha3Final(&Sha3Instance, CalculatedHash); // 计算哈希
XSecure_VerifySignature(CalculatedHash, StoredSignature); // RSA验签
- 硬件加速:
- 使用PS内置的CSU模块(Crypto Subsystem)
- RSA密钥存储在eFUSE或BBRAM中(通过
XSecure_GetEfuseKek()
读取)
阶段3:分区加载循环
for (u8 i=0; i<Header.NumPartitions; i++) {XFsblPs_PartitionHdr PartHdr;XFsbl_ReadPartitionHdr(ImageAddr + Offset, &PartHdr);if (PartHdr.Attr & PART_ATTR_PL) { // PL比特流分区XFsbl_LoadPlBitstream(PartHdr.LoadAddr, PartHdr.Size);} else { // PS应用程序分区XFsbl_LoadElf(PartHdr.LoadAddr, PartHdr.Size); // ELF解析}
}
- 关键操作细节:
- PL加载:通过DevCfg接口(
XDcfg_CfgInitialize()
)写入PCAP - ELF加载:解析Program Headers,使用
Xil_Out32()
逐段写入DDR - 地址对齐:通过
XLAT_FSBL_TABLE
处理非32位对齐访问(触发Data Abort时自动转换)
- PL加载:通过DevCfg接口(
F s b l H o o k B e f o r e H a n d o f f ( ) FsblHookBeforeHandoff() FsblHookBeforeHandoff() 移交前处理
Xil_DCacheFlush(); // 数据缓存刷新(确保DDR数据一致性)
Xil_Out32(CRL_APB_BASE + 0x24, 0x01000F00); // 配置时钟分频
- 寄存器详解:
- CRL_APB (0xFF5E0024): 设置
RPLL_CTRL
分频系数(CPU=1.3GHz, DDR=1066MHz) - SLCR_UNLOCK (0xF8000008): 写入
0xDF0D
解锁保护寄存器
- CRL_APB (0xFF5E0024): 设置
三、关键子函数解析
-
F s b l H o o k B e f o r e B i t s t r e a m D d r ( ) FsblHookBeforeBitstreamDdr() FsblHookBeforeBitstreamDdr()
- 作用:DDR初始化前的预处理钩子
- 执行内容:
#ifdef FSBL_PERF XTime_GetTime(&tStart); // 性能计数器启动 #endif
-
X F s b l L o a d P a r t i t i o n s ( ) XFsbl_LoadPartitions() XFsblLoadPartitions()
- 流程分解:
- X F s b l C h e c k B o o t H e a d e r ( ) XFsbl_CheckBootHeader() XFsblCheckBootHeader()
验证BIN文件头结构(含 s i z e o f ( X F s b l P s B o o t H d r ) sizeof(XFsblPs_BootHdr) sizeof(XFsblPsBootHdr)) - X F s b l A u t h e n t i c a t i o n ( ) XFsbl_Authentication() XFsblAuthentication()
执行RSA-2048签名验证(通过 X S e c u r e S h a 3 I n i t ( ) XSecure_Sha3Init() XSecureSha3Init()等加密API) - 分区加载循环
遍历分区表加载:for(u8 PartNum=0; PartNum<Header.NumPartitions; PartNum++){XFsbl_LoadPartition(...); // 加载单个分区#ifdef FSBL_DEBUGxil_printf("Partition %d Loaded\r\n", PartNum);#endif }
- X F s b l C h e c k B o o t H e a d e r ( ) XFsbl_CheckBootHeader() XFsblCheckBootHeader()
- 流程分解:
-
F s b l H o o k B e f o r e H a n d o f f ( ) FsblHookBeforeHandoff() FsblHookBeforeHandoff()
- 执行DDR刷新操作( X i l D C a c h e F l u s h ( ) Xil_DCacheFlush() XilDCacheFlush())
- 配置时钟分频器(通过 X i l O u t 32 ( ) Xil_Out32() XilOut32()写CRL_APB寄存器)
四、核心宏定义
- $FSBL_DEBUG
控制调试输出(默认关闭) - KaTeX parse error: Double subscript at position 15: XPAR_PSU_DDR_0_̲S_AXI_BASEADDR
DDR控制器基地址宏(值 0 x 00100000 0x00100000 0x00100000) - X L A T F S B L T A B L E XLAT_FSBL_TABLE XLATFSBLTABLE
地址转换表(处理非对齐访问)
五、执行流程图
初始化硬件 → 验证头部 ↓ ↓ DDR预处理 → 加载分区 ↘ ↓ 移交控制权 \begin{array}{ccc} \text{初始化硬件} & \rightarrow & \text{验证头部} \\ \downarrow & & \downarrow \\ \text{DDR预处理} & \rightarrow & \text{加载分区} \\ & \searrow & \downarrow \\ & & \text{移交控制权} \end{array} 初始化硬件↓DDR预处理→→↘验证头部↓加载分区↓移交控制权
六、 关键数据流与硬件交互
数据加载路径
QSPI Flash → AXI Quad-SPI控制器 OCM缓存 → DMA DDR3 \text{QSPI Flash} \xrightarrow{\text{AXI Quad-SPI控制器}} \text{OCM缓存} \xrightarrow{\text{DMA}} \text{DDR3} QSPI FlashAXI Quad-SPI控制器OCM缓存DMADDR3
- 性能优化:
- 启用DMA传输(
XQspiPs_DmaTransfer()
) - 使用线性突发模式(QSPI配置为DDR模式,时钟速率83MHz)
- 启用DMA传输(
安全认证流程
原始镜像 → SHA-3/384 哈希值 哈希值 → RSA-2048签名 验签结果 \begin{aligned} &\text{原始镜像} \xrightarrow{\text{SHA-3/384}} \text{哈希值} \\ &\text{哈希值} \xrightarrow{\text{RSA-2048签名}} \text{验签结果} \end{aligned} 原始镜像SHA-3/384哈希值哈希值RSA-2048签名验签结果
- 抗攻击设计:
- 哈希计算前会清空CSU的密钥缓存(
XSecure_CsuAesKcvClear()
) - 签名失败触发安全锁定(通过
XSecure_SetTamperConfig()
)
- 哈希计算前会清空CSU的密钥缓存(
七、调试与错误处理
调试宏启用
#define FSBL_DEBUG // 启用调试输出
- 典型输出:
XFsbl_Debug: Partition 0 Loaded at 0x00100000 (Size 1MB) XFsbl_Debug: PL Bitstream CRC Check Passed
** 错误码定义**
#define XFSBL_ERROR_BOOTHEADER 0x1000 // 头部校验失败
#define XFSBL_ERROR_AUTHFAIL 0x1001 // RSA验签错误
#define XFSBL_ERROR_PLLLOCK 0x1002 // 时钟锁相环失锁
- 错误处理:
- 记录错误到PMU全局状态寄存器(
XFsbl_WriteReg(PMU_GLOBAL_GLOB_GEN_STORAGE, errCode)
) - 触发系统复位(
XFsbl_FallbackReset()
)
- 记录错误到PMU全局状态寄存器(
**八、 总结 **
L o a d B o o t I m a g e ( ) LoadBootImage() LoadBootImage()作为Zynq7000启动链的核心,其执行涵盖硬件初始化、安全认证、多阶段加载三大模块。函数首先通过 F s b l H o o k B e f o r e B i t s t r e a m D d r ( ) FsblHookBeforeBitstreamDdr() FsblHookBeforeBitstreamDdr()完成DDR时序微调与性能监控启动,随后 X F s b l L o a d P a r t i t i o n s ( ) XFsbl_LoadPartitions() XFsblLoadPartitions()深度解析Boot Header结构,利用CSU硬件模块实现RSA-2048/SHA-3安全认证,并依据分区属性(PL比特流或PS应用)选择PCAP配置或ELF加载机制。关键点包括:通过DevCfg接口的PL动态重配置、基于XLAT表的非对齐地址访问补偿、以及DMA加速的QSPI数据传输。移交控制权前,函数会强制刷新数据缓存(确保内存一致性)并通过CRL_APB寄存器组重配时钟域。调试方面,FSBL_DEBUG宏可实时输出分区加载状态,而错误处理机制将异常状态固化至PMU寄存器,为后续故障分析提供关键日志。该函数的设计充分体现了Zynq架构中PS-PL协同、硬件安全加速、以及多级启动链的技术特点。
注:具体实现细节需参考对应版本的 f s b l _ h o o k s . c fsbl\_hooks.c fsbl_hooks.c和 x f s b l _ p a r t i t i o n l o a d . c xfsbl\_partition_load.c xfsbl_partitionload.c源码文件。
相关文章:
Xilinx ZYNQ FSBL解读:LoadBootImage()
篇首 最近突发奇想,Xilinx 的集成开发环境已经很好了,很多必要的代码都直接生成了,这给开发者带来了巨大便利的同时,也让人错过了很多代码的精彩,可能有很多人用了很多年了,都还无法清楚的理解其中过程。博…...

mysql中in和exists的区别?
大家好,我是锋哥。今天分享关于【mysql中in和exists的区别?】面试题。希望对大家有帮助; mysql中in和exists的区别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 MySQL 中,IN 和 EXISTS 都用于进行子查询,但它…...

oracle 数据导出方案
工作中有遇到需要将oracle 数据库表全部导出,还需要去除表数据中的换行符。 方案 shell 设计 封装函数 1 function con_oracle() 用于连接oracle 2 function send_file() 用于发送文件 3 主程序 使用循环将所有表导出并发送到数据服务器 主程序 程序代码 #!…...
Apache Commons Lang3 和 Commons Net 详解
目录 1. Apache Commons Lang3 1.1 什么是 Apache Commons Lang3? 1.2 主要功能 1.3 示例代码 2. Commons Net 2.1 什么是 Commons Net? 2.2 主要功能 2.3 示例代码 3. 总结 3.1 Apache Commons Lang3 3.2 Commons Net 3.3 使用建议 4. 参考…...
从0开始的操作系统手搓教程33:挂载我们的文件系统
目录 代码实现 添加到初始化上 上电看现象 挂载分区可能是一些朋友不理解的——实际上挂载就是将我们的文件系统封装好了的设备(硬盘啊,SD卡啊,U盘啊等等),挂到我们的默认分区路径下。这样我们就能访问到了ÿ…...
【Linux】36.简单的TCP网络程序
文章目录 1. TCP socket API 详解1.1 socket():打开一个网络通讯端口1.2 bind():绑定一个固定的网络地址和端口号1.3 listen():声明sockfd处于监听状态1.4 accept():接受连接1.5 connect():连接服务器 2. 实现一个TCP网络服务器2.1 Log.hpp - "多级日志系统"2.2 Daem…...
时序分析
1、基本概念介绍 1.1、 建立时间 T(su) 建立时间:setup time,它是指有效的边沿信号到来之前,输入端口数据保持稳定的时间。 1.1.1、 建立时间要求: 建立时间要求指的是 想要寄存器如期的工作,在有效时…...
doris:ClickHouse
Doris JDBC Catalog 支持通过标准 JDBC 接口连接 ClickHouse 数据库。本文档介绍如何配置 ClickHouse 数据库连接。 使用须知 要连接到 ClickHouse 数据库,您需要 ClickHouse 23.x 或更高版本 (低于此版本未经充分测试)。 ClickHouse 数据库的 JDBC 驱动程序&a…...
NLP常见任务专题介绍(1)-关系抽取(Relation Extraction, RE)任务训练模板
📌 关系抽取(Relation Extraction, RE)任务训练示例 本示例展示如何训练一个关系抽取模型,以识别两个实体之间的关系。 1️⃣ 任务描述 目标:从文本中提取两个实体之间的语义关系,例如 “人物 - 组织”、“药物 - 疾病”、“公司 - 创始人” 等。输入:句子 + 标注的实…...

大模型Transformer的MOE架构介绍及方案整理
前言:DeepSeek模型最近引起了NLP领域的极大关注,也让大家进一步对MOE(混合专家网络)架构提起了信心,借此机会整理下MOE的简单知识和对应的大模型。本文的思路是MOE的起源介绍、原理解释、再到现有MOE大模型的整理。 一…...
零基础掌握Linux SCP命令:5分钟实现高效文件传输,小白必看!
引言 “为什么我传个文件到服务器要折腾半小时?” 如果你也曾在Linux系统中为文件传输抓狂,今天这篇保姆级教程就是你的救星!SCP命令——一个基于SSH协议的高效传输工具,只需5分钟,彻底告别FTP客户端和繁琐操作&#…...
分类评价指标
基础概念解释 TP、TN、FP、FN 这里T是True,F是False,P为Positive,N为Negative TP:被模型正确地预测为正样本(原本为正样本,预测为正样本) TN:被模型正确地预测为负样本࿰…...
Python项目-基于Django的在线教育平台开发
1. 项目概述 在线教育平台已成为现代教育的重要组成部分,特别是在后疫情时代,远程学习的需求显著增加。本文将详细介绍如何使用Python的Django框架开发一个功能完善的在线教育平台,包括系统设计、核心功能实现以及部署上线等关键环节。 本项…...

子数组问题——动态规划
个人主页:敲上瘾-CSDN博客 动态规划 基础dp:基础dp——动态规划-CSDN博客多状态dp:多状态dp——动态规划-CSDN博客 目录 一、解题技巧 二、最大子数组和 三、乘积最大子数组 四、最长湍流子数组 五、单词拆分 一、解题技巧 区分子数组&…...

linux设置pem免密登录和密码登录
其实现在chatgpt 上面很多东西问题都可以找到比较好答案了,最近换了一个服务器,记录一下。 如果设置root用户,就直接切换到cd .ssh目录下生成ssh key即可,不需要创建用户创建用户的ssh文件夹了 比如说我要让danny这个用户可以用p…...
什么是Flask
Flask是Python中一个简单、灵活和易用的Web框架,适合初学者使用。它提供了丰富的功能和扩展性,可以帮助开发者快速构建功能完善的Web应用程序。 以下是Python Flask框架的一些特点和功能: Flask 是一个使用 Python 编写的轻量级 WSGI 微 Web…...

Spark(8)配置Hadoop集群环境-使用脚本命令实现集群文件同步
一.hadoop的运行模式 二.scp命令————基本使用 三.scp命令———拓展使用 四.rsync远程同步 五.xsync脚本集群之间的同步 一.hadoop的运行模式 hadoop一共有如下三种运行方式: 1. 本地运行。数据存储在linux本地,测试偶尔用一下。我们上一节课使用…...

【cocos creator】热更新
一、介绍 试了官方的热更新功能,总结一下 主要用于安卓包热更新 参考: Cocos Creator 2.2.2 热更新简易教程 基于cocos creator2.4.x的热更笔记 二、使用软件 1、cocos creator v2.4.10 2、creator热更新插件:热更新manifest生成工具&…...

黑金风格人像静物户外旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!
调色教程 针对人像、静物以及户外旅拍照片,运用 Lightroom 软件进行风格化调色工作。旨在通过软件中的多种工具,如基本参数调整、HSL(色相、饱和度、明亮度)调整、曲线工具等改变照片原本的色彩、明度、对比度等属性,将…...

部署vue+django项目(初版)
1.准备 vscode 插件Remote SSH,连接远程,打开远程中home文件夹。 镜像和容器的一些常用命令 docker images docker ps 查看所有正在运行的容器 docker ps -a docker rmi -f tk-django-app 删除镜像 docker rm xxx 删除容器 docker start xxxx …...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...