zynq_lvgl/sw/swss/zynq_fsbl/image_mover.c
2024-10-20 23:34:36 +08:00

1373 lines
36 KiB
C
Raw Blame History

/******************************************************************************
* Copyright (c) 2011 - 2022 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @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<73>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
* 11.00a ka 10/12/18 Fix for CR#1006294 Zynq FSBL - Zynq FSBL does not check
* USE_AES_ONLY eFuse
* 12.0 vns 03/18/22 Fixed CR#1125470 to authenticate the parition header buffer
* which is being used instead of one from DDR.
* Deleted GetImageHeaderAndSignature() and added
* GetNAuthImageHeader()
*
* </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"
#ifdef XPAR_XWDTPS_0_BASEADDR
#include "xwdtps.h"
#endif
#ifdef RSA_SUPPORT
#include "rsa.h"
#include "xil_cache.h"
#include "xilrsa.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
u8 Hash[SHA_VALBYTES];
u8 *Ac;
#endif
#ifndef FORCE_USE_AES_EXCLUDE
u32 EncOnly;
#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 image header table, image headers and partition header
* with signature
*/
Status = GetNAuthImageHeader(ImageStartAddress);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,
"Header signature verification Failed\r\n");
OutputStatus(GET_HEADER_INFO_FAIL);
FsblFallback();
}
fsbl_printf(DEBUG_GENERAL,
"Header authentication is Success\r\n");
#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;
/*
* 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;
}
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;
}
#ifndef FORCE_USE_AES_EXCLUDE
EncOnly = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,
XDCFG_STATUS_OFFSET) &
XDCFG_STATUS_EFUSE_SEC_EN_MASK;
if ((EncOnly != 0) &&
(EncryptedPartitionFlag == 0)) {
fsbl_printf(DEBUG_GENERAL,"EFUSE_SEC_EN bit is set,"
" Encryption is mandatory\r\n");
OutputStatus(PARTITION_LOAD_FAIL);
FsblFallback();
}
#endif
/*
* 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
*/
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();
}
/*
* 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
*/
Status = PartitionMove(ImageStartAddress, HeaderPtr);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE_FAIL\r\n");
OutputStatus(PARTITION_MOVE_FAIL);
FsblFallback();
}
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();
sha_256((u8 *)PartitionStartAddr,
((PartitionTotalSize << WORD_LENGTH_SHIFT) -
RSA_PARTITION_SIGNATURE_SIZE),
Hash);
FsblPrintArray(Hash, 32,
"Partition Hash Calculated");
Ac = (u8 *)(PartitionStartAddr +
(PartitionTotalSize << WORD_LENGTH_SHIFT) -
RSA_SIGNATURE_SIZE);
Status = AuthenticatePartition((u8*)Ac, Hash);
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 and authenticates.
* the image header Image header consists of image header table, image headers,
* partition headers
*
* @param ImageBaseAddress is the start address of the image header
*
* @return - XST_SUCCESS if image header authentication is successful
* - XST_FAILURE if image header authentication is failed
*
* @note None
*
****************************************************************************/
u32 GetNAuthImageHeader(u32 ImageBaseAddress)
{
u32 Status;
u32 Offset;
u8 *HdrTmpPtr = (u8 *) DDR_TEMP_START_ADDR;
u32 Size;
u8 *Ac;
u8 Hash[SHA_VALBYTES];
sha2_context Sha2Instance;
/*
* Get the start address of the image header table
*/
Status = GetImageHeaderStartAddr(ImageBaseAddress, &Offset);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n");
return XST_FAILURE;
}
Size = IMAGE_HEADER_TABLE_SIZE + TOTAL_IMAGE_HEADER_SIZE;
/* Read image header table and all image headers */
Status = MoveImage(ImageBaseAddress + Offset, (u32)HdrTmpPtr,
Size);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Move IHT and IHs failed\r\n");
return XST_FAILURE;
}
/* Update SHA */
sha2_starts(&Sha2Instance);
sha2_update(&Sha2Instance, (u8 *)HdrTmpPtr, Size);
sha2_update(&Sha2Instance, (u8 *)&PartitionHeader[0],
TOTAL_PARTITION_HEADER_SIZE);
/*
* Get the start address of the partition header table
*/
Status = GetPartitionHeaderStartAddr(ImageBaseAddress, &Offset);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL, "Get Header Start Address Failed\r\n");
return XST_FAILURE;
}
Offset = Offset + TOTAL_PARTITION_HEADER_SIZE;
Size = TOTAL_HEADER_SIZE + RSA_SIGNATURE_SIZE - (Size + TOTAL_PARTITION_HEADER_SIZE);
/* Read RSA signature */
Status = MoveImage(ImageBaseAddress + Offset, (u32)HdrTmpPtr, Size);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Move image header signature is failed\r\n");
return XST_FAILURE;
}
sha2_update(&Sha2Instance, (u8 *)(HdrTmpPtr),
Size - RSA_PARTITION_SIGNATURE_SIZE);
sha2_finish(&Sha2Instance, Hash);
FsblPrintArray(Hash, 32,"Header Hash Calculated");
/* Authentication of image header */
Ac = (u8 *)(HdrTmpPtr + 64);
Status = AuthenticatePartition((u8 *)Ac, Hash);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_GENERAL,"Image header authentication is 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;
u8 SecureTransferFlag = 0;
u32 LoadAddr;
u32 ImageWordLen;
u32 DataWordLen;
SourceAddr = ImageBaseAddress;
SourceAddr += Header->PartitionStart<<WORD_LENGTH_SHIFT;
LoadAddr = Header->LoadAddr;
ImageWordLen = Header->ImageWordLen;
DataWordLen = Header->DataWordLen;
/*
* 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;
}
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;
}
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))) {
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;
}