Xilinx ZYNQ FSBL解读:通览


篇首

最近突发奇想,Xilinx 的集成开发环境已经很好了,很多必要的代码都直接生成了,这给开发者带来了巨大便利的同时,也让人错过了很多代码的精彩,可能有很多人用了很多年了,都还无法清楚的理解其中过程。博主准备以FSBL为例,与大家深入探讨一番,从而加深对ZYNQ的加载过程的理解,以便大家作出更精彩的设计!


** 通览 FSBL **

一、FSBL工程结构与核心文件

SDK生成的FSBL工程目录通常包含以下关键文件:

  1. main.c

    • 入口函数main(),控制整个启动流程。
    • 核心逻辑:初始化硬件 → 加载镜像 → 跳转到SSBL(如U-Boot)。
  2. ps7_init.c / ps7_init.h

    • 硬件初始化:由Xilinx工具自动生成,包含Zynq PS(处理器系统)的底层配置代码,如:
      • DDR控制器参数(DDRSetup()
      • 时钟配置(ClockConfig()
      • MIO(多功能IO)引脚初始化(MIOInit()
  3. asm_vectors.S

    • 异常向量表:定义ARM Cortex-A9的异常处理跳转指令,例如:
      _vector_table:  
          B   _boot           // 复位异常  
          B   Undef_Handler   // 未定义指令异常  
          B   SVC_Handler     // SVC调用  
          ...  
      
  4. xil_exception.c

    • 异常注册:通过Xil_ExceptionRegisterHandler()将自定义处理函数绑定到异常ID。
  5. xil_io.h / xil_printf.h

    • 底层操作:提供内存读写(Xil_Out32())、调试输出(xil_printf())等基础函数。

二、FSBL工作流程详解

从复位到跳转至SSBL的全流程:

  1. 复位与BootROM阶段

    • Zynq上电后,BootROM自动执行,检测启动设备(QSPI/SD/NAND),加载FSBL到OCM(On-Chip Memory)。
  2. FSBL入口(_boot标签)

    • 汇编初始化asm_vectors.S):
      • 设置栈指针(SP指向OCM)。
      • 跳转到main()函数(C语言入口)。
  3. 硬件初始化(main()函数内)

    • 调用ps7_init()(位于ps7_init.c):
      int main() {  
          ps7_init();       // 初始化DDR、时钟、MIO等  
          ...  
      }  
      
    • 关键配置
      • DDR控制器参数(决定内存地址映射)。
      • UART初始化(若启用调试输出)。
  4. 注册异常处理函数

    • 代码片段main.c中):
      Xil_ExceptionInit();  
      Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_DATA_ABORT, DataAbortHandler, NULL);  
      Xil_ExceptionEnable();  
      
    • 作用:确保DDR初始化失败等错误能被捕获。
  5. 加载并验证镜像(BOOT.BIN

    • 步骤
      1. 从启动设备读取镜像头(解析分区信息)。
      2. 按分区加载SSBL(如U-Boot)、PL比特流(.bit)到DDR。
      3. 若启用加密或签名,执行解密和认证。
  6. 配置PL(可选)

    • 代码触发:若镜像中包含PL比特流,调用XFsbl_LoadPLBitstream()通过PCAP接口配置FPGA逻辑。
  7. 跳转到SSBL

    • 关键操作
      void (*SSBL)(void) = (void (*)(void))SSBL_ENTRY_ADDR;  
      SSBL();  // 跳转到U-Boot  
      

三、核心函数代码解析
  1. ps7_init()函数(硬件初始化)

    • 功能:配置PS端所有关键硬件模块。
    • 代码结构
      void ps7_init() {  
          ps7_mio_init();     // MIO引脚配置  
          ps7_clock_init();   // PLL和时钟分配  
          ps7_ddr_init();     // DDR控制器参数  
          ps7_peripherals_init(); // 外设使能(如UART、QSPI)  
      }  
      
  2. Xil_ExceptionRegisterHandler()(异常注册)

    • 参数解析
      • ExceptionId:异常ID(如XIL_EXCEPTION_ID_DATA_ABORT)。
      • Handler:自定义处理函数指针(如DataAbortHandler)。
      • CallBackRef:传递给处理函数的参数(通常为NULL)。
  3. LoadBootImage()(镜像加载)

    • 逻辑分支
      if (ImageHeader->EncryptionFlag) {  
          DecryptImage();    // AES解密  
      }  
      if (ImageHeader->AuthenticationType == RSA) {  
          VerifyRSASignature(); // RSA签名验证  
      }  
      LoadPartitions();      // 加载分区到内存  
      

四、调试与问题排查
  1. 启用调试输出

    • 方法:在xparameters.h中定义FSBL_DEBUG_INFO,并确保UART初始化正确。
    • 输出示例
      XFsbl_LoadPLBitstream: PL configuration started  
      XFsbl_LoadPLBitstream: PL configuration success  
      
  2. 常见错误与解决

    • DDR初始化失败
      • 检查ps7_init.c中的DDR参数是否与硬件匹配(容量、时序)。
    • 镜像加载超时
      • 确认启动设备(如SD卡)连接正常,镜像文件BOOT.BIN未损坏。
    • PL配置错误
      • 检查比特流文件是否为Zynq 7000兼容格式,PCAP接口是否使能。

五、扩展开发指南
  1. 添加自定义初始化代码

    • Hook函数:在main.cmain()函数中插入代码:
      ps7_init();  
      Custom_Init();  // 用户自定义外设初始化  
      LoadBootImage();  
      
  2. 跳过PL配置加速启动

    • 修改代码:注释掉PL加载相关代码:
      // if (BitstreamPresent) {  
      //     XFsbl_LoadPLBitstream();  
      // }  
      
  3. 实现自定义异常处理

    • 示例:在数据中止异常中记录错误地址:
      void DataAbortHandler(void *Callback) {  
          u32 FaultAddr;  
          __asm__("MRC p15, 0, %0, c6, c0, 0" : "=r" (FaultAddr));  
          xil_printf("Data Abort at 0x%08X\n", FaultAddr);  
          FsblHookFallback();  
      }  
      

六、总结

SDK生成的FSBL代码是一个高度模块化的启动框架:

  • 硬件初始化ps7_init()全权负责,开发者需关注硬件参数配置;
  • 异常处理通过绑定向量表实现,是系统稳定的第一道防线;
  • 镜像加载流程可定制(加密、多分区),但需严格遵循Xilinx镜像格式规范。
    理解这些细节,可从容应对启动失败、性能优化、安全加固等实际挑战!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值