首页 > 编程语言 >ZYNQ FSBL源码分析

ZYNQ FSBL源码分析

时间:2023-02-18 16:35:00浏览次数:45  
标签:Status fsbl FSBL GENERAL 源码 ZYNQ MODE printf DEBUG

 FSBL 是ZYNQ的bootloader虽然不是第一个启动的,但属于用户可以更改的启动程序,因此对源码分析是非常有必要的(在FSBL之前有bootRom,这个已经固化)

zynq在运行完芯片内固化的bootRom之后运行的是FSBL程序(first stage boot loader),uboot由FSBL调起,官方说法中将uboot叫做SSBL(second stage boot loader).

以7000系列为例

代码为自动生成的main.c源码(主要看注释,理解下流程)

int main(void)
{
	u32 BootModeRegister = 0;  //SSBL 启动方式,后面会读取或强制修改,
	u32 HandoffAddress = 0; 
	u32 Status = XST_SUCCESS;

	/*
	 * PCW initialization for MIO,PLL,CLK and DDR
     * PS端初始化,包含MIO PLL CLK DDR
	 */
	Status = ps7_init();
	
    if (Status != FSBL_PS7_INIT_SUCCESS) {
        /////如果初始化失败,则打印
		fsbl_printf(DEBUG_GENERAL,"PS7_INIT_FAIL : %s\r\n",
						getPS7MessageInfo(Status));
		OutputStatus(PS7_INIT_FAIL);
		/*
		 * Calling FsblHookFallback instead of Fallback
		 * since, devcfg driver is not yet initialized
         * 异常
		 */
		FsblHookFallback();
	}

	/*
	 * Unlock SLCR for SLCR register write
     * SLCR 解锁,开放写权限;
     * SLCR =  System Level Control Registers,也就是说系统级别寄存器
	 */
	SlcrUnlock();

	/* If Performance measurement is required 
	 * then read the Global Timer value , Please note that the
	 * time taken for mio, clock and ddr initialisation
	 * done in the ps7_init function is not accounted in the FSBL
	 * 如果需要统计FSBL加载的时间,那么需要先记录当前时间
	 */
#ifdef FSBL_PERF
	XTime tCur = 0;
	FsblGetGlobalTime(&tCur);
#endif

	/*
	 * Flush the Caches
     * 刷新缓存
	 */
	Xil_DCacheFlush();

	/*
	 * Disable Data Cache
     * 禁用数据缓存
	 */
	Xil_DCacheDisable();

	/*
	 * Register the Exception handlers
     * 注册异常处理
	 */
	RegisterHandlers();
	
	/*
	 * Print the FSBL Banner
     * 打印FSBL 信息,包括编译时间
	 */
	fsbl_printf(DEBUG_GENERAL,"\n\rXilinx First Stage Boot Loader \n\r");
	fsbl_printf(DEBUG_GENERAL,"Release %d.%d	%s-%s\r\n",
			SDK_RELEASE_YEAR, SDK_RELEASE_QUARTER,
			__DATE__,__TIME__);

#ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR

    /*
     * DDR Read/write test 
     * DDR 读写测试
     */
	Status = DDRInitCheck();
	if (Status == XST_FAILURE) {
		fsbl_printf(DEBUG_GENERAL,"DDR_INIT_FAIL \r\n");
		/* Error Handling here */
		OutputStatus(DDR_INIT_FAIL);
		/*
		 * Calling FsblHookFallback instead of Fallback
		 * since, devcfg driver is not yet initialized
		 */
		FsblHookFallback();
	}


	/*
	 * PCAP initialization PCAP初始化,此处的pcap不是wireshark的pcap 包;
     * PCAP 全称是Processor Configuration Access Port, 即处理器配置接口,可以理解 PCAP 代表着硬件,那么这座桥的另一边 PS AXI 接口即代表软件。是为一座沟通软件和硬件的桥梁。
     * 
	 */
	Status = InitPcap();
	if (Status == XST_FAILURE) {
		fsbl_printf(DEBUG_GENERAL,"PCAP_INIT_FAIL \n\r");
		OutputStatus(PCAP_INIT_FAIL);
		/*
		 * Calling FsblHookFallback instead of Fallback
		 * since, devcfg driver is not yet initialized
		 */
		FsblHookFallback();
	}

	fsbl_printf(DEBUG_INFO,"Devcfg driver initialized \r\n");

	/*
	 * Get the Silicon Version
     * 获取芯片版本
	 */
	GetSiliconVersion();

#ifdef XPAR_XWDTPS_0_BASEADDR
	/*
	 * Check if WDT Reset has occurred or not
     * WDT=看门狗,重置
	 */
	CheckWDTReset();

	/*
	 * Initialize the Watchdog Timer so that it is ready to use
     * 初始化看门狗
	 */
	Status = InitWatchDog();
	if (Status == XST_FAILURE) {
		fsbl_printf(DEBUG_GENERAL,"WATCHDOG_INIT_FAIL \n\r");
		OutputStatus(WDT_INIT_FAIL);
		FsblFallback();
	}
	fsbl_printf(DEBUG_INFO,"Watchdog driver initialized \r\n");
#endif

	/*
	 * Get PCAP controller settings
     * 获取
	 */
	PcapCtrlRegVal = XDcfg_GetControlRegister(DcfgInstPtr);

	/*
	 * Check for AES source key
     * AES加密,检查AES秘钥
	 */
	if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) {
		/*
		 * For E-Fuse AES encryption Watch dog Timer disabled and
		 * User not allowed to do system reset
		 */
#ifdef	XPAR_XWDTPS_0_BASEADDR
		fsbl_printf(DEBUG_INFO,"Watchdog Timer Disabled\r\n");
		XWdtPs_Stop(&Watchdog);
#endif
		fsbl_printf(DEBUG_INFO,"User not allowed to do "
								"any system resets\r\n");
	}

	/*
	 * Store FSBL run state in Reboot Status Register
     * 设置FSBL run 状态
	 */
	MarkFSBLIn();

	/*
	 * Read bootmode register
     * 读取 加载方式项,默认是根据外部的引脚配置
	 */
	BootModeRegister = Xil_In32(BOOT_MODE_REG);  ///寄存器地址
	BootModeRegister &= BOOT_MODES_MASK;
	//BootModeRegister = JTAG_MODE; ///如果有需要,则强制改成某种方式

	/*
	 * QSPI BOOT MODE
     * QSPI 加载,从QSPI接口;以下流程都差不多,选择某个外部,然后先初始化,再赋值Access到MoveImage接口。
	 */
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR

#ifdef MMC_SUPPORT
	/*
	 * To support MMC boot
	 * QSPI boot mode detection ignored
	 */
	if (BootModeRegister == QSPI_MODE) {
		BootModeRegister = MMC_MODE;
	}
#endif

	if (BootModeRegister == QSPI_MODE) {
		fsbl_printf(DEBUG_GENERAL,"Boot mode is QSPI\n\r");
		InitQspi();
		MoveImage = QspiAccess;
		fsbl_printf(DEBUG_INFO,"QSPI Init Done \r\n");
	} else
#endif

	/*
	 * NAND BOOT MODE
	 */
#ifdef XPAR_PS7_NAND_0_BASEADDR
	if (BootModeRegister == NAND_FLASH_MODE) {
		/*
	 	* Boot ROM always initialize the nand at lower speed
	 	* This is the chance to put it to an optimum speed for your nand
	 	* device
	 	*/
		fsbl_printf(DEBUG_GENERAL,"Boot mode is NAND\n");

		Status = InitNand();
		if (Status != XST_SUCCESS) {
			fsbl_printf(DEBUG_GENERAL,"NAND_INIT_FAIL \r\n");
			/*
			 * Error Handling here
			 */
			OutputStatus(NAND_INIT_FAIL);
			FsblFallback();
		}
		MoveImage = NandAccess;
		fsbl_printf(DEBUG_INFO,"NAND Init Done \r\n");
	} else
#endif

	/*
	 * NOR BOOT MODE
	 */
	if (BootModeRegister == NOR_FLASH_MODE) {
		fsbl_printf(DEBUG_GENERAL,"Boot mode is NOR\n\r");
		/*
		 * Boot ROM always initialize the nor at lower speed
		 * This is the chance to put it to an optimum speed for your nor
		 * device
		 */
		InitNor();
		fsbl_printf(DEBUG_INFO,"NOR Init Done \r\n");
		MoveImage = NorAccess;
	} else

	/*
	 * SD BOOT MODE
	 */
#if defined(XPAR_PS7_SD_0_S_AXI_BASEADDR) || defined(XPAR_XSDPS_0_BASEADDR)

	if (BootModeRegister == SD_MODE) {
		fsbl_printf(DEBUG_GENERAL,"Boot mode is SD\r\n");

		/*
		 * SD initialization returns file open error or success
		 */
		Status = InitSD("BOOT.BIN");
		if (Status != XST_SUCCESS) {
			fsbl_printf(DEBUG_GENERAL,"SD_INIT_FAIL\r\n");
			OutputStatus(SD_INIT_FAIL);
			FsblFallback();
		}
		MoveImage = SDAccess;
		fsbl_printf(DEBUG_INFO,"SD Init Done \r\n");
	} else

	if (BootModeRegister == MMC_MODE) {
		fsbl_printf(DEBUG_GENERAL,"Booting Device is MMC\r\n");

		/*
		 * MMC initialization returns file open error or success
		 */
		Status = InitSD("BOOT.BIN");
		if (Status != XST_SUCCESS) {
			fsbl_printf(DEBUG_GENERAL,"MMC_INIT_FAIL\r\n");
			OutputStatus(SD_INIT_FAIL);
			FsblFallback();
		}
		MoveImage = SDAccess;
		fsbl_printf(DEBUG_INFO,"MMC Init Done \r\n");
	} else

#endif

	/*
	 * JTAG  BOOT MODE
	 */
	if (BootModeRegister == JTAG_MODE) {
		fsbl_printf(DEBUG_GENERAL,"Boot mode is JTAG\r\n");
		/*
		 * Stop the Watchdog before JTAG handoff
		 */
#ifdef	XPAR_XWDTPS_0_BASEADDR
		XWdtPs_Stop(&Watchdog);
#endif
		/*
		 * Clear our mark in reboot status register
		 */
		ClearFSBLIn();

		/*
		 * SLCR lock
		 */
		SlcrLock();

		FsblHandoffJtagExit();
	} else {
		fsbl_printf(DEBUG_GENERAL,"ILLEGAL_BOOT_MODE \r\n");
		OutputStatus(ILLEGAL_BOOT_MODE);
		/*
		 * fallback starts, no return
		 */
		FsblFallback();
	}

	fsbl_printf(DEBUG_INFO,"Flash Base Address: 0x%08lx\r\n", FlashReadBaseAddress);

	/*
	 * Check for valid flash address
	 */
	if ((FlashReadBaseAddress != XPS_QSPI_LINEAR_BASEADDR) &&
			(FlashReadBaseAddress != XPS_NAND_BASEADDR) &&
			(FlashReadBaseAddress != XPS_NOR_BASEADDR) &&
			(FlashReadBaseAddress != XPS_SDIO0_BASEADDR)) {
		fsbl_printf(DEBUG_GENERAL,"INVALID_FLASH_ADDRESS \r\n");
		OutputStatus(INVALID_FLASH_ADDRESS);
		FsblFallback();
	}

	/*
	 * NOR and QSPI (parallel) are linear boot devices
	 */
	if ((FlashReadBaseAddress == XPS_NOR_BASEADDR)) {
		fsbl_printf(DEBUG_INFO, "Linear Boot Device\r\n");
		LinearBootDeviceFlag = 1;
	}

#ifdef	XPAR_XWDTPS_0_BASEADDR
	/*
	 * Prevent WDT reset
	 */
	XWdtPs_RestartWdt(&Watchdog);
#endif

	/*
	 * This used only in case of E-Fuse encryption
	 * For image search
	 */
	SystemInitFlag = 1;

	/*
	 * Load boot image
	 */
	HandoffAddress = LoadBootImage();

	fsbl_printf(DEBUG_INFO,"Handoff Address: 0x%08lx\r\n",HandoffAddress);

	/*
	 * For Performance measurement
	 */
#ifdef FSBL_PERF
	XTime tEnd = 0;
	fsbl_printf(DEBUG_GENERAL,"Total Execution time is ");
	FsblMeasurePerfTime(tCur,tEnd);
#endif

	/*
	 * FSBL handoff to valid handoff address or
	 * exit in JTAG
	 */
	FsblHandoff(HandoffAddress);

#else
	OutputStatus(NO_DDR);
	FsblFallback();
#endif

	return Status;
}

 

标签:Status,fsbl,FSBL,GENERAL,源码,ZYNQ,MODE,printf,DEBUG
From: https://www.cnblogs.com/winafa/p/17132934.html

相关文章

  • 摄像头视频云台控制PTZ前端html css原生样式源码分享
        ​<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0">......
  • 智慧校园:带微信小程序端源码
    智慧校园-基础数据管理1、学校信息:支持管理员对学校对基本学校信息进行编辑并浏览,通过编辑提交后全校可查看2、学科设置:支持管理添加并编辑以及删除学科,添加学科时系统自动......
  • Linux系列教程(十三)——Linux软件包管理之源码包、脚本安装包
    上篇博客我们讲解了网络yum源和光盘yum源的搭建步骤,然后详细介绍了相关的yum命令,yum最重要是解决了软件包依赖性问题。在安装软件时,我们使用yum命令将会简单方便很多。......
  • Semaphore源码解析
    Semaphore源码解析描述:一个计数信号量。从概念上讲,信号量维护一组许可。每个acquire()方法在必要时阻塞,直到获得许可,然后才能使用它。每次release()释放一个许可,潜在......
  • 阅读GitHub上的项目源码有以下几种方法
    GitHub是一个非常流行的代码托管平台,上面有很多优秀的开源项目。阅读这些项目的源码可以帮助我们学习和提高编程技能。阅读GitHub上的项目源码有以下几种方法:1、下载源码到......
  • 多线程等待所有子线程执行完使用总结(3)——CyclicBarrier使用和源码初步分析
    问题背景我们在日常开发和学习过程中,经常会使用到多线程的场景,其中我们经常会碰到,我们代码需要等待某个或者多个线程执行完再开始执行,上一篇文章中(参考https://blog.51cto......
  • 3、TreeMap源码解析
    目录1TreeMap基本介绍2红黑树数据结构回顾3成员变量4内部类Entry5构造函数6重要方法分析6.1get方法分析6.2put方法分析6.3插入调整函数fixAfterInsertion()解析6.......
  • 3D目标检测 | BEVDet系列源码解读
    前言本文介绍了BEVDet实现过程中的代码注释,希望能帮助大家更好地理解如何从论文原理到mmdet3d上代码实现BEVDet。 本文转载自自动驾驶之心作者丨小书童 欢......
  • udhcp源码剖析(一)——DHCP服务器和客户端的工作流程
    DHCP服务器的工作流程udhcpd,即dhcp服务器,在路由器等网关设备中,DHCP服务器启动后用于给LAN侧和无线终端分配IP、租约和其他网络配置。根据RFC2131文档规范,一个标准的DHCP服......
  • DHCP源码分析_dhcpd后台进程子模块
    dhcpd是dhcp服务器端后台进程文件,dhcpd后台程序总是读取配置文件/etc/dhcpd.conf。一,守护进程的基本流程    dhcpd基本流程为: main(){/*设置isc和d......