1、背景介绍
为了节约成本和降低功耗,现在板载BMC全部选择了ZYNQ7010,无外挂DDR,存储空间使用QSPI,借助板载OCM执行应用程序。
xilinx网站上提供了一种解决方案,链接如下:
注:建议使用vivado2017.3及以上版本进行硬件工程设计。
2、fsbl修改
vivado产生bit之后,导入SDK,根据新的硬件工程产生fsbl和fsbl_bsp。
首先需要对fsbl_bsp进行修改
Translation_table.s修改
需要修改地方如下:
/******************************************************************************
*
* Copyright (C) 2009 - 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
* @file translation_table.s
*
* @addtogroup a9_boot_code
* @{
* <h2> translation_table.S </h2>
* translation_table.S contains a static page table required by MMU for
* cortex-A9. This translation table is flat mapped (input address = output
* address) with default memory attributes defined for zynq architecture. It
* utilizes short descriptor translation table format with each section defining
* 1MB of memory.
*
* The overview of translation table memory attributes is described below.
*
*| | Memory Range | Definition in Translation Table |
*|-----------------------|-------------------------|-----------------------------------|
*| DDR | 0x00000000 - 0x3FFFFFFF | Normal write-back Cacheable |
*| PL | 0x40000000 - 0xBFFFFFFF | Strongly Ordered |
*| Reserved | 0xC0000000 - 0xDFFFFFFF | Unassigned |
*| Memory mapped devices | 0xE0000000 - 0xE02FFFFF | Device Memory |
*| Reserved | 0xE0300000 - 0xE0FFFFFF | Unassigned |
*| NAND, NOR | 0xE1000000 - 0xE3FFFFFF | Device memory |
*| SRAM | 0xE4000000 - 0xE5FFFFFF | Normal write-back Cacheable |
*| Reserved | 0xE6000000 - 0xF7FFFFFF | Unassigned |
*| AMBA APB Peripherals | 0xF8000000 - 0xF8FFFFFF | Device Memory |
*| Reserved | 0xF9000000 - 0xFBFFFFFF | Unassigned |
*| Linear QSPI - XIP | 0xFC000000 - 0xFDFFFFFF | Normal write-through cacheable |
*| Reserved | 0xFE000000 - 0xFFEFFFFF | Unassigned |
*| OCM | 0xFFF00000 - 0xFFFFFFFF | Normal inner write-back cacheable |
*
* @note
*
* For region 0x00000000 - 0x3FFFFFFF, a system where DDR is less than 1GB,
* region after DDR and before PL is marked as undefined/reserved in translation
* table. In 0xF8000000 - 0xF8FFFFFF, 0xF8000C00 - 0xF8000FFF, 0xF8010000 -
* 0xF88FFFFF and 0xF8F03000 to 0xF8FFFFFF are reserved but due to granual size
* of 1MB, it is not possible to define separate regions for them. For region
* 0xFFF00000 - 0xFFFFFFFF, 0xFFF00000 to 0xFFFB0000 is reserved but due to 1MB
* granual size, it is not possible to define separate region for it
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 1.00a ecm 10/20/09 Initial version
* 3.04a sdm 01/13/12 Updated MMU table to mark DDR memory as Shareable
* 3.07a sgd 07/05/2012 Configuring device address spaces as shareable device
* instead of strongly-ordered.
* 3.07a asa 07/17/2012 Changed the property of the ".mmu_tbl" section.
* 4.2 pkp 09/02/2014 added entries for 0xfe000000 to 0xffefffff as reserved
* and 0xe0000000 - 0xe1ffffff is broken down into
* 0xe0000000 - 0xe02fffff (memory mapped devides)
* 0xe0300000 - 0xe0ffffff (reserved) and
* 0xe1000000 - 0xe1ffffff (NAND)
* 5.2 pkp 06/08/2015 put a check for XPAR_PS7_DDR_0_S_AXI_BASEADDR to confirm
* if DDR is present or not and accordingly generate the
* translation table
* 6.1 pkp 07/11/2016 Corrected comments for memory attributes
* </pre>
*
*
******************************************************************************/
#include "xparameters.h"
.globl MMUTable
.section .mmu_tbl,"a"
MMUTable:
/* Each table entry occupies one 32-bit word and there are
* 4096 entries, so the entire table takes up 16KB.
* Each entry covers a 1MB section.
*/
.set SECT, 0
#ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR
.set DDR_START, XPAR_PS7_DDR_0_S_AXI_BASEADDR
.set DDR_END, XPAR_PS7_DDR_0_S_AXI_HIGHADDR
.set DDR_SIZE, (DDR_END - DDR_START)+1
.set DDR_REG, DDR_SIZE/0x100000
#else
.set DDR_REG, 0
#endif
.set UNDEF_REG, 0x3FF - DDR_REG
/*0x00000000 - 0x00100000 (cacheable )*/
.word SECT + 0x15de6 /* S=b1 TEX=b101 AP=b11, Domain=b1111, C=b0, B=b1 */
.set SECT, SECT+0x100000
.rept DDR_REG /* (DDR Cacheable) */
.word SECT + 0x15de6 /* S=b1 TEX=b101 AP=b11, Domain=b1111, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept UNDEF_REG /* (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0400 /* 0x40000000 - 0x7fffffff (FPGA slave0) */
.word SECT + 0xc02 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0400 /* 0x80000000 - 0xbfffffff (FPGA slave1) */
.word SECT + 0xc02 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0200 /* 0xc0000000 - 0xdfffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x003 /* 0xe0000000 - 0xe02fffff (Memory mapped devices)
* UART/USB/IIC/SPI/CAN/GEM/GPIO/QSPI/SD/NAND */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0D /* 0xe0300000 - 0xe0ffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0010 /* 0xe1000000 - 0xe1ffffff (NAND) */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0020 /* 0xe2000000 - 0xe3ffffff (NOR) */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0020 /* 0xe4000000 - 0xe5ffffff (SRAM) */
.word SECT + 0xc0e /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0120 /* 0xe6000000 - 0xf7ffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
/* 0xf8000c00 to 0xf8000fff, 0xf8010000 to 0xf88fffff and
0xf8f03000 to 0xf8ffffff are reserved but due to granual size of
1MB, it is not possible to define separate regions for them */
.rept 0x0010 /* 0xf8000000 - 0xf8ffffff (AMBA APB Peripherals) */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0030 /* 0xf9000000 - 0xfbffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
#if 0
.rept 0x0020 /* 0xfc000000 - 0xfdffffff (Linear QSPI - XIP) */
.word SECT + 0xc0a /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b0 */
.set SECT, SECT+0x100000
.endr
#endif
.rept 0x0007 /* 0xfc000000 - 0xfc6fffff (Linear QSPI - XIP) */
.word SECT + 0xc0a /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0019 /* 0xfc700000 - 0xfdffffff (Linear QSPI - XIP) */
.word SECT + 0x15de2 /* S=b0 TEX=b101 AP=b11, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x001F /* 0xfe000000 - 0xffefffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
/* 0xfff00000 to 0xfffb0000 is reserved but due to granual size of
1MB, it is not possible to define separate region for it
0xfff00000 - 0xffffffff
256K OCM when mapped to high address space
inner-cacheable */
.word SECT + 0x4c0e /* S=b0 TEX=b100 AP=b11, Domain=b0, C=b1, B=b1 */
.set SECT, SECT+0x100000
.end
/**
* @} End of "addtogroup a9_boot_code".
*/
增加的代码使用了QSPI内部的存储空间,用于执行FSBL,这里将QSPI配置为线性模式,分为2段XIP,7MB和25MB。这与后面提到的产生BIN文件时使用XIP模块相对应,同时0XFC000000这个地址将会用在fsbl的lscript.ld中。
xil_exception.c修改
如下图
修改完fsbl_bsp后,下面开始修改fsbl工程下的文件
Fsbl工程下需要修改的文件如下:
Main.c修改
Main.c中修改的地方较多,具体参考修改后的main.c代码,下面只做简述:
增加preload_funct函数和copy函数,作用如下
在main主函数中取消DDR初始化
在main主函数中对L1cache使能
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file main.c
*
* The main file for the First Stage Boot Loader (FSBL).
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a jz 06/04/11 Initial release
* 2.00a mb 25/05/12 standalone based FSBL
* 3.00a np/mb 08/03/12 Added call to FSBL user hook - before handoff.
* DDR ECC initialization added
* fsbl print with verbose added
* Performance measurement added
* Flushed the UART Tx buffer
* Added the performance time for ECC DDR init
* Added clearing of ECC Error Code
* Added the watchdog timer value
* 4.00a sgd 02/28/13 Code Cleanup
* Fix for CR#681014 - ECC init in FSBL should not
* call fabric_init()
* Fix for CR#689077 - FSBL hangs at Handoff clearing the
* TX UART buffer when using UART0
* instead of UART1
* Fix for CR#694038 - FSBL debug logs always prints 14.3
* as the Revision number - this is
* incorrect
* Fix for CR#694039 - FSBL prints "unsupported silicon
* version for v3.0" 3.0 Silicon
* Fix for CR#699475 - FSBL functionality is broken and
* its not able to boot in QSPI/NAND
* bootmode
* Removed DDR initialization check
* Removed DDR ECC initialization code
* Modified hand off address check to 1MB
* Added RSA authentication support
* Watchdog disabled for AES E-Fuse encryption
* 5.00a sgd 05/17/13 Fallback support for E-Fuse encryption
* Fix for CR#708728 - Issues seen while making HP
* interconnect 32 bit wide
* 6.00a kc 07/30/13 Fix for CR#708316 - PS7_init.tcl file should have
* Error mechanism for all mask_poll
* Fix for CR#691150 - ps7_init does not check for
* peripheral initialization failures
* or timeout on polls
* Fix for CR#724165 - Partition Header used by FSBL is
* not authenticated
* Fix for CR#724166 - FSBL doesn’t use PPK authenticated
* by Boot ROM for authenticating
* the Partition images
* Fix for CR#722979 - Provide customer-friendly
* changelogs in FSBL
* Fix for CR#732865 - Backward compatibility for ps7_init
* function
* 7.00a kc 10/18/13 Integrated SD/MMC driver
* 8.00a kc 02/20/14 Fix for CR#775631 - FSBL: FsblGetGlobalTimer()
* is not proper
* 9.00a kc 04/16/14 Fix for CR#724166 - SetPpk() will fail on secure
* fallback unless FSBL* and FSBL
* are identical in length
* 10.00a kc 07/24/14 Fix for CR#809336 - Minor code cleanup
* kc 08/27/14 Fix for CR#820356 - FSBL compilation fails with
* IAR compiler
* 11.00a kv 10/08/14 Fix for CR#826030 - LinearBootDeviceFlag should
* be initialized to 0 in IO mode
* case
* 15.00a gan 07/21/16 Fix for CR# 953654 -(2016.3)FSBL -
* In pcap.c/pcap.h/main.c,
* Fabric Initialization sequence
* is modified to check the PL power
* before sequence starts and checking
* INIT_B reset status twice in case
* of failure.
* </pre>
*
* @note
* FSBL runs from OCM, Based on the boot mode selected, FSBL will copy
* the partitions from the flash device. If the partition is bitstream then
* the bitstream is programmed in the Fabric and for an partition that is
* an application , FSBL will copy the application into DDR and does a
* handoff.The application should not be starting at the OCM address,
* FSBL does not remap the DDR. Application should use DDR starting from 1MB
*
* FSBL can be stitched along with bitstream and application using bootgen
*
* Refer to fsbl.h file for details on the compilation flags supported in FSBL
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "fsbl.h"
#include "qspi.h"
#include "nand.h"
#include "nor.h"
#include "sd.h"
#include "pcap.h"
#include "image_mover.h"
#include "xparameters.h"
#include "xil_cache.h"
#include "xil_cache_l.h"
#include "xil_exception.h"
#include "xstatus.h"
#include "fsbl_hooks.h"
#include "xtime_l.h"
#include "xl2cc.h"
#ifdef XPAR_XWDTPS_0_BASEADDR
#include "xwdtps.h"
#endif
#ifdef STDOUT_BASEADDRESS
#ifdef XPAR_XUARTPS_0_BASEADDR
#include "xuartps_hw.h"
#endif
#endif
#ifdef RSA_SUPPORT
#include "rsa.h"
#endif
/************************** Constant Definitions *****************************/
#ifdef XPAR_XWDTPS_0_BASEADDR
#define WDT_DEVICE_ID XPAR_XWDTPS_0_DEVICE_ID
#define WDT_EXPIRE_TIME 100
#define WDT_CRV_SHIFT 12
#endif
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
#ifdef XPAR_XWDTPS_0_BASEADDR
XWdtPs Watchdog; /* Instance of WatchDog Timer */
#endif
/************************** Function Prototypes ******************************/
extern int ps7_init();
extern char* getPS7MessageInfo(unsigned key);
#ifdef PS7_POST_CONFIG
extern int ps7_post_config();
#endif
static void Update_MultiBootRegister(void);
/* Exception handlers */
static void RegisterHandlers(void);
static void Undef_Handler (void);
static void SVC_Handler (void);
static void PreFetch_Abort_Handler (void);
static void Data_Abort_Handler (void);
static void IRQ_Handler (void);
static void FIQ_Handler (void);
#ifdef XPAR_XWDTPS_0_BASEADDR
int InitWatchDog(void);
u32 ConvertTime_WdtCounter(u32 seconds);
void CheckWDTReset(void);
#endif
u32 NextValidImageCheck(void);
u32 DDRInitCheck(void);
/************************** Variable Definitions *****************************/
/*
* Base Address for the Read Functionality for Image Processing
*/
u32 FlashReadBaseAddress = 0;
/*
* Silicon Version
*/
u32 Silicon_Version;
/*
* Boot Device flag
*/
#ifdef QSPI_XIP
u8 LinearBootDeviceFlag=1;
#else
u8 LinearBootDeviceFlag=0;
#endif
u32 PcapCtrlRegVal;
u8 SystemInitFlag;
extern ImageMoverType MoveImage;
extern XDcfg *DcfgInstPtr;
extern u8 BitstreamFlag;
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR
extern u32 QspiFlashSize;
#endif
#ifdef DDRLESS_SYSTEM
#define WAY_SIZE 65536
#define MAX_NUM_WAYS 8
int preload_funct(unsigned int uiSrcAddress, unsigned int uiSize);/* __attribute__ ((section ("ncmemory")));*/
/*****************************************************************************/
/**
*
* This function is used to preload and lock data in to L2 Cache.
*
*
* @param None.
*
* @return
* - XST_SUCCESS to indicate success
* - XST_FAILURE.to indicate failure
*
* @note
*
****************************************************************************/
int preload_funct(unsigned int uiSrcAddress, unsigned int uiSize)
{
// static unsigned int uiAlreadyProgrammed;
unsigned int i=0;
// unsigned int uiNumofWays=0;
// unsigned int uiVariable=0;
// unsigned int uiValue0=0;
// unsigned int uiValue1=0;
fsbl_printf(DEBUG_GENERAL,"\n\rInside Preload Functions \n\r");
// Disable FIQ and IRQ interrupt
Xil_ExceptionDisableMask(XIL_EXCEPTION_ALL);
/*
* UnLock Data and Instruction from way 1 to7 and unlock Data and instruction for Way 0.
* The PL310 has 8 sets of registers, one per possible CPU.
*/
for(i=0;i<8;i++)
{
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_DLCKDWN_0_WAY_OFFSET + (i*8)) ), (0x00000000));
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_ILCKDWN_0_WAY_OFFSET + (i*8)) ), (0x00000000));
}
/* Flush the Caches */
Xil_DCacheFlush();
Xil_DCacheInvalidate();
fsbl_printf(DEBUG_GENERAL,"\n\r Invalidate D cache \n\r");
/*Preload instruction from section starts from 0x31000000 to Cache Way 0*/
fsbl_printf(DEBUG_GENERAL,"Preload instructions uiSrcAddress = 0x%8x\n\r", uiSrcAddress);
fsbl_printf(DEBUG_GENERAL,"Preload instructions uiSize = 0x%8x\n\r", uiSize);
{
// Copy Applciation source adress to ro register
asm volatile ("mov r0,%0":: "r"(uiSrcAddress));
//Copy application size to r1 register
asm volatile ("mov r1,%0":: "r"(uiSize));
// Offset register i.e. r2
asm volatile ("mov r2, #0");
// Label
asm ("preload_inst:");
// Load r4 register from the r0+r2 (Source address + offset)
// This step create an valid entry of the address (Source address + offset) in L2 cache
asm volatile ("ldr r4, [r0,r2]");
// Increment the offset by one cache line
asm volatile ("add r2,r2,#4");
// Compare the offset with the Application size.
asm volatile ("cmp r1, r2");
// If not equal jump to Label
asm volatile ("bge preload_inst");
}
// lock both Data and instruction caches from Way 1 to 7.
// Lock Data and Instruction Caches for Way 0
for(i=0;i<8;i++)
{
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_DLCKDWN_0_WAY_OFFSET + (i*8)) ), 0xffff);
Xil_Out32((XPS_L2CC_BASEADDR + (XPS_L2CC_CACHE_ILCKDWN_0_WAY_OFFSET + (i*8)) ), 0xffff);
}
fsbl_printf(DEBUG_GENERAL,"Lock both Data and instruction caches from Way 1 to 7\n\r");
// Enable all the Interrupts
Xil_ExceptionEnableMask(XIL_EXCEPTION_ALL);
// uiAlreadyProgrammed=uiVariable;
return - XST_SUCCESS;
}
#endif
/*****************************************************************************/
/**
*
* This is the main function for the FSBL ROM code.
*
*
* @param None.
*
* @return
* - XST_SUCCESS to indicate success
* - XST_FAILURE.to indicate failure
*
* @note
*
****************************************************************************/
extern char _image_start, _dataLMA, _dataVMA_start, _dataVMA_end, _vectorscopy, __vectors_start, __vectors_end;
extern char _dataXVtableLMA, _dataXVtableVMA_start,_dataXVtableVMA_end;
extern unsigned int _ncSTART_ADDR;
static void copy(char *src, char *dstStart, char *dstEnd) {
/* ROM has data at end of text; copy it. */
while (dstStart < dstEnd) {
*dstStart++ = *src++;
}
}
#define WRITE_VEC_BASE_ADDR(value) mtcp(XREG_CP15_VEC_BASE_ADDR,value)
#define READ_VEC_BASE_ADDR(value) value = mfcp(XREG_CP15_VEC_BASE_ADDR)
int main(void)
{
u32 BootModeRegister = 0;
u32 HandoffAddress = 0;
u32 Status = XST_SUCCESS;
copy(&_dataLMA,&_dataVMA_start,&_dataVMA_end);
copy(&_dataXVtableLMA,&_dataXVtableVMA_start,&_dataXVtableVMA_end);
/*
* PCW initialization for MIO,PLL,CLK and 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
*/
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
*
*/
#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_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__);
//fsbl_printf(DEBUG_GENERAL,"_image_start \t= 0x%8x\n\r", &_image_start);
fsbl_printf(DEBUG_GENERAL,"_dataLMA \t= 0x%8x\n\r", &_dataLMA);
fsbl_printf(DEBUG_GENERAL,"_dataVMA_start \t= 0x%8x\n\r", &_dataVMA_start);
fsbl_printf(DEBUG_GENERAL,"_dataVMA_end \t= 0x%8x\n\r", &_dataVMA_end);
//fsbl_printf(DEBUG_GENERAL,"_vectorscopy \t= 0x%8x\n\r", &_vectorscopy);
//fsbl_printf(DEBUG_GENERAL,"__vectors_start \t= 0x%8x\n\r", &__vectors_start);
//fsbl_printf(DEBUG_GENERAL,"__vectors_end \t= 0x%8x\n\r", &__vectors_end);
fsbl_printf(DEBUG_GENERAL,"_dataXVtableLMA \t= 0x%8x\n\r", &_dataXVtableLMA);
fsbl_printf(DEBUG_GENERAL,"_dataXVtableVMA_start \t= 0x%8x\n\r", &_dataXVtableVMA_start);
fsbl_printf(DEBUG_GENERAL,"_dataXVtableVMA_end \t= 0x%8x\n\r", &_dataXVtableVMA_end);
#ifdef XPAR_PS7_DDR_0_S_AXI_BASEADDR
#ifndef DDRLESS_SYSTEM
/*
* DDR Read/write test
*/
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();
}
#endif
/*
* PCAP initialization
*/
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
*/
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
*/
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
*/
MarkFSBLIn();
/*
* Read bootmode register
*/
BootModeRegister = Xil_In32(BOOT_MODE_REG);
BootModeRegister &= BOOT_MODES_MASK;
/*
* QSPI BOOT MODE
*/
#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;
FlashReadBaseAddress = XPS_QSPI_LINEAR_BASEADDR;
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();
Xil_L1DCacheEnable();
Xil_L1ICacheEnable();
Xil_L1DCacheInvalidate();
Xil_L1ICacheInvalidate();
fsbl_printf(DEBUG_INFO,"Handoff Address original : 0x%08lx\r\n",HandoffAddress);
// HandoffAddress = 0x10000;
//fsbl_printf(DEBUG_INFO,"Handoff Address modified : 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
*/
//for debug
// int x = 1;
// while (x==1);
FsblHandoff(HandoffAddress);
#else
fsbl_printf(DEBUG_GENERAL,"-> FsblFallback\n\r");
// OutputStatus(NO_DDR);
FsblFallback();
#endif
return Status;
}
/******************************************************************************/
/**
*
* This function reset the CPU and goes for Boot ROM fallback handling
*
* @param None
*
* @return None
*
* @note None
*
****************************************************************************/
void FsblFallback(void)
{
u32 RebootStatusReg;
u32 Status;
u32 HandoffAddr;
u32 BootModeRegister;
/*
* Read bootmode register
*/
BootModeRegister = Xil_In32(BOOT_MODE_REG);
BootModeRegister &= BOOT_MODES_MASK;
/*
* Fallback support check
*/
if (!((BootModeRegister == QSPI_MODE) ||
(BootModeRegister == NAND_FLASH_MODE) ||
(BootModeRegister == NOR_FLASH_MODE))) {
fsbl_printf(DEBUG_INFO,"\r\n"
"This Boot Mode Doesn't Support Fallback\r\n");
ClearFSBLIn();
FsblHookFallback();
}
/*
* update the Multiboot Register for Golden search hunt
*/
Update_MultiBootRegister();
/*
* Notify Boot ROM something is wrong
*/
RebootStatusReg = Xil_In32(REBOOT_STATUS_REG);
/*
* Set the FSBL Fail mask
*/
Xil_Out32(REBOOT_STATUS_REG, RebootStatusReg | FSBL_FAIL_MASK);
/*
* Barrier for synchronization
*/
__asm(
"dsb\n\t"
"isb"
);
/*
* Check for AES source key
*/
if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) {
/*
* Next valid image search can happen only
* when system initialization done
*/
if (SystemInitFlag == 1) {
/*
* Clean the Fabric
*/
FabricInit();
#ifdef RSA_SUPPORT
/*
* Making sure PPK is set for efuse error cases
*/
SetPpk();
#endif
/*
* Search for next valid image
*/
Status = NextValidImageCheck();
if(Status != XST_SUCCESS){
fsbl_printf(DEBUG_INFO,"\r\nNo Image Found\r\n");
ClearFSBLIn();
FsblHookFallback();
}
/*
* Load next valid image
*/
HandoffAddr = LoadBootImage();
/*
* Handoff to next image
*/
FsblHandoff(HandoffAddr);
} else {
fsbl_printf(DEBUG_INFO,"System Initialization Failed\r\n");
fsbl_printf(DEBUG_INFO,"\r\nNo Image Search\r\n");
ClearFSBLIn();
FsblHookFallback();
}
}
/*
* Reset PS, so Boot ROM will restart
*/
Xil_Out32(PS_RST_CTRL_REG, PS_RST_MASK);
}
/******************************************************************************/
/**
*
* This function hands the A9/PS to the loaded user code.
*
* @param none
*
* @return none
*
* @note This function does not return.
*
****************************************************************************/
void FsblHandoff(u32 FsblStartAddr)
{
u32 Status;
/*
* Enable level shifter
*/
if(BitstreamFlag) {
/*
* FSBL will not enable the level shifters for a NON PS instantiated
* Bitstream
* CR# 671028
* This flag can be set during compilation for a NON PS instantiated
* bitstream
*/
#ifndef NON_PS_INSTANTIATED_BITSTREAM
#ifdef PS7_POST_CONFIG
ps7_post_config();
/*
* Unlock SLCR for SLCR register write
*/
SlcrUnlock();
#else
/*
* Set Level Shifters DT618760
*/
Xil_Out32(PS_LVL_SHFTR_EN, LVL_PL_PS);
fsbl_printf(DEBUG_INFO,"Enabling Level Shifters PL to PS "
"Address = 0x%x Value = 0x%x \n\r",
PS_LVL_SHFTR_EN, Xil_In32(PS_LVL_SHFTR_EN));
/*
* Enable AXI interface
*/
Xil_Out32(FPGA_RESET_REG, 0);
fsbl_printf(DEBUG_INFO,"AXI Interface enabled \n\r");
fsbl_printf(DEBUG_INFO, "FPGA Reset Register "
"Address = 0x%x , Value = 0x%x \r\n",
FPGA_RESET_REG ,Xil_In32(FPGA_RESET_REG));
#endif
#endif
}
/*
* FSBL user hook call before handoff to the application
*/
Status = FsblHookBeforeHandoff(FsblStartAddr);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"FSBL_HANDOFF_HOOK_FAIL\r\n");
OutputStatus(FSBL_HANDOFF_HOOK_FAIL);
FsblFallback();
}
#ifdef XPAR_XWDTPS_0_BASEADDR
XWdtPs_Stop(&Watchdog);
#endif
/*
* Clear our mark in reboot status register
*/
ClearFSBLIn();
if(FsblStartAddr == 0) {
/*
* SLCR lock
*/
SlcrLock();
fsbl_printf(DEBUG_INFO,"No Execution Address JTAG handoff \r\n");
FsblHandoffJtagExit();
} else {
fsbl_printf(DEBUG_GENERAL,"SUCCESSFUL_HANDOFF\r\n");
OutputStatus(SUCCESSFUL_HANDOFF);
FsblHandoffExit(FsblStartAddr);
}
OutputStatus(ILLEGAL_RETURN);
FsblFallback();
}
/******************************************************************************/
/**
*
* This function outputs the status for the provided State in the boot process.
*
* @param State is where in the boot process the output is desired.
*
* @return None.
*
* @note None.
*
****************************************************************************/
void OutputStatus(u32 State)
{
#ifdef STDOUT_BASEADDRESS
#ifdef XPAR_XUARTPS_0_BASEADDR
u32 UartReg = 0;
#endif
fsbl_printf(DEBUG_GENERAL,"FSBL Status = 0x%.4lx\r\n", State);
/*
* The TX buffer needs to be flushed out
* If this is not done some of the prints will not appear on the
* serial output
*/
#ifdef XPAR_XUARTPS_0_BASEADDR
UartReg = Xil_In32(STDOUT_BASEADDRESS + XUARTPS_SR_OFFSET);
while ((UartReg & XUARTPS_SR_TXEMPTY) != XUARTPS_SR_TXEMPTY) {
UartReg = Xil_In32(STDOUT_BASEADDRESS + XUARTPS_SR_OFFSET);
}
#endif
#endif
}
/******************************************************************************/
/**
*
* This function handles the error and lockdown processing and outputs the status
* for the provided State in the boot process.
*
* This function is called upon exceptions.
*
* @param State - where in the boot process the error occured.
*
* @return None.
*
* @note This function does not return, the PS block is reset
*
****************************************************************************/
void ErrorLockdown(u32 State)
{
/*
* Store the error status
*/
OutputStatus(State);
/*
* Fall back
*/
FsblFallback();
}
/******************************************************************************/
/**
*
* This function copies a memory region to another memory region
*
* @param s1 is starting address for destination
* @param s2 is starting address for the source
* @param n is the number of bytes to copy
*
* @return Starting address for destination
*
****************************************************************************/
void *(memcpy_rom)(void * s1, const void * s2, u32 n)
{
char *dst = (char *)s1;
const char *src = (char *)s2;
/*
* Loop and copy
*/
while (n-- != 0)
*dst++ = *src++;
return s1;
}
/******************************************************************************/
/**
*
* This function copies a string to another, the source string must be null-
* terminated.
*
* @param Dest is starting address for the destination string
* @param Src is starting address for the source string
*
* @return Starting address for the destination string
*
****************************************************************************/
char *strcpy_rom(char *Dest, const char *Src)
{
unsigned i;
for (i=0; Src[i] != '\0'; ++i)
Dest[i] = Src[i];
Dest[i] = '\0';
return Dest;
}
/******************************************************************************/
/**
*
* This function sets FSBL is running mask in reboot status register
*
* @param None.
*
* @return None.
*
* @note None.
*
****************************************************************************/
void MarkFSBLIn(void)
{
Xil_Out32(REBOOT_STATUS_REG,
Xil_In32(REBOOT_STATUS_REG) | FSBL_IN_MASK);
}
/******************************************************************************/
/**
*
* This function clears FSBL is running mask in reboot status register
*
* @param None.
*
* @return None.
*
* @note None.
*
****************************************************************************/
void ClearFSBLIn(void)
{
Xil_Out32(REBOOT_STATUS_REG,
(Xil_In32(REBOOT_STATUS_REG)) & ~(FSBL_FAIL_MASK));
}
/******************************************************************************/
/**
*
* This function Registers the Exception Handlers
*
* @param None.
*
* @return None.
*
* @note None.
*
****************************************************************************/
static void RegisterHandlers(void)
{
Xil_ExceptionInit();
/*
* Initialize the vector table. Register the stub Handler for each
* exception.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_UNDEFINED_INT,
(Xil_ExceptionHandler)Undef_Handler,
(void *) 0);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_SWI_INT,
(Xil_ExceptionHandler)SVC_Handler,
(void *) 0);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_PREFETCH_ABORT_INT,
(Xil_ExceptionHandler)PreFetch_Abort_Handler,
(void *) 0);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_DATA_ABORT_INT,
(Xil_ExceptionHandler)Data_Abort_Handler,
(void *) 0);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)IRQ_Handler,(void *) 0);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_FIQ_INT,
(Xil_ExceptionHandler)FIQ_Handler,(void *) 0);
Xil_ExceptionEnable();
}
static void Undef_Handler (void)
{
fsbl_printf(DEBUG_GENERAL,"UNDEFINED_HANDLER\r\n");
ErrorLockdown (EXCEPTION_ID_UNDEFINED_INT);
}
static void SVC_Handler (void)
{
fsbl_printf(DEBUG_GENERAL,"SVC_HANDLER \r\n");
ErrorLockdown (EXCEPTION_ID_SWI_INT);
}
static void PreFetch_Abort_Handler (void)
{
fsbl_printf(DEBUG_GENERAL,"PREFETCH_ABORT_HANDLER \r\n");
ErrorLockdown (EXCEPTION_ID_PREFETCH_ABORT_INT);
}
static void Data_Abort_Handler (void)
{
fsbl_printf(DEBUG_GENERAL,"DATA_ABORT_HANDLER \r\n");
ErrorLockdown (EXCEPTION_ID_DATA_ABORT_INT);
}
static void IRQ_Handler (void)
{
fsbl_printf(DEBUG_GENERAL,"IRQ_HANDLER \r\n");
ErrorLockdown (EXCEPTION_ID_IRQ_INT);
}
static void FIQ_Handler (void)
{
fsbl_printf(DEBUG_GENERAL,"FIQ_HANDLER \r\n");
ErrorLockdown (EXCEPTION_ID_FIQ_INT);
}
/******************************************************************************/
/**
*
* This function Updates the Multi boot Register to enable golden image
* search for boot rom
*
* @param None
*
* @return
* return none
*
****************************************************************************/
static void Update_MultiBootRegister(void)
{
u32 MultiBootReg = 0;
if (Silicon_Version != SILICON_VERSION_1) {
/*
* Read the mulitboot register
*/
MultiBootReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,
XDCFG_MULTIBOOT_ADDR_OFFSET);
/*
* Incrementing multiboot register by one
*/
MultiBootReg++;
XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr,
XDCFG_MULTIBOOT_ADDR_OFFSET,
MultiBootReg);
fsbl_printf(DEBUG_INFO,"Updated MultiBootReg = 0x%08lx\r\n",
MultiBootReg);
}
}
/******************************************************************************
*
* This function reset the CPU and goes for Boot ROM fallback handling
*
* @param None
*
* @return None
*
* @note None
*
*******************************************************************************/
u32 GetResetReason(void)
{
u32 Regval;
/* We are using REBOOT_STATUS_REG, we have to use bits 23:16 */
/* for storing the RESET_REASON register value*/
Regval = ((Xil_In32(REBOOT_STATUS_REG) >> 16) & 0xFF);
return Regval;
}
/******************************************************************************
*
* This function Gets the ticks from the Global Timer
*
* @param Current time
*
* @return
* None
*
* @note None
*
*******************************************************************************/
#ifdef FSBL_PERF
void FsblGetGlobalTime (XTime *tCur)
{
XTime_GetTime(tCur);
}
/******************************************************************************
*
* This function Measures the execution time
*
* @param Current time , End time
*
* @return
* None
*
* @note None
*
*******************************************************************************/
void FsblMeasurePerfTime (XTime tCur, XTime tEnd)
{
double tDiff = 0.0;
double tPerfSeconds;
XTime_GetTime(&tEnd);
tDiff = (double)tEnd - (double)tCur;
/*
* Convert tPerf into Seconds
*/
tPerfSeconds = tDiff/COUNTS_PER_SECOND;
#if defined(STDOUT_BASEADDRESS)
printf("%f seconds \r\n",tPerfSeconds);
#endif
}
#endif
/******************************************************************************
*
* This function initializes the Watchdog driver and starts the timer
*
* @param None
*
* @return
* - XST_SUCCESS if the Watchdog driver is initialized
* - XST_FAILURE if Watchdog driver initialization fails
*
* @note None
*
*******************************************************************************/
#ifdef XPAR_XWDTPS_0_BASEADDR
int InitWatchDog(void)
{
u32 Status = XST_SUCCESS;
XWdtPs_Config *ConfigPtr; /* Config structure of the WatchDog Timer */
u32 CounterValue = 1;
ConfigPtr = XWdtPs_LookupConfig(WDT_DEVICE_ID);
Status = XWdtPs_CfgInitialize(&Watchdog,
ConfigPtr,
ConfigPtr->BaseAddress);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"Watchdog Driver init Failed \n\r");
return XST_FAILURE;
}
/*
* Setting the divider value
*/
XWdtPs_SetControlValue(&Watchdog,
XWDTPS_CLK_PRESCALE,
XWDTPS_CCR_PSCALE_4096);
/*
* Convert time to Watchdog counter reset value
*/
CounterValue = ConvertTime_WdtCounter(WDT_EXPIRE_TIME);
/*
* Set the Watchdog counter reset value
*/
XWdtPs_SetControlValue(&Watchdog,
XWDTPS_COUNTER_RESET,
CounterValue);
/*
* enable reset output, as we are only using this as a basic counter
*/
XWdtPs_EnableOutput(&Watchdog, XWDTPS_RESET_SIGNAL);
/*
* Start the Watchdog timer
*/
XWdtPs_Start(&Watchdog);
XWdtPs_RestartWdt(&Watchdog);
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function checks whether WDT reset has happened during FSBL run
*
* If WDT reset happened during FSBL run, then need to fallback
*
* @param None.
*
* @return
* None
*
* @note None
*
****************************************************************************/
void CheckWDTReset(void)
{
u32 ResetReason;
u32 RebootStatusRegister;
RebootStatusRegister = Xil_In32(REBOOT_STATUS_REG);
/*
* For 1.0 Silicon the reason for Reset is in the ResetReason Register
* Hence this register can be read to know the cause for previous reset
* that happened.
* Check if that reset is a Software WatchDog reset that happened
*/
if (Silicon_Version == SILICON_VERSION_1) {
ResetReason = Xil_In32(RESET_REASON_REG);
} else {
ResetReason = GetResetReason();
}
/*
* If the FSBL_IN_MASK Has not been cleared, WDT happened
* before FSBL exits
*/
if ((ResetReason & RESET_REASON_SWDT) == RESET_REASON_SWDT ) {
if ((RebootStatusRegister & FSBL_FAIL_MASK) == FSBL_IN_MASK) {
/*
* Clear the SWDT Reset bit
*/
ResetReason &= ~RESET_REASON_SWDT;
if (Silicon_Version == SILICON_VERSION_1) {
/*
* for 1.0 Silicon we need to write
* 1 to the RESET REASON Clear register
*/
Xil_Out32(RESET_REASON_CLR, 1);
} else {
Xil_Out32(REBOOT_STATUS_REG, ResetReason);
}
fsbl_printf(DEBUG_GENERAL,"WDT_RESET_OCCURED \n\r");
}
}
}
/******************************************************************************
*
* This function converts time into Watchdog counter value
*
* @param watchdog expire time in seconds
*
* @return
* Counter value for Watchdog
*
* @note None
*
*******************************************************************************/
u32 ConvertTime_WdtCounter(u32 seconds)
{
double time = 0.0;
double CounterValue;
u32 Crv = 0;
u32 Prescaler,PrescalerValue;
Prescaler = XWdtPs_GetControlValue(&Watchdog, XWDTPS_CLK_PRESCALE);
if (Prescaler == XWDTPS_CCR_PSCALE_0008)
PrescalerValue = 8;
if (Prescaler == XWDTPS_CCR_PSCALE_0064)
PrescalerValue = 64;
if (Prescaler == XWDTPS_CCR_PSCALE_4096)
PrescalerValue = 4096;
time = (double)(PrescalerValue) / (double)XPAR_PS7_WDT_0_WDT_CLK_FREQ_HZ;
CounterValue = seconds / time;
Crv = (u32)CounterValue;
Crv >>= WDT_CRV_SHIFT;
return Crv;
}
#endif
/******************************************************************************
*
* This function Gets the Silicon Version stores in global variable
*
* @param None
*
* @return None
*
* @note None
*
*******************************************************************************/
void GetSiliconVersion(void)
{
/*
* Get the silicon version
*/
Silicon_Version = XDcfg_GetPsVersion(DcfgInstPtr);
if(Silicon_Version == SILICON_VERSION_3_1) {
fsbl_printf(DEBUG_GENERAL,"Silicon Version 3.1\r\n");
} else {
fsbl_printf(DEBUG_GENERAL,"Silicon Version %lu.0\r\n",
Silicon_Version + 1);
}
}
/******************************************************************************
*
* This function HeaderChecksum will calculates the header checksum and
* compares with checksum read from flash
*
* @param FlashOffsetAddress Flash offset address
*
* @return
* - XST_SUCCESS if ID matches
* - XST_FAILURE if ID mismatches
*
* @note None
*
*******************************************************************************/
u32 HeaderChecksum(u32 FlashOffsetAddress){
u32 Checksum = 0;
u32 Count;
u32 TempValue = 0;
for (Count = 0; Count < IMAGE_HEADER_CHECKSUM_COUNT; Count++) {
/*
* Read the word from the header
*/
MoveImage(FlashOffsetAddress + IMAGE_WIDTH_CHECK_OFFSET + (Count*4), (u32)&TempValue, 4);
/*
* Update checksum
*/
Checksum += TempValue;
}
/*
* Invert checksum, last bit of error checking
*/
Checksum ^= 0xFFFFFFFF;
MoveImage(FlashOffsetAddress + IMAGE_CHECKSUM_OFFSET, (u32)&TempValue, 4);
/*
* Validate the checksum
*/
if (TempValue != Checksum){
fsbl_printf(DEBUG_INFO, "Checksum = %8.8lx\r\n", Checksum);
return XST_FAILURE;
}
return XST_SUCCESS;
}
/******************************************************************************
*
* This function ImageCheckID will do check for XLNX pattern
*
* @param FlashOffsetAddress Flash offset address
*
* @return
* - XST_SUCCESS if ID matches
* - XST_FAILURE if ID mismatches
*
* @note None
*
*******************************************************************************/
u32 ImageCheckID(u32 FlashOffsetAddress){
u32 ID;
/*
* Read in the header info
*/
MoveImage(FlashOffsetAddress + IMAGE_IDENT_OFFSET, (u32)&ID, 4);
/*
* Check the ID, make sure image is XLNX format
*/
if (ID != IMAGE_IDENT){
return XST_FAILURE;
}
return XST_SUCCESS;
}
/******************************************************************************
*
* This function NextValidImageCheck search for valid boot image
*
* @param None
*
* @return
* - XST_SUCCESS if valid image found
* - XST_FAILURE if no image found
*
* @note None
*
*******************************************************************************/
u32 NextValidImageCheck(void)
{
u32 ImageBaseAddr;
u32 MultiBootReg;
u32 BootDevMaxSize=0;
fsbl_printf(DEBUG_GENERAL, "Searching For Next Valid Image");
/*
* Setting variable with maximum flash size based on boot mode
*/
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR
if (FlashReadBaseAddress == XPS_QSPI_LINEAR_BASEADDR) {
BootDevMaxSize = QspiFlashSize;
}
#endif
if (FlashReadBaseAddress == XPS_NAND_BASEADDR) {
BootDevMaxSize = NAND_FLASH_SIZE;
}
if (FlashReadBaseAddress == XPS_NOR_BASEADDR) {
BootDevMaxSize = NOR_FLASH_SIZE;
}
/*
* Read the multiboot register
*/
MultiBootReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,
XDCFG_MULTIBOOT_ADDR_OFFSET);
/*
* Compute the image start address
*/
ImageBaseAddr = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK)
* GOLDEN_IMAGE_OFFSET;
/*
* Valid image search continue till end of the flash
* With increment 32KB in each iteration
*/
while (ImageBaseAddr < BootDevMaxSize) {
fsbl_printf(DEBUG_INFO,".");
/*
* Valid image search using XLNX pattern at fixed offset
* and header checksum
*/
if ((ImageCheckID(ImageBaseAddr) == XST_SUCCESS) &&
(HeaderChecksum(ImageBaseAddr) == XST_SUCCESS)) {
fsbl_printf(DEBUG_GENERAL, "\r\nImage found, offset: 0x%.8lx\r\n",
ImageBaseAddr);
/*
* Update multiboot register
*/
XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr,
XDCFG_MULTIBOOT_ADDR_OFFSET,
MultiBootReg);
return XST_SUCCESS;
}
/*
* Increment mulitboot count
*/
MultiBootReg++;
/*
* Compute the image start address
*/
ImageBaseAddr = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK)
* GOLDEN_IMAGE_OFFSET;
}
return XST_FAILURE;
}
/******************************************************************************/
/**
*
* This function Checks for the ddr initialization completion
*
* @param None.
*
* @return
* - XST_SUCCESS if the initialization is successful
* - XST_FAILURE if the initialization is NOT successful
*
* @note None.
*
****************************************************************************/
u32 DDRInitCheck(void)
{
u32 ReadVal;
/*
* Write and Read from the DDR location for sanity checks
*/
Xil_Out32(DDR_START_ADDR, DDR_TEST_PATTERN);
ReadVal = Xil_In32(DDR_START_ADDR);
if (ReadVal != DDR_TEST_PATTERN) {
return XST_FAILURE;
}
/*
* Write and Read from the DDR location for sanity checks
*/
Xil_Out32(DDR_START_ADDR + DDR_TEST_OFFSET, DDR_TEST_PATTERN);
ReadVal = Xil_In32(DDR_START_ADDR + DDR_TEST_OFFSET);
if (ReadVal != DDR_TEST_PATTERN) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
Image_mover.c修改
具体参看代码部分,这里只做简述:
Loadbootimage函数中对L2cache禁用
/******************************************************************************
*
* Copyright (C) 2011 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file image_mover.c
*
* Move partitions to either DDR to execute or to program FPGA.
* It performs partition walk.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a jz 05/24/11 Initial release
* 2.00a jz 06/30/11 Updated partition header defs for 64-byte
* alignment change in data2mem tool
* 2.00a mb 05/25/12 Updated for standalone based bsp FSBL
* Nand/SD encryption and review comments
* 3.00a np 08/30/12 Added FSBL user hook calls
* (before and after bitstream download.)
* 4.00a sgd 02/28/13 Fix for CR#691148 Secure bootmode error in devcfg test
* Fix for CR#695578 FSBL failed to load standalone
* application in secure bootmode
*
* 4.00a sgd 04/23/13 Fix for CR#710128 FSBL failed to load standalone
* application in secure bootmode
* 5.00a kc 07/30/13 Fix for CR#724165 Partition Header used by FSBL
* is not authenticated
* Fix for CR#724166 FSBL doesn�t use PPK authenticated
* by Boot ROM for authenticating the Partition images
* Fix for CR#732062 FSBL fails to build if UART not
* available
* 7.00a kc 10/30/13 Fix for CR#755245 FSBL does not load partition
* if eMMC has only one partition
* 8.00a kc 01/16/13 Fix for CR#767798 FSBL MD5 Checksum failure
* for encrypted images
* Fix for CR#761895 FSBL should authenticate image
* only if partition owner was not set to u-boot
* 9.00a kc 04/16/14 Fix for CR#785778 FSBL takes 8 seconds to
* authenticate (RSA) a bitstream on zc706
* 10.00a kc 07/15/14 Fix for CR#804595 Zynq FSBL - Issues with
* fallback image offset handling using MD5
* Fix for PR#782309 Fallback support for AES
* encryption with E-Fuse - Enhancement
*
* </pre>
*
* @note
* A partition is either an executable or a bitstream to program FPGA
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "fsbl.h"
#include "image_mover.h"
#include "xil_printf.h"
#include "xreg_cortexa9.h"
#include "pcap.h"
#include "fsbl_hooks.h"
#include "md5.h"
#include "xil_cache.h"
#include "xil_cache_l.h"
#ifdef XPAR_XWDTPS_0_BASEADDR
#include "xwdtps.h"
#endif
#ifdef RSA_SUPPORT
#include "rsa.h"
#include "xil_cache.h"
#endif
/************************** Constant Definitions *****************************/
/* We are 32-bit machine */
#define MAXIMUM_IMAGE_WORD_LEN 0x40000000
#define MD5_CHECKSUM_SIZE 16
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
u32 ValidateParition(u32 StartAddr, u32 Length, u32 ChecksumOffset);
u32 GetPartitionChecksum(u32 ChecksumOffset, u8 *Checksum);
u32 CalcPartitionChecksum(u32 SourceAddr, u32 DataLength, u8 *Checksum);
/************************** Variable Definitions *****************************/
/*
* Partition information flags
*/
u8 EncryptedPartitionFlag;
u8 PLPartitionFlag;
u8 PSPartitionFlag;
u8 SignedPartitionFlag;
u8 PartitionChecksumFlag;
u8 BitstreamFlag;
u8 ApplicationFlag;
u32 ExecutionAddress;
ImageMoverType MoveImage;
/*
* Header array
*/
PartHeader PartitionHeader[MAX_PARTITION_NUMBER];
u32 PartitionCount;
u32 FsblLength;
#ifdef XPAR_XWDTPS_0_BASEADDR
extern XWdtPs Watchdog; /* Instance of WatchDog Timer */
#endif
extern u32 Silicon_Version;
extern u32 FlashReadBaseAddress;
extern u8 LinearBootDeviceFlag;
extern XDcfg *DcfgInstPtr;
/*****************************************************************************/
/**
*
* This function
*
* @param
*
* @return
*
*
* @note None
*
****************************************************************************/
u32 LoadBootImage(void)
{
u32 RebootStatusRegister = 0;
u32 MultiBootReg = 0;
u32 ImageStartAddress = 0;
u32 PartitionNum;
u32 PartitionDataLength;
u32 PartitionImageLength;
u32 PartitionTotalSize;
u32 PartitionExecAddr;
u32 PartitionAttr;
u32 ExecAddress = 0;
u32 PartitionLoadAddr;
u32 PartitionStartAddr;
u32 PartitionChecksumOffset;
u8 ExecAddrFlag = 0 ;
u32 Status;
PartHeader *HeaderPtr;
u32 EfuseStatusRegValue;
#ifdef RSA_SUPPORT
u32 HeaderSize;
#endif
/*
* Resetting the Flags
*/
BitstreamFlag = 0;
ApplicationFlag = 0;
RebootStatusRegister = Xil_In32(REBOOT_STATUS_REG);
fsbl_printf(DEBUG_INFO,
"Reboot status register: 0x%08lx\r\n",RebootStatusRegister);
if (Silicon_Version == SILICON_VERSION_1) {
/*
* Clear out fallback mask from previous run
* We start from the first partition again
*/
if ((RebootStatusRegister & FSBL_FAIL_MASK) ==
FSBL_FAIL_MASK) {
fsbl_printf(DEBUG_INFO,
"Reboot status shows previous run falls back\r\n");
RebootStatusRegister &= ~(FSBL_FAIL_MASK);
Xil_Out32(REBOOT_STATUS_REG, RebootStatusRegister);
}
/*
* Read the image start address
*/
ImageStartAddress = *(u32 *)BASEADDR_HOLDER;
} else {
/*
* read the multiboot register
*/
MultiBootReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,
XDCFG_MULTIBOOT_ADDR_OFFSET);
fsbl_printf(DEBUG_INFO,"Multiboot Register: 0x%08lx\r\n",MultiBootReg);
/*
* Compute the image start address
*/
ImageStartAddress = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK)
* GOLDEN_IMAGE_OFFSET;
}
fsbl_printf(DEBUG_INFO,"Image Start Address: 0x%08lx\r\n",ImageStartAddress);
/*
* Get partitions header information
*/
Status = GetPartitionHeaderInfo(ImageStartAddress);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Partition Header Load Failed\r\n");
OutputStatus(GET_HEADER_INFO_FAIL);
FsblFallback();
}
/*
* RSA is not implemented in 1.0 and 2.0
* silicon
*/
if ((Silicon_Version != SILICON_VERSION_1) &&
(Silicon_Version != SILICON_VERSION_2)) {
/*
* Read Efuse Status Register
*/
EfuseStatusRegValue = Xil_In32(EFUSE_STATUS_REG);
if (EfuseStatusRegValue & EFUSE_STATUS_RSA_ENABLE_MASK) {
fsbl_printf(DEBUG_GENERAL,"RSA enabled for Chip\r\n");
#ifdef RSA_SUPPORT
/*
* Set the Ppk
*/
SetPpk();
/*
* Read partition header with signature
*/
Status = GetImageHeaderAndSignature(ImageStartAddress,
(u32 *)DDR_TEMP_START_ADDR);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,
"Read Partition Header signature Failed\r\n");
OutputStatus(GET_HEADER_INFO_FAIL);
FsblFallback();
}
HeaderSize=TOTAL_HEADER_SIZE+RSA_SIGNATURE_SIZE;
Status = AuthenticatePartition((u8 *)DDR_TEMP_START_ADDR, HeaderSize);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,
"Partition Header signature Failed\r\n");
OutputStatus(GET_HEADER_INFO_FAIL);
FsblFallback();
}
#else
/*
* In case user not enabled RSA authentication feature
*/
fsbl_printf(DEBUG_GENERAL,"RSA_SUPPORT_NOT_ENABLED_FAIL\r\n");
OutputStatus(RSA_SUPPORT_NOT_ENABLED_FAIL);
FsblFallback();
#endif
}
}
#ifdef MMC_SUPPORT
/*
* In case of MMC support
* boot image preset in MMC will not have FSBL partition
*/
PartitionNum = 0;
#else
/*
* First partition header was ignored by FSBL
* As it contain FSBL partition information
*/
PartitionNum = 1;
#endif
while (PartitionNum < PartitionCount) {
fsbl_printf(DEBUG_INFO, "Partition Number: %lu\r\n", PartitionNum);
HeaderPtr = &PartitionHeader[PartitionNum];
/*
* Print partition header information
*/
HeaderDump(HeaderPtr);
/*
* Validate partition header
*/
Status = ValidateHeader(HeaderPtr);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "INVALID_HEADER_FAIL\r\n");
OutputStatus(INVALID_HEADER_FAIL);
FsblFallback();
}
/*
* Load partition header information in to local variables
*/
PartitionDataLength = HeaderPtr->DataWordLen;
PartitionImageLength = HeaderPtr->ImageWordLen;
PartitionExecAddr = HeaderPtr->ExecAddr;
PartitionAttr = HeaderPtr->PartitionAttr;
PartitionLoadAddr = HeaderPtr->LoadAddr;
PartitionChecksumOffset = HeaderPtr->CheckSumOffset;
PartitionStartAddr = HeaderPtr->PartitionStart;
PartitionTotalSize = HeaderPtr->PartitionWordLen;
#ifndef DDRLESS_SYSTEM
/*
* Partition owner should be FSBL to validate the partition
*/
if ((PartitionAttr & ATTRIBUTE_PARTITION_OWNER_MASK) !=
ATTRIBUTE_PARTITION_OWNER_FSBL) {
/*
* if FSBL is not the owner of partition,
* skip this partition, continue with next partition
*/
fsbl_printf(DEBUG_INFO, "Skipping partition %0lx\r\n",
PartitionNum);
/*
* Increment partition number
*/
PartitionNum++;
continue;
}
#endif
if (PartitionAttr & ATTRIBUTE_PL_IMAGE_MASK) {
fsbl_printf(DEBUG_INFO, "Bitstream\r\n");
PLPartitionFlag = 1;
PSPartitionFlag = 0;
BitstreamFlag = 1;
if (ApplicationFlag == 1) {
#ifdef STDOUT_BASEADDRESS
xil_printf("\r\nFSBL Warning !!!"
"Bitstream not loaded into PL\r\n");
xil_printf("Partition order invalid\r\n");
#endif
break;
}
}
if (PartitionAttr & ATTRIBUTE_PS_IMAGE_MASK) {
fsbl_printf(DEBUG_INFO, "Application\r\n");
PSPartitionFlag = 1;
PLPartitionFlag = 0;
ApplicationFlag = 1;
}
/*
* Encrypted partition will have different value
* for Image length and data length
*/
if (PartitionDataLength != PartitionImageLength) {
fsbl_printf(DEBUG_INFO, "Encrypted\r\n");
EncryptedPartitionFlag = 1;
} else {
EncryptedPartitionFlag = 0;
}
/*
* Check for partition checksum check
*/
if (PartitionAttr & ATTRIBUTE_CHECKSUM_TYPE_MASK) {
PartitionChecksumFlag = 1;
} else {
PartitionChecksumFlag = 0;
}
/*
* RSA signature check
*/
if (PartitionAttr & ATTRIBUTE_RSA_PRESENT_MASK) {
fsbl_printf(DEBUG_INFO, "RSA Signed\r\n");
SignedPartitionFlag = 1;
} else {
SignedPartitionFlag = 0;
}
/*
* Load address check
* Loop will break when PS load address zero and partition is
* un-signed or un-encrypted
*/
#ifndef DDRLESS_SYSTEM
if ((PSPartitionFlag == 1) && (PartitionLoadAddr < DDR_START_ADDR)) {
if ((PartitionLoadAddr == 0) &&
(!((SignedPartitionFlag == 1) ||
(EncryptedPartitionFlag == 1)))) {
break;
} else {
fsbl_printf(DEBUG_GENERAL,
"INVALID_LOAD_ADDRESS_FAIL\r\n");
OutputStatus(INVALID_LOAD_ADDRESS_FAIL);
FsblFallback();
}
}
if (PSPartitionFlag && (PartitionLoadAddr > DDR_END_ADDR)) {
fsbl_printf(DEBUG_GENERAL,
"INVALID_LOAD_ADDRESS_FAIL\r\n");
OutputStatus(INVALID_LOAD_ADDRESS_FAIL);
FsblFallback();
}
#endif
/*
* Load execution address of first PS partition
*/
if (PSPartitionFlag && (!ExecAddrFlag)) {
ExecAddrFlag++;
ExecAddress = PartitionExecAddr;
}
/*
* FSBL user hook call before bitstream download
*/
if (PLPartitionFlag) {
Status = FsblHookBeforeBitstreamDload();
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"FSBL_BEFORE_BSTREAM_HOOK_FAIL\r\n");
OutputStatus(FSBL_BEFORE_BSTREAM_HOOK_FAIL);
FsblFallback();
}
}
/*
* Move partitions from boot device
*/
#ifdef DDRLESS_SYSTEM
Xil_L2CacheEnable();
Xil_L1DCacheDisable();
Xil_L1ICacheDisable();
#endif
Status = PartitionMove(ImageStartAddress, HeaderPtr);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE_FAIL\r\n");
OutputStatus(PARTITION_MOVE_FAIL);
FsblFallback();
} else {
fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE Successful\r\n");
}
if ((SignedPartitionFlag) || (PartitionChecksumFlag)) {
if(PLPartitionFlag) {
/*
* PL partition loaded in to DDR temporary address
* for authentication and checksum verification
*/
PartitionStartAddr = DDR_TEMP_START_ADDR;
} else {
PartitionStartAddr = PartitionLoadAddr;
}
if (PartitionChecksumFlag) {
/*
* Validate the partition data with checksum
*/
Status = ValidateParition(PartitionStartAddr,
(PartitionTotalSize << WORD_LENGTH_SHIFT),
ImageStartAddress +
(PartitionChecksumOffset << WORD_LENGTH_SHIFT));
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"PARTITION_CHECKSUM_FAIL\r\n");
OutputStatus(PARTITION_CHECKSUM_FAIL);
FsblFallback();
}
fsbl_printf(DEBUG_INFO, "Partition Validation Done\r\n");
}
/*
* Authentication Partition
*/
if (SignedPartitionFlag == 1 ) {
#ifdef RSA_SUPPORT
Xil_DCacheEnable();
Status = AuthenticatePartition((u8*)PartitionStartAddr,
(PartitionTotalSize << WORD_LENGTH_SHIFT));
if (Status != XST_SUCCESS) {
Xil_DCacheFlush();
Xil_DCacheDisable();
fsbl_printf(DEBUG_GENERAL,"AUTHENTICATION_FAIL\r\n");
OutputStatus(AUTHENTICATION_FAIL);
FsblFallback();
}
fsbl_printf(DEBUG_INFO,"Authentication Done\r\n");
Xil_DCacheFlush();
Xil_DCacheDisable();
#else
/*
* In case user not enabled RSA authentication feature
*/
fsbl_printf(DEBUG_GENERAL,"RSA_SUPPORT_NOT_ENABLED_FAIL\r\n");
OutputStatus(RSA_SUPPORT_NOT_ENABLED_FAIL);
FsblFallback();
#endif
}
/*
* Decrypt PS partition
*/
if (EncryptedPartitionFlag && PSPartitionFlag) {
Status = DecryptPartition(PartitionStartAddr,
PartitionDataLength,
PartitionImageLength);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"DECRYPTION_FAIL\r\n");
OutputStatus(DECRYPTION_FAIL);
FsblFallback();
}
}
/*
* Load Signed PL partition in Fabric
*/
if (PLPartitionFlag) {
Status = PcapLoadPartition((u32*)PartitionStartAddr,
(u32*)PartitionLoadAddr,
PartitionImageLength,
PartitionDataLength,
EncryptedPartitionFlag);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"BITSTREAM_DOWNLOAD_FAIL\r\n");
OutputStatus(BITSTREAM_DOWNLOAD_FAIL);
FsblFallback();
}
}
}
/*
* FSBL user hook call after bitstream download
*/
if (PLPartitionFlag) {
Status = FsblHookAfterBitstreamDload();
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"FSBL_AFTER_BSTREAM_HOOK_FAIL\r\n");
OutputStatus(FSBL_AFTER_BSTREAM_HOOK_FAIL);
FsblFallback();
}
}
/*
* Increment partition number
*/
PartitionNum++;
}
return ExecAddress;
}
/*****************************************************************************/
/**
*
* This function loads all partition header information in global array
*
* @param ImageAddress is the start address of the image
*
* @return - XST_SUCCESS if Get partition Header information successful
* - XST_FAILURE if Get Partition Header information failed
*
* @note None
*
****************************************************************************/
u32 GetPartitionHeaderInfo(u32 ImageBaseAddress)
{
u32 PartitionHeaderOffset;
u32 Status;
/*
* Get the length of the FSBL from BootHeader
*/
Status = GetFsblLength(ImageBaseAddress, &FsblLength);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n");
return XST_FAILURE;
}
/*
* Get the start address of the partition header table
*/
Status = GetPartitionHeaderStartAddr(ImageBaseAddress,
&PartitionHeaderOffset);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n");
return XST_FAILURE;
}
/*
* Header offset on flash
*/
PartitionHeaderOffset += ImageBaseAddress;
fsbl_printf(DEBUG_INFO,"Partition Header Offset:0x%08lx\r\n",
PartitionHeaderOffset);
/*
* Load all partitions header data in to global variable
*/
Status = LoadPartitionsHeaderInfo(PartitionHeaderOffset,
&PartitionHeader[0]);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Header Information Load Failed\r\n");
return XST_FAILURE;
}
/*
* Get partitions count from partitions header information
*/
PartitionCount = GetPartitionCount(&PartitionHeader[0]);
fsbl_printf(DEBUG_INFO, "Partition Count: %lu\r\n", PartitionCount);
/*
* Partition Count check
*/
if (PartitionCount >= MAX_PARTITION_NUMBER) {
fsbl_printf(DEBUG_GENERAL, "Invalid Partition Count\r\n");
return XST_FAILURE;
#ifndef MMC_SUPPORT
} else if (PartitionCount <= 1) {
fsbl_printf(DEBUG_GENERAL, "There is no partition to load\r\n");
return XST_FAILURE;
#endif
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function goes to the partition header of the specified partition
*
* @param ImageAddress is the start address of the image
*
* @return Offset Partition header address of the image
*
* @return - XST_SUCCESS if Get Partition Header start address successful
* - XST_FAILURE if Get Partition Header start address failed
*
* @note None
*
****************************************************************************/
u32 GetPartitionHeaderStartAddr(u32 ImageAddress, u32 *Offset)
{
u32 Status;
Status = MoveImage(ImageAddress + IMAGE_PHDR_OFFSET, (u32)Offset, 4);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function goes to the partition header of the specified partition
*
* @param ImageAddress is the start address of the image
*
* @return Offset to Image header table address of the image
*
* @return - XST_SUCCESS if Get Partition Header start address successful
* - XST_FAILURE if Get Partition Header start address failed
*
* @note None
*
****************************************************************************/
u32 GetImageHeaderStartAddr(u32 ImageAddress, u32 *Offset)
{
u32 Status;
Status = MoveImage(ImageAddress + IMAGE_HDR_OFFSET, (u32)Offset, 4);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function gets the length of the FSBL
*
* @param ImageAddress is the start address of the image
*
* @return FsblLength is the length of the fsbl
*
* @return - XST_SUCCESS if fsbl length reading is successful
* - XST_FAILURE if fsbl length reading failed
*
* @note None
*
****************************************************************************/
u32 GetFsblLength(u32 ImageAddress, u32 *FsblLength)
{
u32 Status;
Status = MoveImage(ImageAddress + IMAGE_TOT_BYTE_LEN_OFFSET,
(u32)FsblLength, 4);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Move Image failed reading FsblLength\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
#ifdef RSA_SUPPORT
/*****************************************************************************/
/**
*
* This function goes to read the image headers and its signature. Image
* header consists of image header table, image headers, partition
* headers
*
* @param ImageBaseAddress is the start address of the image header
*
* @return Offset Partition header address of the image
*
* @return - XST_SUCCESS if Get Partition Header start address successful
* - XST_FAILURE if Get Partition Header start address failed
*
* @note None
*
****************************************************************************/
u32 GetImageHeaderAndSignature(u32 ImageBaseAddress, u32 *Offset)
{
u32 Status;
u32 ImageHeaderOffset;
/*
* Get the start address of the partition header table
*/
Status = GetImageHeaderStartAddr(ImageBaseAddress, &ImageHeaderOffset);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n");
return XST_FAILURE;
}
Status = MoveImage(ImageBaseAddress+ImageHeaderOffset, (u32)Offset,
TOTAL_HEADER_SIZE + RSA_SIGNATURE_SIZE);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
#endif
/*****************************************************************************/
/**
*
* This function get the header information of the all the partitions and load into
* global array
*
* @param PartHeaderOffset Offset address where the header information present
*
* @param Header Partition header pointer
*
* @return - XST_SUCCESS if Load Partitions Header information successful
* - XST_FAILURE if Load Partitions Header information failed
*
* @note None
*
****************************************************************************/
u32 LoadPartitionsHeaderInfo(u32 PartHeaderOffset, PartHeader *Header)
{
u32 Status;
Status = MoveImage(PartHeaderOffset, (u32)Header, sizeof(PartHeader)*MAX_PARTITION_NUMBER);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Move Image failed\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function dumps the partition header.
*
* @param Header Partition header pointer
*
* @return None
*
* @note None
*
******************************************************************************/
void HeaderDump(PartHeader *Header)
{
fsbl_printf(DEBUG_INFO, "Header Dump\r\n");
fsbl_printf(DEBUG_INFO, "Image Word Len: 0x%08lx\r\n",
Header->ImageWordLen);
fsbl_printf(DEBUG_INFO, "Data Word Len: 0x%08lx\r\n",
Header->DataWordLen);
fsbl_printf(DEBUG_INFO, "Partition Word Len:0x%08lx\r\n",
Header->PartitionWordLen);
fsbl_printf(DEBUG_INFO, "Load Addr: 0x%08lx\r\n",
Header->LoadAddr);
fsbl_printf(DEBUG_INFO, "Exec Addr: 0x%08lx\r\n",
Header->ExecAddr);
fsbl_printf(DEBUG_INFO, "Partition Start: 0x%08lx\r\n",
Header->PartitionStart);
fsbl_printf(DEBUG_INFO, "Partition Attr: 0x%08lx\r\n",
Header->PartitionAttr);
fsbl_printf(DEBUG_INFO, "Partition Checksum Offset: 0x%08lx\r\n",
Header->CheckSumOffset);
fsbl_printf(DEBUG_INFO, "Section Count: 0x%08lx\r\n",
Header->SectionCount);
fsbl_printf(DEBUG_INFO, "Checksum: 0x%08lx\r\n",
Header->CheckSum);
}
/******************************************************************************/
/**
*
* This function calculates the partitions count from header information
*
* @param Header Partition header pointer
*
* @return Count Partition count
*
* @note None
*
*******************************************************************************/
u32 GetPartitionCount(PartHeader *Header)
{
u32 Count=0;
struct HeaderArray *Hap;
for(Count = 0; Count < MAX_PARTITION_NUMBER; Count++) {
Hap = (struct HeaderArray *)&Header[Count];
if(IsLastPartition(Hap)!=XST_FAILURE)
break;
}
return Count;
}
/******************************************************************************/
/**
* This function check whether the current partition is the end of partitions
*
* The partition is the end of the partitions if it looks like this:
* 0x00000000
* 0x00000000
* ....
* 0x00000000
* 0x00000000
* 0xFFFFFFFF
*
* @param H is a pointer to struct HeaderArray
*
* @return
* - XST_SUCCESS if it is the last partition
* - XST_FAILURE if it is not last partition
*
****************************************************************************/
u32 IsLastPartition(struct HeaderArray *H)
{
int Index;
if (H->Fields[PARTITION_HDR_CHECKSUM_WORD_COUNT] != 0xFFFFFFFF) {
return XST_FAILURE;
}
for (Index = 0; Index < PARTITION_HDR_WORD_COUNT - 1; Index++) {
if (H->Fields[Index] != 0x0) {
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function validates the partition header.
*
* @param Header Partition header pointer
*
* @return
* - XST_FAILURE if bad header.
* - XST_SUCCESS if successful.
*
* @note None
*
*******************************************************************************/
u32 ValidateHeader(PartHeader *Header)
{
struct HeaderArray *Hap;
Hap = (struct HeaderArray *)Header;
/*
* If there are no partitions to load, fail
*/
if (IsEmptyHeader(Hap) == XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "IMAGE_HAS_NO_PARTITIONS\r\n");
return XST_FAILURE;
}
/*
* Validate partition header checksum
*/
if (ValidatePartitionHeaderChecksum(Hap) != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "PARTITION_HEADER_CORRUPTION\r\n");
return XST_FAILURE;
}
/*
* Validate partition data size
*/
if (Header->ImageWordLen > MAXIMUM_IMAGE_WORD_LEN) {
fsbl_printf(DEBUG_GENERAL, "INVALID_PARTITION_LENGTH\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
* This function check whether the current partition header is empty.
* A partition header is considered empty if image word length is 0 and the
* last word is 0.
*
* @param H is a pointer to struct HeaderArray
*
* @return
* - XST_SUCCESS , If the partition header is empty
* - XST_FAILURE , If the partition header is NOT empty
*
* @note Caller is responsible to make sure the address is valid.
*
*
****************************************************************************/
u32 IsEmptyHeader(struct HeaderArray *H)
{
int Index;
for (Index = 0; Index < PARTITION_HDR_WORD_COUNT; Index++) {
if (H->Fields[Index] != 0x0) {
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function checks the header checksum If the header checksum is not valid
* XST_FAILURE is returned.
*
* @param H is a pointer to struct HeaderArray
*
* @return
* - XST_SUCCESS is header checksum is ok
* - XST_FAILURE if the header checksum is not correct
*
* @note None.
*
****************************************************************************/
u32 ValidatePartitionHeaderChecksum(struct HeaderArray *H)
{
u32 Checksum;
u32 Count;
Checksum = 0;
for (Count = 0; Count < PARTITION_HDR_CHECKSUM_WORD_COUNT; Count++) {
/*
* Read the word from the header
*/
Checksum += H->Fields[Count];
}
/*
* Invert checksum, last bit of error checking
*/
Checksum ^= 0xFFFFFFFF;
/*
* Validate the checksum
*/
if (H->Fields[PARTITION_HDR_CHECKSUM_WORD_COUNT] != Checksum) {
fsbl_printf(DEBUG_GENERAL, "Error: Checksum 0x%8.8lx != 0x%8.8lx\r\n",
Checksum, H->Fields[PARTITION_HDR_CHECKSUM_WORD_COUNT]);
return XST_FAILURE;
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function load the partition from boot device
*
* @param ImageBaseAddress Base address on flash
* @param Header Partition header pointer
*
* @return
* - XST_SUCCESS if partition move successful
* - XST_FAILURE if check failed move failed
*
* @note None
*
*******************************************************************************/
u32 PartitionMove(u32 ImageBaseAddress, PartHeader *Header)
{
u32 SourceAddr;
u32 Status=0;
u8 SecureTransferFlag = 0;
u32 LoadAddr;
u32 ImageWordLen;
u32 DataWordLen;
u32 ExecuionAddr;
SourceAddr = ImageBaseAddress;
SourceAddr += Header->PartitionStart<<WORD_LENGTH_SHIFT;
LoadAddr = Header->LoadAddr;
ImageWordLen = Header->ImageWordLen;
DataWordLen = Header->DataWordLen;
ExecuionAddr = Header->ExecAddr;
/*
* Add flash base address for linear boot devices
*/
if (LinearBootDeviceFlag) {
SourceAddr += FlashReadBaseAddress;
}
/*
* Partition encrypted
*/
if(EncryptedPartitionFlag) {
SecureTransferFlag = 1;
}
/*
* For Signed or checksum enabled partition,
* Total partition image need to copied to DDR
*/
if (SignedPartitionFlag || PartitionChecksumFlag) {
ImageWordLen = Header->PartitionWordLen;
DataWordLen = Header->PartitionWordLen;
}
/*
* Encrypted and Signed PS partition need to be loaded on to DDR
* without decryption
*/
if (PSPartitionFlag &&
(SignedPartitionFlag || PartitionChecksumFlag) &&
EncryptedPartitionFlag) {
SecureTransferFlag = 0;
}
/*
* CPU is used for data transfer in case of non-linear
* boot device
*/
if (!LinearBootDeviceFlag) {
/*
* PL partition copied to DDR temporary location
*/
if (PLPartitionFlag) {
LoadAddr = DDR_TEMP_START_ADDR;
}
#ifdef DDRLESS_SYSTEM
fsbl_printf(DEBUG_GENERAL,"Source Address %x\n\r",(FlashReadBaseAddress + SourceAddr));
fsbl_printf(DEBUG_GENERAL,"DataWordLen %x\n\r",(DataWordLen << WORD_LENGTH_SHIFT));
fsbl_printf(DEBUG_GENERAL,"LoadAddr %x\n\r",LoadAddr);
if(ExecuionAddr &&(LoadAddr && FlashReadBaseAddress))
{
Status=preload_funct((FlashReadBaseAddress + SourceAddr), (ImageWordLen << WORD_LENGTH_SHIFT));
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "preload_funct failed\r\n");
return XST_FAILURE;
}
}
#else
Status = MoveImage(SourceAddr,
LoadAddr,
(ImageWordLen << WORD_LENGTH_SHIFT));
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Move Image Failed\r\n");
return XST_FAILURE;
}
/*
* As image present at load address
*/
SourceAddr = LoadAddr;
#endif
}
if ((LinearBootDeviceFlag && PLPartitionFlag &&
(SignedPartitionFlag || PartitionChecksumFlag)) ||
(LinearBootDeviceFlag && PSPartitionFlag) ||
((!LinearBootDeviceFlag) && PSPartitionFlag && SecureTransferFlag)) {
/*
* PL signed partition copied to DDR temporary location
* using non-secure PCAP for linear boot device
*/
if(PLPartitionFlag){
SecureTransferFlag = 0;
LoadAddr = DDR_TEMP_START_ADDR;
}
/*
* Data transfer using PCAP
*/
Status = PcapDataTransfer((u32*)SourceAddr,
(u32*)LoadAddr,
ImageWordLen,
DataWordLen,
SecureTransferFlag);
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "PCAP Data Transfer Failed\r\n");
return XST_FAILURE;
}
/*
* As image present at load address
*/
SourceAddr = LoadAddr;
}
/*
* Load Bitstream partition in to fabric only
* if checksum and authentication bits are not set
*/
if (PLPartitionFlag && (!(SignedPartitionFlag || PartitionChecksumFlag))) {
SourceAddr += FlashReadBaseAddress;
Status = PcapLoadPartition((u32*)SourceAddr,
(u32*)Header->LoadAddr,
Header->ImageWordLen,
Header->DataWordLen,
EncryptedPartitionFlag);
if(Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "PCAP Bitstream Download Failed\r\n");
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function load the decrypts partition
*
* @param StartAddr Source start address
* @param DataLength Data length in words
* @param ImageLength Image length in words
*
* @return
* - XST_SUCCESS if decryption successful
* - XST_FAILURE if decryption failed
*
* @note None
*
*******************************************************************************/
u32 DecryptPartition(u32 StartAddr, u32 DataLength, u32 ImageLength)
{
u32 Status;
u8 SecureTransferFlag =1;
/*
* Data transfer using PCAP
*/
Status = PcapDataTransfer((u32*)StartAddr,
(u32*)StartAddr,
ImageLength,
DataLength,
SecureTransferFlag);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"PCAP Data Transfer failed \r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function Validate Partition Data by using checksum preset in image
*
* @param Partition header pointer
* @param Partition check sum offset
* @return
* - XST_SUCCESS if partition data is ok
* - XST_FAILURE if partition data is corrupted
*
* @note None
*
*******************************************************************************/
u32 ValidateParition(u32 StartAddr, u32 Length, u32 ChecksumOffset)
{
u8 Checksum[MD5_CHECKSUM_SIZE];
u8 CalcChecksum[MD5_CHECKSUM_SIZE];
u32 Status;
u32 Index;
#ifdef XPAR_XWDTPS_0_BASEADDR
/*
* Prevent WDT reset
*/
XWdtPs_RestartWdt(&Watchdog);
#endif
/*
* Get checksum from flash
*/
Status = GetPartitionChecksum(ChecksumOffset, &Checksum[0]);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
fsbl_printf(DEBUG_INFO, "Actual checksum\r\n");
for (Index = 0; Index < MD5_CHECKSUM_SIZE; Index++) {
fsbl_printf(DEBUG_INFO, "0x%0x ",Checksum[Index]);
}
fsbl_printf(DEBUG_INFO, "\r\n");
/*
* Calculate checksum for the partition
*/
Status = CalcPartitionChecksum(StartAddr, Length, &CalcChecksum[0]);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
fsbl_printf(DEBUG_INFO, "Calculated checksum\r\n");
for (Index = 0; Index < MD5_CHECKSUM_SIZE; Index++) {
fsbl_printf(DEBUG_INFO, "0x%0x ",CalcChecksum[Index]);
}
fsbl_printf(DEBUG_INFO, "\r\n");
/*
* Compare actual checksum with the calculated checksum
*/
for (Index = 0; Index < MD5_CHECKSUM_SIZE; Index++) {
if(Checksum[Index] != CalcChecksum[Index]) {
fsbl_printf(DEBUG_GENERAL, "Error: "
"Partition DataChecksum 0x%0x!= 0x%0x\r\n",
Checksum[Index], CalcChecksum[Index]);
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function gets partition checksum from flash
*
* @param Check sum offset
* @param Checksum pointer
* @return
* - XST_SUCCESS if checksum read success
* - XST_FAILURE if unable get checksum
*
* @note None
*
*******************************************************************************/
u32 GetPartitionChecksum(u32 ChecksumOffset, u8 *Checksum)
{
u32 Status;
Status = MoveImage(ChecksumOffset, (u32)Checksum, MD5_CHECKSUM_SIZE);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function calculates the checksum preset in image
*
* @param Start address
* @param Length of the data
* @param Checksum pointer
*
* @return
* - XST_SUCCESS if Checksum calculate successful
* - XST_FAILURE if Checksum calculate failed
*
* @note None
*
*******************************************************************************/
u32 CalcPartitionChecksum(u32 SourceAddr, u32 DataLength, u8 *Checksum)
{
/*
* Calculate checksum using MD5 algorithm
*/
md5((u8*)SourceAddr, DataLength, Checksum, 0 );
return XST_SUCCESS;
}
Qspi.c修改
由于FSBL需要在QSPI中执行,所以Qspi.c中需要在InitQspi函数中取消对QSPI FLASH的再次初始化,同时修改QSPIAccess函数中对QSPI FLASH的访问方式,强制为线性模式访问。具体参考代码。
/******************************************************************************
*
* Copyright (C) 2012 - 2016 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file qspi.c
*
* Contains code for the QSPI FLASH functionality.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a ecm 01/10/10 Initial release
* 3.00a mb 25/06/12 InitQspi, data is read first and required config bits
* are set
* 4.00a sg 02/28/13 Cleanup
* Removed LPBK_DLY_ADJ register setting code as we use
* divisor 8
* 5.00a sgd 05/17/13 Added Flash Size > 128Mbit support
* Dual Stack support
* Fix for CR:721674 - FSBL- Failed to boot from Dual
* stacked QSPI
* 6.00a kc 08/30/13 Fix for CR#722979 - Provide customer-friendly
* changelogs in FSBL
* Fix for CR#739711 - FSBL not able to read Large QSPI
* (512M) in IO Mode
* 7.00a kc 10/25/13 Fix for CR#739968 - FSBL should do the QSPI config
* settings for Dual parallel
* configuration in IO mode
* 14.0 gan 01/13/16 Fix for CR#869081 - (2016.1)FSBL picks the qspi read
* command from LQSPI_CFG register
* instead of hard coded read
* command (0x6B).
*
* </pre>
*
* @note
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "qspi.h"
#include "image_mover.h"
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR
#include "xqspips_hw.h"
#include "xqspips.h"
/************************** Constant Definitions *****************************/
/*
* The following constants map to the XPAR parameters created in the
* xparameters.h file. They are defined here such that a user can easily
* change all the needed parameters in one place.
*/
#define QSPI_DEVICE_ID XPAR_XQSPIPS_0_DEVICE_ID
/*
* The following constants define the commands which may be sent to the FLASH
* device.
*/
#define QUAD_READ_CMD 0x6B
#define READ_ID_CMD 0x9F
#define WRITE_ENABLE_CMD 0x06
#define BANK_REG_RD 0x16
#define BANK_REG_WR 0x17
/* Bank register is called Extended Address Reg in Micron */
#define EXTADD_REG_RD 0xC8
#define EXTADD_REG_WR 0xC5
#define COMMAND_OFFSET 0 /* FLASH instruction */
#define ADDRESS_1_OFFSET 1 /* MSB byte of address to read or write */
#define ADDRESS_2_OFFSET 2 /* Middle byte of address to read or write */
#define ADDRESS_3_OFFSET 3 /* LSB byte of address to read or write */
#define DATA_OFFSET 4 /* Start of Data for Read/Write */
#define DUMMY_OFFSET 4 /* Dummy byte offset for fast, dual and quad
reads */
#define DUMMY_SIZE 1 /* Number of dummy bytes for fast, dual and
quad reads */
#define RD_ID_SIZE 4 /* Read ID command + 3 bytes ID response */
#define BANK_SEL_SIZE 2 /* BRWR or EARWR command + 1 byte bank value */
#define WRITE_ENABLE_CMD_SIZE 1 /* WE command */
/*
* The following constants specify the extra bytes which are sent to the
* FLASH on the QSPI interface, that are not data, but control information
* which includes the command and address
*/
#define OVERHEAD_SIZE 4
/*
* The following constants specify the max amount of data and the size of the
* the buffer required to hold the data and overhead to transfer the data to
* and from the FLASH.
*/
#define DATA_SIZE 4096
/*
* The following defines are for dual flash interface.
*/
#define LQSPI_CR_FAST_QUAD_READ 0x0000006B /* Fast Quad Read output */
#define LQSPI_CR_1_DUMMY_BYTE 0x00000100 /* 1 Dummy Byte between
address and return data */
#define SINGLE_QSPI_CONFIG_QUAD_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \
LQSPI_CR_1_DUMMY_BYTE | \
LQSPI_CR_FAST_QUAD_READ)
#define DUAL_QSPI_CONFIG_QUAD_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \
XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \
XQSPIPS_LQSPI_CR_SEP_BUS_MASK | \
LQSPI_CR_1_DUMMY_BYTE | \
LQSPI_CR_FAST_QUAD_READ)
#define DUAL_STACK_CONFIG_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \
LQSPI_CR_1_DUMMY_BYTE | \
LQSPI_CR_FAST_QUAD_READ)
#define SINGLE_QSPI_IO_CONFIG_QUAD_READ (LQSPI_CR_1_DUMMY_BYTE | \
LQSPI_CR_FAST_QUAD_READ)
#define DUAL_QSPI_IO_CONFIG_QUAD_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \
XQSPIPS_LQSPI_CR_SEP_BUS_MASK | \
LQSPI_CR_1_DUMMY_BYTE | \
LQSPI_CR_FAST_QUAD_READ)
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/************************** Variable Definitions *****************************/
XQspiPs QspiInstance;
XQspiPs *QspiInstancePtr;
u32 QspiFlashSize;
u32 QspiFlashMake;
extern u32 FlashReadBaseAddress;
extern u8 LinearBootDeviceFlag;
/*
* The following variables are used to read and write to the eeprom and they
* are global to avoid having large buffers on the stack
*/
u8 ReadBuffer[DATA_SIZE + DATA_OFFSET + DUMMY_SIZE];
u8 WriteBuffer[DATA_OFFSET + DUMMY_SIZE];
/******************************************************************************/
/**
*
* This function initializes the controller for the QSPI interface.
*
* @param None
*
* @return None
*
* @note None
*
****************************************************************************/
u32 InitQspi(void)
{
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR
u32 QspiControlReg = 0;
u32 QspiDelayReg = 0;
u32 Prescaler = XQSPIPS_CLK_PRESCALE_8;
#ifndef QSPI_XIP
/* Fix for CR #664560 */
QspiControlReg = Xil_In32((XPS_QSPI_BASEADDR + XQSPIPS_CR_OFFSET));
/* Change the baud rate to DIV/8 prescaler value */
QspiControlReg &= ~XQSPIPS_CR_PRESC_MASK;
QspiControlReg |= (u32) (Prescaler & XQSPIPS_CR_PRESC_MAXIMUM) <<
XQSPIPS_CR_PRESC_SHIFT;
Xil_Out32((XPS_QSPI_BASEADDR + XQSPIPS_CR_OFFSET), QspiControlReg);
/*
* Set the USE loopback bit
* Fix for the CR #664560
* Delay DLY1 = 0
* Delay DLY0 = 0
*/
QspiDelayReg = Xil_In32((XPS_QSPI_BASEADDR +
XQSPIPS_LPBK_DLY_ADJ_OFFSET));
QspiDelayReg &= FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY_VALUE;
Xil_Out32((XPS_QSPI_BASEADDR + XQSPIPS_LPBK_DLY_ADJ_OFFSET),
QspiDelayReg);
fsbl_printf(DEBUG_INFO, "QSPI initialized with Control value = 0x%x \n \r",
Xil_In32(XPS_QSPI_BASEADDR +
XQSPIPS_CR_OFFSET));
fsbl_printf(DEBUG_INFO, "QSPI loopback register value = 0x%x \n \r",
Xil_In32(XPS_QSPI_BASEADDR +
XQSPIPS_LPBK_DLY_ADJ_OFFSET));
#endif
#endif
return XST_SUCCESS;
}
/******************************************************************************
*
* This function reads serial FLASH ID connected to the SPI interface.
* It then deduces the make and size of the flash and obtains the
* connection mode to point to corresponding parameters in the flash
* configuration table. The flash driver will function based on this and
* it presently supports Micron and Spansion - 128, 256 and 512Mbit and
* Winbond 128Mbit
*
* @param none
*
* @return XST_SUCCESS if read id, otherwise XST_FAILURE.
*
* @note None.
*
******************************************************************************/
u32 FlashReadID(void)
{
u32 Status;
/*
* Read ID in Auto mode.
*/
WriteBuffer[COMMAND_OFFSET] = READ_ID_CMD;
WriteBuffer[ADDRESS_1_OFFSET] = 0x00; /* 3 dummy bytes */
WriteBuffer[ADDRESS_2_OFFSET] = 0x00;
WriteBuffer[ADDRESS_3_OFFSET] = 0x00;
Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer,
RD_ID_SIZE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
fsbl_printf(DEBUG_INFO,"Single Flash Information\r\n");
fsbl_printf(DEBUG_INFO,"FlashID=0x%x 0x%x 0x%x\r\n", ReadBuffer[1],
ReadBuffer[2],
ReadBuffer[3]);
/*
* Deduce flash make
*/
if (ReadBuffer[1] == MICRON_ID) {
QspiFlashMake = MICRON_ID;
fsbl_printf(DEBUG_INFO, "MICRON ");
} else if(ReadBuffer[1] == SPANSION_ID) {
QspiFlashMake = SPANSION_ID;
fsbl_printf(DEBUG_INFO, "SPANSION ");
} else if(ReadBuffer[1] == WINBOND_ID) {
QspiFlashMake = WINBOND_ID;
fsbl_printf(DEBUG_INFO, "WINBOND ");
}
/*
* Deduce flash Size
*/
if (ReadBuffer[3] == FLASH_SIZE_ID_128M) {
QspiFlashSize = FLASH_SIZE_128M;
fsbl_printf(DEBUG_INFO, "128M Bits\r\n");
} else if (ReadBuffer[3] == FLASH_SIZE_ID_256M) {
QspiFlashSize = FLASH_SIZE_256M;
fsbl_printf(DEBUG_INFO, "256M Bits\r\n");
} else if (ReadBuffer[3] == FLASH_SIZE_ID_512M) {
QspiFlashSize = FLASH_SIZE_512M;
fsbl_printf(DEBUG_INFO, "512M Bits\r\n");
} else if (ReadBuffer[3] == FLASH_SIZE_ID_1G) {
QspiFlashSize = FLASH_SIZE_1G;
fsbl_printf(DEBUG_INFO, "1G Bits\r\n");
}
return XST_SUCCESS;
}
/******************************************************************************
*
* This function reads from the serial FLASH connected to the
* QSPI interface.
*
* @param Address contains the address to read data from in the FLASH.
* @param ByteCount contains the number of bytes to read.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void FlashRead(u32 Address, u32 ByteCount)
{
/*
* Setup the write command with the specified address and data for the
* FLASH
*/
WriteBuffer[COMMAND_OFFSET] = QUAD_READ_CMD;
WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);
WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);
ByteCount += DUMMY_SIZE;
/*
* Send the read command to the FLASH to read the specified number
* of bytes from the FLASH, send the read command and address and
* receive the specified number of bytes of data in the data buffer
*/
XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer,
ByteCount + OVERHEAD_SIZE);
}
/******************************************************************************/
/**
*
* This function provides the QSPI FLASH interface for the Simplified header
* functionality.
*
* @param SourceAddress is address in FLASH data space
* @param DestinationAddress is address in DDR data space
* @param LengthBytes is the length of the data in Bytes
*
* @return
* - XST_SUCCESS if the write completes correctly
* - XST_FAILURE if the write fails to completes correctly
*
* @note none.
*
****************************************************************************/
u32 QspiAccess( u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes)
{
#ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR
u32 Data;
u32 Count;
u32 *SourceAddr;
u32 *DestAddr;
/* Check for non-word tail, add bytes to cover the end */
if ((LengthBytes%4) != 0){
LengthBytes += (4 - (LengthBytes & 0x00000003));
}
SourceAddr = (u32 *)(SourceAddress + FlashReadBaseAddress);
DestAddr = (u32 *)(DestinationAddress);
/* Word transfers, endianism isn't an issue */
for (Count=0; Count < (LengthBytes / 4); Count++){
Data = Xil_In32((u32)(SourceAddr));
SourceAddr++;
Xil_Out32((u32)(DestAddr), Data);
DestAddr++;
}
#endif
return XST_SUCCESS;
}
/******************************************************************************
*
* This functions selects the current bank
*
* @param BankSel is the bank to be selected in the flash device(s).
*
* @return XST_SUCCESS if bank selected
* XST_FAILURE if selection failed
* @note None.
*
******************************************************************************/
u32 SendBankSelect(u8 BankSel)
{
u32 Status;
/*
* bank select commands for Micron and Spansion are different
*/
if (QspiFlashMake == MICRON_ID) {
/*
* For micron command WREN should be sent first
* except for some specific feature set
*/
WriteBuffer[COMMAND_OFFSET] = WRITE_ENABLE_CMD;
Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL,
WRITE_ENABLE_CMD_SIZE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_WR;
WriteBuffer[ADDRESS_1_OFFSET] = BankSel;
Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL,
BANK_SEL_SIZE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
if (QspiFlashMake == SPANSION_ID) {
WriteBuffer[COMMAND_OFFSET] = BANK_REG_WR;
WriteBuffer[ADDRESS_1_OFFSET] = BankSel;
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL,
BANK_SEL_SIZE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
/*
* For testing - Read bank to verify
*/
if (QspiFlashMake == SPANSION_ID) {
WriteBuffer[COMMAND_OFFSET] = BANK_REG_RD;
WriteBuffer[ADDRESS_1_OFFSET] = 0x00;
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer,
BANK_SEL_SIZE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
if (QspiFlashMake == MICRON_ID) {
WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_RD;
WriteBuffer[ADDRESS_1_OFFSET] = 0x00;
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer,
BANK_SEL_SIZE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
if (ReadBuffer[1] != BankSel) {
fsbl_printf(DEBUG_INFO, "BankSel %d != Register Read %d\n\r", BankSel,
ReadBuffer[1]);
return XST_FAILURE;
}
return XST_SUCCESS;
}
#endif
Qspi.h修改
Qspi.h中需要增加三个宏定义,如下。
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file qspi.h
*
* This file contains the interface for the QSPI FLASH functionality
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a ecm 01/10/10 Initial release
* 3.00a mb 01/09/12 Added the Delay Values defines for qspi
* 5.00a sgd 05/17/13 Added Flash Size > 128Mbit support
* Dual Stack support
* </pre>
*
* @note
*
******************************************************************************/
#ifndef ___QSPI_H___
#define ___QSPI_H___
#include "fsbl.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************** Include Files *********************************/
#include "fsbl.h"
/************************** Constant Definitions *****************************/
#define SINGLE_FLASH_CONNECTION 0
#define DUAL_STACK_CONNECTION 1
#define DUAL_PARALLEL_CONNECTION 2
#define FLASH_SIZE_16MB 0x1000000
/*
* Bank mask
*/
#define BANKMASK 0xF000000
/*
* Identification of Flash
* Micron:
* Byte 0 is Manufacturer ID;
* Byte 1 is first byte of Device ID - 0xBB or 0xBA
* Byte 2 is second byte of Device ID describes flash size:
* 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20
* Spansion:
* Byte 0 is Manufacturer ID;
* Byte 1 is Device ID - Memory Interface type - 0x20 or 0x02
* Byte 2 is second byte of Device ID describes flash size:
* 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20
*/
#define MICRON_ID 0x20
#define SPANSION_ID 0x01
#define WINBOND_ID 0xEF
#define FLASH_SIZE_ID_128M 0x18
#define FLASH_SIZE_ID_256M 0x19
#define FLASH_SIZE_ID_512M 0x20
#define FLASH_SIZE_ID_1G 0x21
/*
* Size in bytes
*/
#define FLASH_SIZE_128M 0x1000000
#define FLASH_SIZE_256M 0x2000000
#define FLASH_SIZE_512M 0x4000000
#define FLASH_SIZE_1G 0x8000000
#define FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY1 0
#define FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY2 0
#define FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY_VALUE (FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY1 | \
FSBL_XQSPIPS_LPBK_DLY_ADJ_DLY2)
/************************** Function Prototypes ******************************/
u32 InitQspi(void);
u32 QspiAccess( u32 SourceAddress,
u32 DestinationAddress,
u32 LengthBytes);
u32 FlashReadID(void);
u32 SendBankSelect(u8 BankSel);
/************************** Variable Definitions *****************************/
#ifdef __cplusplus
}
#endif
#endif /* ___QSPI_H___ */
Pcap.c修改
修改了FabricInit函数,具体参考代码
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file pcap.c
*
* Contains code for enabling and accessing the PCAP
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a ecm 02/10/10 Initial release
* 2.00a jz 05/28/11 Add SD support
* 2.00a mb 25/05/12 using the EDK provided devcfg driver
* Nand/SD encryption and review comments
* 3.00a mb 16/08/12 Added the poll function
* Removed the FPGA_RST_CTRL define
* Added the flag for NON PS instantiated bitstream
* 4.00a sgd 02/28/13 Fix for CR#681014 - ECC init in FSBL should not call
* fabric_init()
* Fix for CR#689026 - FSBL doesn't hold PL resets active
* during bit download
* Fix for CR#699475 - FSBL functionality is broken and
* its not able to boot in QSPI/NAND
* bootmode
* Fix for CR#705664 - FSBL fails to decrypt the
* bitstream when the image is AES
* encrypted using non-zero key value
* 6.00a kc 08/30/13 Fix for CR#722979 - Provide customer-friendly
* changelogs in FSBL
* 7.00a kc 10/25/13 Fix for CR#724620 - How to handle PCAP_MODE after
* bitstream configuration
* Fix for CR#726178 - FabricInit() PROG_B is kept active
* for 5mS.
* Fix for CR#731839 - FSBL has to check the
* HMAC error status after decryption
* 12/04/13 Fix for CR#764382 - How to handle PCAP_MODE after
* bitstream configuration - PCAP_MODE
* and PCAP_PR bits are not modified
* 8.00a kc 2/20/14 Fix for CR#775631 - FSBL: FsblGetGlobalTimer()
* is not proper
* 10.00a kc 07/24/14 Fix for CR#809336 - Minor code cleanup
* 13.00a ssc 04/10/15 Fix for CR#846899 - Corrected logic to clear
* DMA done count
* </pre>
*
* @note
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "pcap.h"
#include "nand.h" /* For NAND geometry information */
#include "fsbl.h"
#include "image_mover.h" /* For MoveImage */
#include "xparameters.h"
#include "xil_exception.h"
#include "xdevcfg.h"
#include "sleep.h"
#ifdef XPAR_XWDTPS_0_BASEADDR
#include "xwdtps.h"
#endif
/************************** Constant Definitions *****************************/
/*
* The following constants map to the XPAR parameters created in the
* xparameters.h file. They are only defined here such that a user can easily
* change all the needed parameters in one place.
*/
#define DCFG_DEVICE_ID XPAR_XDCFG_0_DEVICE_ID
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
extern int XDcfgPollDone(u32 MaskValue, u32 MaxCount);
/************************** Variable Definitions *****************************/
/* Devcfg driver instance */
static XDcfg DcfgInstance;
XDcfg *DcfgInstPtr;
#ifdef XPAR_XWDTPS_0_BASEADDR
extern XWdtPs Watchdog; /* Instance of WatchDog Timer */
#endif
/******************************************************************************/
/**
*
* This function transfer data using PCAP
*
* @param SourceDataPtr is a pointer to where the data is read from
* @param DestinationDataPtr is a pointer to where the data is written to
* @param SourceLength is the length of the data to be moved in words
* @param DestinationLength is the length of the data to be moved in words
* @param SecureTransfer indicated the encryption key location, 0 for
* non-encrypted
*
* @return
* - XST_SUCCESS if the transfer is successful
* - XST_FAILURE if the transfer fails
*
* @note None
*
****************************************************************************/
u32 PcapDataTransfer(u32 *SourceDataPtr, u32 *DestinationDataPtr,
u32 SourceLength, u32 DestinationLength, u32 SecureTransfer)
{
u32 Status;
u32 IntrStsReg;
u32 PcapTransferType = XDCFG_CONCURRENT_NONSEC_READ_WRITE;
/*
* Check for secure transfer
*/
if (SecureTransfer) {
PcapTransferType = XDCFG_CONCURRENT_SECURE_READ_WRITE;
}
#ifdef FSBL_PERF
XTime tXferCur = 0;
FsblGetGlobalTime(&tXferCur);
#endif
/*
* Clear the PCAP status registers
*/
Status = ClearPcapStatus();
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"PCAP_CLEAR_STATUS_FAIL \r\n");
return XST_FAILURE;
}
#ifdef XPAR_XWDTPS_0_BASEADDR
/*
* Prevent WDT reset
*/
XWdtPs_RestartWdt(&Watchdog);
#endif
/*
* PCAP single DMA transfer setup
*/
SourceDataPtr = (u32*)((u32)SourceDataPtr | PCAP_LAST_TRANSFER);
DestinationDataPtr = (u32*)((u32)DestinationDataPtr | PCAP_LAST_TRANSFER);
/*
* Transfer using Device Configuration
*/
Status = XDcfg_Transfer(DcfgInstPtr, (u8 *)SourceDataPtr,
SourceLength,
(u8 *)DestinationDataPtr,
DestinationLength, PcapTransferType);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"Status of XDcfg_Transfer = %lu \r \n",Status);
return XST_FAILURE;
}
/*
* Dump the PCAP registers
*/
PcapDumpRegisters();
/*
* Poll for the DMA done
*/
Status = XDcfgPollDone(XDCFG_IXR_DMA_DONE_MASK, MAX_COUNT);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"PCAP_DMA_DONE_FAIL \r\n");
return XST_FAILURE;
}
fsbl_printf(DEBUG_INFO,"DMA Done ! \n\r");
/*
* Check for errors
*/
IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) {
fsbl_printf(DEBUG_INFO,"Errors in PCAP \r\n");
return XST_FAILURE;
}
/*
* For Performance measurement
*/
#ifdef FSBL_PERF
XTime tXferEnd = 0;
fsbl_printf(DEBUG_GENERAL,"Time taken is ");
FsblMeasurePerfTime(tXferCur,tXferEnd);
#endif
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function loads PL partition using PCAP
*
* @param SourceDataPtr is a pointer to where the data is read from
* @param DestinationDataPtr is a pointer to where the data is written to
* @param SourceLength is the length of the data to be moved in words
* @param DestinationLength is the length of the data to be moved in words
* @param SecureTransfer indicated the encryption key location, 0 for
* non-encrypted
*
* @return
* - XST_SUCCESS if the transfer is successful
* - XST_FAILURE if the transfer fails
*
* @note None
*
****************************************************************************/
u32 PcapLoadPartition(u32 *SourceDataPtr, u32 *DestinationDataPtr,
u32 SourceLength, u32 DestinationLength, u32 SecureTransfer)
{
u32 Status;
u32 IntrStsReg;
u32 PcapTransferType = XDCFG_NON_SECURE_PCAP_WRITE;
/*
* Check for secure transfer
*/
if (SecureTransfer) {
PcapTransferType = XDCFG_SECURE_PCAP_WRITE;
}
#ifdef FSBL_PERF
XTime tXferCur = 0;
FsblGetGlobalTime(&tXferCur);
#endif
/*
* Clear the PCAP status registers
*/
Status = ClearPcapStatus();
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"PCAP_CLEAR_STATUS_FAIL \r\n");
return XST_FAILURE;
}
/*
* For Bitstream case destination address will be 0xFFFFFFFF
*/
DestinationDataPtr = (u32*)XDCFG_DMA_INVALID_ADDRESS;
/*
* New Bitstream download initialization sequence
*/
FabricInit();
#ifdef XPAR_XWDTPS_0_BASEADDR
/*
* Prevent WDT reset
*/
XWdtPs_RestartWdt(&Watchdog);
#endif
/*
* PCAP single DMA transfer setup
*/
SourceDataPtr = (u32*)((u32)SourceDataPtr | PCAP_LAST_TRANSFER);
DestinationDataPtr = (u32*)((u32)DestinationDataPtr | PCAP_LAST_TRANSFER);
/*
* Transfer using Device Configuration
*/
Status = XDcfg_Transfer(DcfgInstPtr, (u8 *)SourceDataPtr,
SourceLength,
(u8 *)DestinationDataPtr,
DestinationLength, PcapTransferType);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"Status of XDcfg_Transfer = %lu \r \n",Status);
return XST_FAILURE;
}
/*
* Dump the PCAP registers
*/
PcapDumpRegisters();
/*
* Poll for the DMA done
*/
Status = XDcfgPollDone(XDCFG_IXR_DMA_DONE_MASK, MAX_COUNT);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"PCAP_DMA_DONE_FAIL \r\n");
return XST_FAILURE;
}
fsbl_printf(DEBUG_INFO,"DMA Done ! \n\r");
/*
* Poll for FPGA Done
*/
Status = XDcfgPollDone(XDCFG_IXR_PCFG_DONE_MASK, MAX_COUNT);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO,"PCAP_FPGA_DONE_FAIL\r\n");
return XST_FAILURE;
}
fsbl_printf(DEBUG_INFO,"FPGA Done ! \n\r");
#ifndef DDRLESS_SYSTEM
/*
* Check for errors
*/
IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) {
fsbl_printf(DEBUG_INFO,"Errors in PCAP \r\n");
return XST_FAILURE;
}
#endif
/*
* For Performance measurement
*/
#ifdef FSBL_PERF
XTime tXferEnd = 0;
fsbl_printf(DEBUG_GENERAL,"Time taken is ");
FsblMeasurePerfTime(tXferCur,tXferEnd);
#endif
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function Initializes the PCAP driver.
*
* @param none
*
* @return
* - XST_SUCCESS if the pcap driver initialization is successful
* - XST_FAILURE if the pcap driver initialization fails
*
* @note none
*
****************************************************************************/
int InitPcap(void)
{
XDcfg_Config *ConfigPtr;
int Status = XST_SUCCESS;
DcfgInstPtr = &DcfgInstance;
/*
* Initialize the Device Configuration Interface driver.
*/
ConfigPtr = XDcfg_LookupConfig(DCFG_DEVICE_ID);
Status = XDcfg_CfgInitialize(DcfgInstPtr, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO, "XDcfg_CfgInitialize failed \n\r");
return XST_FAILURE;
}
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function programs the Fabric for use.
*
* @param None
*
* @return None
* - XST_SUCCESS if the Fabric initialization is successful
* - XST_FAILURE if the Fabric initialization fails
* @note None
*
****************************************************************************/
void FabricInit(void)
{
u32 PcapReg;
u32 PcapCtrlRegVal;
u32 StatusReg;
/*
* Set Level Shifters DT618760 - PS to PL enabling
*/
Xil_Out32(PS_LVL_SHFTR_EN, LVL_PS_PL);
fsbl_printf(DEBUG_INFO,"Level Shifter Value = 0x%lx \r\n",
Xil_In32(PS_LVL_SHFTR_EN));
/*
* Get DEVCFG controller settings
*/
PcapReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,
XDCFG_CTRL_OFFSET);
/*
* Setting PCFG_PROG_B signal to high
*/
XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET,
(PcapReg | XDCFG_CTRL_PCFG_PROG_B_MASK));
/*
* Check for AES source key
*/
PcapCtrlRegVal = XDcfg_GetControlRegister(DcfgInstPtr);
if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) {
/*
* 5msec delay
*/
usleep(5000);
}
/*
* Setting PCFG_PROG_B signal to low
*/
XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET,
(PcapReg & ~XDCFG_CTRL_PCFG_PROG_B_MASK));
/*
* Check for AES source key
*/
if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) {
/*
* 5msec delay
*/
usleep(5000);
}
/*
* Polling the PCAP_INIT status for Reset
*/
while(XDcfg_GetStatusRegister(DcfgInstPtr) &
XDCFG_STATUS_PCFG_INIT_MASK);
/*
* Setting PCFG_PROG_B signal to high
*/
XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET,
(PcapReg | XDCFG_CTRL_PCFG_PROG_B_MASK));
/*
* Polling the PCAP_INIT status for Set
*/
while(!(XDcfg_GetStatusRegister(DcfgInstPtr) &
XDCFG_STATUS_PCFG_INIT_MASK));
/*
* Get Device configuration status
*/
StatusReg = XDcfg_GetStatusRegister(DcfgInstPtr);
fsbl_printf(DEBUG_INFO,"Devcfg Status register = 0x%lx \r\n",StatusReg);
fsbl_printf(DEBUG_INFO,"PCAP:Fabric is Initialized done\r\n");
}
/******************************************************************************/
/**
*
* This function Clears the PCAP status registers.
*
* @param None
*
* @return
* - XST_SUCCESS if the pcap status registers are cleared
* - XST_FAILURE if errors are there
* - XST_DEVICE_BUSY if Pcap device is busy
* @note None
*
****************************************************************************/
u32 ClearPcapStatus(void)
{
u32 StatusReg;
u32 IntStatusReg;
/*
* Clear it all, so if Boot ROM comes back, it can proceed
*/
XDcfg_IntrClear(DcfgInstPtr, 0xFFFFFFFF);
/*
* Get PCAP Interrupt Status Register
*/
IntStatusReg = XDcfg_IntrGetStatus(DcfgInstPtr);
if (IntStatusReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) {
fsbl_printf(DEBUG_INFO,"FATAL errors in PCAP %lx\r\n",
IntStatusReg);
return XST_FAILURE;
}
/*
* Read the PCAP status register for DMA status
*/
StatusReg = XDcfg_GetStatusRegister(DcfgInstPtr);
fsbl_printf(DEBUG_INFO,"PCAP:StatusReg = 0x%.8lx\r\n", StatusReg);
/*
* If the queue is full, return w/ XST_DEVICE_BUSY
*/
if ((StatusReg & XDCFG_STATUS_DMA_CMD_Q_F_MASK) ==
XDCFG_STATUS_DMA_CMD_Q_F_MASK) {
fsbl_printf(DEBUG_INFO,"PCAP_DEVICE_BUSY\r\n");
return XST_DEVICE_BUSY;
}
fsbl_printf(DEBUG_INFO,"PCAP:device ready\r\n");
/*
* There are unacknowledged DMA commands outstanding
*/
if ((StatusReg & XDCFG_STATUS_DMA_CMD_Q_E_MASK) !=
XDCFG_STATUS_DMA_CMD_Q_E_MASK) {
IntStatusReg = XDcfg_IntrGetStatus(DcfgInstPtr);
if ((IntStatusReg & XDCFG_IXR_DMA_DONE_MASK) !=
XDCFG_IXR_DMA_DONE_MASK){
/*
* Error state, transfer cannot occur
*/
fsbl_printf(DEBUG_INFO,"PCAP:IntStatus indicates error\r\n");
return XST_FAILURE;
}
else {
/*
* clear out the status
*/
XDcfg_IntrClear(DcfgInstPtr, XDCFG_IXR_DMA_DONE_MASK);
}
}
if ((StatusReg & XDCFG_STATUS_DMA_DONE_CNT_MASK) != 0) {
XDcfg_SetStatusRegister(DcfgInstPtr, StatusReg |
XDCFG_STATUS_DMA_DONE_CNT_MASK);
}
fsbl_printf(DEBUG_INFO,"PCAP:Clear done\r\n");
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function prints PCAP register status.
*
* @param none
*
* @return none
*
* @note none
*
****************************************************************************/
void PcapDumpRegisters (void) {
fsbl_printf(DEBUG_INFO,"PCAP register dump:\r\n");
fsbl_printf(DEBUG_INFO,"PCAP CTRL 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_CTRL_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_CTRL_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP LOCK 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_LOCK_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_LOCK_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP CONFIG 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_CFG_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_CFG_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP ISR 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_STS_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_STS_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP IMR 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_MASK_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_INT_MASK_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP STATUS 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_STATUS_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_STATUS_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP DMA SRC ADDR 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_ADDR_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_ADDR_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP DMA DEST ADDR 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_ADDR_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_ADDR_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP DMA SRC LEN 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_LEN_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_SRC_LEN_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP DMA DEST LEN 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_LEN_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_DMA_DEST_LEN_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP ROM SHADOW CTRL 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_ROM_SHADOW_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_ROM_SHADOW_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP MBOOT 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_MULTIBOOT_ADDR_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_MULTIBOOT_ADDR_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP SW ID 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_SW_ID_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_SW_ID_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP UNLOCK 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_UNLOCK_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_UNLOCK_OFFSET));
fsbl_printf(DEBUG_INFO,"PCAP MCTRL 0x%x: 0x%08lx\r\n",
XPS_DEV_CFG_APB_BASEADDR + XDCFG_MCTRL_OFFSET,
Xil_In32(XPS_DEV_CFG_APB_BASEADDR + XDCFG_MCTRL_OFFSET));
}
/******************************************************************************/
/**
*
* This function Polls for the DMA done or FPGA done.
*
* @param none
*
* @return
* - XST_SUCCESS if polling for DMA/FPGA done is successful
* - XST_FAILURE if polling for DMA/FPGA done fails
*
* @note none
*
****************************************************************************/
int XDcfgPollDone(u32 MaskValue, u32 MaxCount)
{
int Count = MaxCount;
u32 IntrStsReg = 0;
/*
* poll for the DMA done
*/
IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
while ((IntrStsReg & MaskValue) !=
MaskValue) {
IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
Count -=1;
#ifndef DDRLESS_SYSTEM
if (IntrStsReg & FSBL_XDCFG_IXR_ERROR_FLAGS_MASK) {
fsbl_printf(DEBUG_INFO,"FATAL errors in PCAP %lx\r\n",
IntrStsReg);
PcapDumpRegisters();
return XST_FAILURE;
}
#endif
if(!Count) {
fsbl_printf(DEBUG_GENERAL,"PCAP transfer timed out \r\n");
return XST_FAILURE;
}
if (Count > (MAX_COUNT-100)) {
fsbl_printf(DEBUG_GENERAL,".");
}
}
fsbl_printf(DEBUG_GENERAL,"\n\r");
XDcfg_IntrClear(DcfgInstPtr, IntrStsReg & MaskValue);
return XST_SUCCESS;
}
Pcap.h修改
修改FabricInit()函数返回类型。
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file pcap.h
*
* This file contains the interface for intiializing and accessing the PCAP
*
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a ecm 02/10/10 Initial release
* 2.00a mb 16/08/12 Added the macros and function prototypes
* </pre>
*
* @note
*
******************************************************************************/
#ifndef ___PCAP_H___
#define ___PCAP_H___
#ifdef __cplusplus
extern "C" {
#endif
/***************************** Include Files *********************************/
#include "xdevcfg.h"
/************************** Function Prototypes ******************************/
/* Multiboot register offset mask */
#define PCAP_MBOOT_REG_REBOOT_OFFSET_MASK 0x1FFF
#define PCAP_CTRL_PCFG_AES_FUSE_EFUSE_MASK 0x1000
#define PCAP_LAST_TRANSFER 1
#define MAX_COUNT 1000000000
#define LVL_PL_PS 0x0000000F
#define LVL_PS_PL 0x0000000A
/* Fix for #672779 */
#define FSBL_XDCFG_IXR_ERROR_FLAGS_MASK (XDCFG_IXR_AXI_WERR_MASK | \
XDCFG_IXR_AXI_RTO_MASK | \
XDCFG_IXR_AXI_RERR_MASK | \
XDCFG_IXR_RX_FIFO_OV_MASK | \
XDCFG_IXR_DMA_CMD_ERR_MASK |\
XDCFG_IXR_DMA_Q_OV_MASK | \
XDCFG_IXR_P2D_LEN_ERR_MASK |\
XDCFG_IXR_PCFG_HMAC_ERR_MASK)
int InitPcap(void);
void PcapDumpRegisters(void);
u32 ClearPcapStatus(void);
void FabricInit(void);
int XDcfgPollDone(u32 MaskValue, u32 MaxCount);
u32 PcapLoadPartition(u32 *SourceData, u32 *DestinationData, u32 SourceLength,
u32 DestinationLength, u32 Flags);
u32 PcapDataTransfer(u32 *SourceData, u32 *DestinationData, u32 SourceLength,
u32 DestinationLength, u32 Flags);
/************************** Variable Definitions *****************************/
#ifdef __cplusplus
}
#endif
#endif /* ___PCAP_H___ */
Fsbl_handoff.S修改
由于程序不在DDR中执行,需要修改FsblHandoffExit段
#ifdef __GNUC__
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file handoff.S
*
* Contains the code that does the handoff to the loaded application. This
* code lives high in the ROM.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date.word Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a ecm 03/01/10 Initial release
* 7.00a kc 10/23/13 Added support for armcc compiler
* </pre>
*
* @note
* Assumes that the starting address of the FSBL is provided by the calling routine
* in R0.
*
******************************************************************************/
.globl FsblHandoffJtagExit
.globl FsblHandoffExit
.section .handoff,"axS"
/***************************** Include Files *********************************/
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/************************** Variable Definitions *****************************/
FsblHandoffJtagExit:
mcr 15,0,r0,cr7,cr5,0 /* Invalidate Instruction cache */
mcr 15,0,r0,cr7,cr5,6 /* Invalidate branch predictor array */
dsb
isb /* make sure it completes */
ldr r4, =0
mcr 15,0,r4,cr1,cr0,0 /* disable the ICache and MMU */
isb /* make sure it completes */
Loop:
wfe
b Loop
FsblHandoffExit:
#ifdef DDRLESS_SYSTEM
mov lr, r0 /* move the destination address into link register */
bx lr /* force the switch, destination should have been in r0 */
#else
mov lr, r0 /* move the destination address into link register */
mcr 15,0,r0,cr7,cr5,0 /* Invalidate Instruction cache */
mcr 15,0,r0,cr7,cr5,6 /* Invalidate branch predictor array */
dsb
isb /* make sure it completes */
ldr r4, =0
mcr 15,0,r4,cr1,cr0,0 /* disable the ICache and MMU */
isb /* make sure it completes */
bx lr /* force the switch, destination should have been in r0 */
#endif
.Ldone: b .Ldone /* Paranoia: we should never get here */
.end
#elif defined (__IASMARM__)
PUBLIC FsblHandoffJtagExit
PUBLIC FsblHandoffExit
SECTION .handoff:CODE:NOROOT(2)
/***************************** Include Files *********************************/
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/************************** Variable Definitions *****************************/
FsblHandoffJtagExit
mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */
mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */
dsb
isb ;/* make sure it completes */
ldr r4, =0
mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */
isb ;/* make sure it completes */
Loop
wfe
b Loop
FsblHandoffExit
#ifdef DDRLESS_SYSTEM
mov lr, r0 /* move the destination address into link register */
bx lr /* force the switch, destination should have been in r0 */
#else
mov lr, r0 ;/* move the destination address into link register */
mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */
mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */
dsb
isb ;/* make sure it completes */
ldr r4, =0
mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */
isb ;/* make sure it completes */
bx lr ;/* force the switch, destination should have been in r0 */
#endif
.Ldone
b .Ldone ;/* Paranoia: we should never get here */
END
#else
EXPORT FsblHandoffJtagExit
EXPORT FsblHandoffExit
AREA |.handoff|,CODE
;/***************************** Include Files *********************************/
;/************************** Constant Definitions *****************************/
;/**************************** Type Definitions *******************************/
;/***************** Macros (Inline Functions) Definitions *********************/
;/************************** Function Prototypes ******************************/
;/************************** Variable Definitions *****************************/
FsblHandoffJtagExit
mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */
mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */
dsb
isb ;/* make sure it completes */
ldr r4, =0
mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */
isb ;/* make sure it completes */
Loop
wfe
b Loop
FsblHandoffExit
#ifdef DDRLESS_SYSTEM
mov lr, r0 /* move the destination address into link register */
bx lr /* force the switch, destination should have been in r0 */
#else
mov lr, r0 ;/* move the destination address into link register */
mcr p15,0,r0,c7,c5,0 ;/* Invalidate Instruction cache */
mcr p15,0,r0,c7,c5,6 ;/* Invalidate branch predictor array */
dsb
isb ;/* make sure it completes */
ldr r4, =0
mcr p15,0,r4,c1,c0,0 ;/* disable the ICache and MMU */
isb ;/* make sure it completes */
bx lr ;/* force the switch, destination should have been in r0 */
#endif
Ldone b Ldone ;/* Paranoia: we should never get here */
END
#endif
Fsbl_hooks.c修改
修改部分如下:
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************
*
* @file fsbl_hooks.c
*
* This file provides functions that serve as user hooks. The user can add the
* additional functionality required into these routines. This would help retain
* the normal FSBL flow unchanged.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 3.00a np 08/03/12 Initial release
* </pre>
*
* @note
*
******************************************************************************/
#include "fsbl.h"
#include "xstatus.h"
#include "fsbl_hooks.h"
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
/******************************************************************************
* This function is the hook which will be called before the bitstream download.
* The user can add all the customized code required to be executed before the
* bitstream download to this routine.
*
* @param None
*
* @return
* - XST_SUCCESS to indicate success
* - XST_FAILURE.to indicate failure
*
****************************************************************************/
u32 FsblHookBeforeBitstreamDload(void) {
u32 Status;
Status = XST_SUCCESS;
/*
* User logic to be added here. Errors to be stored in the status variable
* and returned
*/
fsbl_printf(DEBUG_INFO, "In FsblHookBeforeBitstreamDload function \r\n");
return (Status);
}
/******************************************************************************
* This function is the hook which will be called after the bitstream download.
* The user can add all the customized code required to be executed after the
* bitstream download to this routine.
*
* @param None
*
* @return
* - XST_SUCCESS to indicate success
* - XST_FAILURE.to indicate failure
*
****************************************************************************/
u32 FsblHookAfterBitstreamDload(void) {
u32 Status;
Status = XST_SUCCESS;
/*
* User logic to be added here.
* Errors to be stored in the status variable and returned
*/
fsbl_printf(DEBUG_INFO, "In FsblHookAfterBitstreamDload function \r\n");
return (Status);
}
/******************************************************************************
* This function is the hook which will be called before the FSBL does a handoff
* to the application. The user can add all the customized code required to be
* executed before the handoff to this routine.
*
* @param None
*
* @return
* - XST_SUCCESS to indicate success
* - XST_FAILURE.to indicate failure
*
****************************************************************************/
u32 FsblHookBeforeHandoff(u32 FsblStartAddr) {
u32 Status;
u32* ptr;
u32 i;
ptr = (u32*) FsblStartAddr;
Status = XST_SUCCESS;
/*
* User logic to be added here.
* Errors to be stored in the status variable and returned
*/
fsbl_printf(DEBUG_INFO, "In FsblHookBeforeHandoff function \r\n");
for (i = 0; i < 8; i++) {
fsbl_printf(DEBUG_INFO, "*(0x%x) = 0x%x\r\n", ptr, *(ptr));
ptr++;
}
fsbl_printf(DEBUG_INFO,
"Returning from FsblHookBeforeHandoff function \r\n");
return (Status);
}
/******************************************************************************
* This function is the hook which will be called in case FSBL fall back
*
* @param None
*
* @return None
*
****************************************************************************/
void FsblHookFallback(void) {
/*
* User logic to be added here.
* Errors to be stored in the status variable and returned
*/
fsbl_printf(DEBUG_INFO, "In FsblHookFallback function \r\n");
while (1)
;
}
Fsbl_hook.h修改
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file fsbl_hooks.h
*
* Contains the function prototypes, defines and macros required by fsbl_hooks.c
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 3.00a np/mb 10/08/12 Initial release
* Corrected the prototype
*
* </pre>
*
* @note
*
******************************************************************************/
#ifndef FSBL_HOOKS_H_
#define FSBL_HOOKS_H_
#ifdef __cplusplus
extern "C" {
#endif
/***************************** Include Files *********************************/
#include "fsbl.h"
/************************** Function Prototypes ******************************/
/* FSBL hook function which is called before bitstream download */
u32 FsblHookBeforeBitstreamDload(void);
/* FSBL hook function which is called after bitstream download */
u32 FsblHookAfterBitstreamDload(void);
/* FSBL hook function which is called before handoff to the application */
u32 FsblHookBeforeHandoff(u32 FsblStartAddr);
/* FSBL hook function which is called in FSBL fallback */
void FsblHookFallback(void);
#ifdef __cplusplus
}
#endif
#endif /* end of protection macro */
Lscript.ld修改
该文件为生成.elf过程中的链接文件,主要修改MEMORY地址,如下。
Fsb中使用的空间包括OCM 0-191KB 及后面256字节,FLASH 8KB-3MB。
各section的配置参看具体代码。
/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x6000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000;
_RSA_AC_SIZE = DEFINED(_RSA_AC_SIZE) ? _RSA_AC_SIZE : 0x1000;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
/* Define Memories in the system */
MEMORY
{
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x0002FF00
ps7_ram_0_S_AXI_BASEADDR_1 : ORIGIN = 0x0002FF00, LENGTH = 0x0000100
FLASH : ORIGIN = 0xFC000000 + 0x2000, LENGTH = 0x2FE000
}
/* Specify the default entry point to the program */
ENTRY(_vector_table)
PHDRS { text PT_LOAD; }
SECTIONS
{
.text : {
*(.vectors)
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > FLASH : text
.init : {
KEEP (*(.init))
} > FLASH
.fini : {
KEEP (*(.fini))
} > FLASH
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > FLASH
.data : {
_dataVMA_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
_dataVMA_end = .;
} > ps7_ram_0_S_AXI_BASEADDR AT> FLASH
_dataLMA = LOADADDR(.data);
.eh_frame : {
*(.eh_frame)
} > FLASH
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > ps7_ram_0_S_AXI_BASEADDR
.bss (NOLOAD) : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
__bss_end = .;
} > ps7_ram_0_S_AXI_BASEADDR
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > FLASH
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > FLASH
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > FLASH
.mmu_tbl ALIGN(0x4000): {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > FLASH
/*
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
*/
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > ps7_ram_0_S_AXI_BASEADDR
.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _STACK_SIZE;
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > ps7_ram_0_S_AXI_BASEADDR
.XVtable(NOLOAD) : {
_dataXVtableVMA_start = .;
*(XVtable)
_dataXVtableVMA_end = .;
} > ps7_ram_0_S_AXI_BASEADDR_1 AT> FLASH
_dataXVtableLMA = LOADADDR(.XVtable);
_end = .;
}
当前ZYNQ中地址分配如下:
OCM地址从0x0-0x0003ffff,QSPI地址从0xfc000000-0xfdffffff。Fsbl中会用到这两段地址,上面的memory中ps7_ram_0_S_AXI_BASEADDR和ps7_ram_0_S_AXI_BASEADDR_1使用了OCM空间,FLASH使用了QSPI FLASH空间。
通过查看fsbl.elf文件,可以查看目前sections的分配,对于其中具有READONLY属性的section,可以放在QSPI FLASH中运行,即XIP模式。
以下是一个FSBL.elf示例
上图中.text,.handoff等都是READONLY属性,所以在ldscript.ld中将他们放在FLASH中。
对于不是READONLY属性的section,如下
需要直接在OCM中为其分配地址
对.data段进行特殊处理,需要load,即从QSPI FLASH中搬到ocm中,如下:
添加宏定义
代码修改完后,在fsbl工程中添加两个宏定义。
编译,会发现.data未分配,这个错误不用管,能顺利得到fsbl.elf文件
3、APP修改
应用程序需要修改的地方如下
Main.c修改
在main函数中需要增加将.data拷贝到OCM中的操作
/******************************************************************************
*
* (c) Copyright 2011-2012 Xilinx, Inc. All rights reserved.
*
* This file contains confidential and proprietary information of Xilinx, Inc.
* and is protected under U.S. and international copyright and other
* intellectual property laws.
*
* DISCLAIMER
* This disclaimer is not a license and does not grant any rights to the
* materials distributed herewith. Except as otherwise provided in a valid
* license issued to you by Xilinx, and to the maximum extent permitted by
* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
* and (2) Xilinx shall not be liable (whether in contract or tort, including
* negligence, or under any other theory of liability) for any loss or damage
* of any kind or nature related to, arising under or in connection with these
* materials, including for any direct, or any indirect, special, incidental,
* or consequential loss or damage (including loss of data, profits, goodwill,
* or any type of loss or damage suffered as a result of any action brought by
* a third party) even if such damage or loss was reasonably foreseeable or
* Xilinx had been advised of the possibility of the same.
*
* CRITICAL APPLICATIONS
* Xilinx products are not designed or intended to be fail-safe, or for use in
* any application requiring fail-safe performance, such as life-support or
* safety devices or systems, Class III medical devices, nuclear facilities,
* applications related to the deployment of airbags, or any other applications
* that could lead to death, personal injury, or severe property or
* environmental damage (individually and collectively, "Critical
* Applications"). Customer assumes the sole risk and liability of any use of
* Xilinx products in Critical Applications, subject only to applicable laws
* and regulations governing limitations on product liability.
*
* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
* AT ALL TIMES.
*
*******************************************************************************/
/*****************************************************************************/
/**
*
* @file Application.c
*
* The Appliation file is small application.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
******************************************************************************/
/***************************** Include Files *********************************/
#include <stdio.h>
//#include "platform.h"
#include "xil_print.h"
#define XPS_L2CC_BASEADDR 0xF8F02000
#define XPS_L2CC_EVNT_CNTRL_OFFSET 0x0200
#define XPS_L2CC_EVNT_CNT1_CTRL_OFFSET 0x0204
#define XPS_L2CC_EVNT_CNT0_CTRL_OFFSET 0x0208
#define XPS_L2CC_EVNT_CNT1_VAL_OFFSET 0x020C
#define XPS_L2CC_EVNT_CNT0_VAL_OFFSET 0x0210
#define QSPI_BaseAddress 0xE000D000
extern char _image_start, _dataLMA, _dataVMA_start, _dataVMA_end, _vectorscopy, __vectors_start, __vectors_end;
extern char _dataXVtableLMA, _dataXVtableVMA_start,_dataXVtableVMA_end;
static void copy(char *src, char *dstStart, char *dstEnd) {
/* ROM has data at end of text; copy it. */
while (dstStart < dstEnd)
{
*dstStart++ = *src++;
asm volatile ("dsb sy");
}
}
void Xil_Write32(unsigned int OutAddress, unsigned int Value)
{
*(volatile unsigned int *) OutAddress = Value;
}
unsigned int Xil_Read32(unsigned int Addr)
{
return *(volatile unsigned int *) Addr;
}
int main()
{
//copy the data section from FLASH(load region) to OCM(Execution region) memory region.
copy(&_dataLMA,&_dataVMA_start,&_dataVMA_end);
//Copy the Interrupt vector table from FLASH(load region) to OCM(Execution region) memory region.
copy(&_dataXVtableLMA,&_dataXVtableVMA_start,&_dataXVtableVMA_end);
xil_printf("Application Starts hello world\n\r");
return 0;
}
standalone修改
将实例工程里面的src目录下standalone目录拷贝到应用工程中,注意将其中两个xparameters.h替换为实际工程的
Ldscript.ld修改
同fsbl一样,APP中也需要指定地址空间
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000;
MEMORY
{
FLASH : ORIGIN = 0xFC700000, LENGTH = 0x100000
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00010000, LENGTH = 0x0001FF00
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0x0002ff00, LENGTH = 0x00000100
}
ENTRY(_startcode)
SECTIONS
{
/DISCARD/ :
{
*(.ARM.exidx)
}
.ro : ALIGN(0x40){
*(.text)
*(.rodata)
} > FLASH
.rw : ALIGN(0x40){
_dataVMA_start = .;
*(.data)
*(.bss)
*(COMMON)
_dataVMA_end = .;
}> ps7_ram_0_S_AXI_BASEADDR AT> FLASH
_dataLMA = LOADADDR(.rw);
.heap (NOLOAD): {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > ps7_ram_0_S_AXI_BASEADDR
.stack (NOLOAD) : {. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
_stack = .;
__stack = _stack;
}> ps7_ram_0_S_AXI_BASEADDR
.XVtable : {
_dataXVtableVMA_start = .;
*(XVtable)
_dataXVtableVMA_end = .;
} > ps7_ram_1_S_AXI_BASEADDR AT> FLASH
_dataXVtableLMA = LOADADDR(.XVtable);
}
APP使用FLASH区域为7MB-8MB,使用OCM区域为64KB-191KB以及后续256字节,从下图中能看到bootrom执行后系统内存空间变化情况。
当bootrom执行后OCM MEMORY为0-192KB,fsbl和app都只能使用这段区域。
通过查看app.elf文件,也能看到READONLY属性的段,这些段也放在QSPI FLASH中即可,另一些段从QSPI FLASH中拷贝到OCM中执行。
4、生成boot.bin
生成boot.bin需要使用bif文件,需要注意设置xip模式
//arch = zynq; split = false; format = BIN
the_ROM_image:
{
[bootloader, xip_mode,offset = 0x2000]F:\Reference_Design_Files\test\FSBL_XIP.elf
[offset = 0x200000]F:\Reference_Design_Files\test\system_top_wrapper.bit
[offset = 0x700000]F:\Reference_Design_Files\test\Application.elf
}
如上图所示,fsbl_xip.elf从QSPI FLASH的0x2000地址开始存储,与fsbl中lscript.ld内存空间FLASH地址一致。Bit文件从2MB位置开始存储,应用程序从7MB位置开始存储,这又与app中lscript.ld内存空间FLASH地址一致。
生成boot.bin时不能通过SDK图形化方式产生,必须要使用命令行方式
最后将boot.bin烧入QSPI FLASH即可。