/****************************************************************************** * 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. * *
* 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 * 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() * ** * @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<