/** * * This function reads the data at the provided FLASH address and expects * the partition header structure to be present. If the header is not * present (blank FLASH) or does not match expected values, MOVE_IMAGE_FAIL * is returned. * * There are four cases in partition handling: * * 1. If attribute indicates this is a bitstream partition, FPGA is programmed, * and if this is the last partition, FSBL hangs with WDT kicking * 2. If Image word Length != data word length, the partition is encrypted * partition. The partition is decrypted into DDR * 3. Other cases, partition is moved from flash to DDR through copying or DMA * 4. If partition data word length is 0, the partition is to be skipped. Note * that partition header cannot be encrypted for this to work * * Except case 1, the reboot status register is updated to reflect the next * partition. * * @param ImageAddress is the start of the image * @param PartitionNum is the index of the partition to process * * @return * - MOVE_IMAGE_FAIL (0xFFFFFFFF) if image load failed * - Address to begin executing at if successful * * @note * ****************************************************************************/ u32 PartitionMove(u32 ImageAddress, int PartitionNum) { u32 SourceAddr; u32 LoadAddr; u32 ExecAddr; u32 ImageLength; u32 DataLength; u32 SectionCount; u32 PartitionStart; u32 PartitionLength; u32 NextPartitionAddr; int NextPartition; u32 Status; u32 Attribute; /* Flag to determine if image is encrypted or not */ u32 IsEncrypted = 0; struct HeaderArray *Hap; struct PartHeader Header; /* Execution Address */ ExecAddr = MOVE_IMAGE_FAIL; /* Default is not to skip partition execution */ SkipPartition = 0; fsbl_printf(DEBUG_INFO,"image move with partition number %d\r\n", PartitionNum); PartitionStart = GoToPartition(ImageAddress, PartitionNum); GetHeader(PartitionStart, &Header); fsbl_printf(DEBUG_INFO,"Header dump:\n\r"); DumpHeader(&Header); Hap = (struct HeaderArray *)&Header; Status = ValidateHeader(&Header); if(Status != XST_SUCCESS) { return Status; } ImageLength = Header.ImageWordLen; DataLength = Header.DataWordLen; PartitionLength = Header.PartitionWordLen; LoadAddr = Header.LoadAddr; ExecAddr = Header.ExecAddr; SourceAddr = Header.PartitionStart; Attribute = Header.PartitionAttr; SectionCount = Header.SectionCount; /* The offset in header is word offset */ SourceAddr = SourceAddr << WORD_LENGTH_SHIFT; /* Consider image offset */ SourceAddr += ImageAddress; fsbl_printf(DEBUG_INFO,"Partition Start %08x, " "Partition Length %08x\r\n", PartitionStart, PartitionLength); fsbl_printf(DEBUG_INFO,"Source addr %08x, Load addr %08x, " "Exec addr %08x\r\n", SourceAddr, LoadAddr, ExecAddr); /* * If encrypted partition header, will get wrong next partition * address. Next run will fail and invoke FSBL fallback. * WARNING: Cannot handle skipping over encrypted partition header */ if (DataLength == 0) { fsbl_printf(DEBUG_INFO,"PartitionImageMove: skip partition. " "If encrypted partition, will fail\r\n"); SkipPartition = 1; goto update_status_reg; } if (Attribute == ATTRIBUTE_PL_IMAGE_MASK) { /* FSBL user hook call before bitstream download. */ Status = FsblHookBeforeBitstreamDload(); if (Status != XST_SUCCESS) { /* Error Handling here */ fsbl_printf(DEBUG_GENERAL,"FSBL_BEFORE_BSTREAM_HOOK_FAILED\r\n"); OutputStatus(FSBL_BEFORE_BSTREAM_HOOK_FAIL); FsblFallback(); } /* Check if encrypted or non encrypted */ /* If the ImageLength not equal to DataLength, encrypted */ if (ImageLength != DataLength) { IsEncrypted = 1; fsbl_printf(DEBUG_INFO,"Encrypted partition \r \n"); } fsbl_printf(DEBUG_INFO,"Source addr %x, load addr %x, " "exec addr %x\r\n", SourceAddr, LoadAddr, ExecAddr); fsbl_printf(DEBUG_GENERAL,"Bitstream Download Start \r\n"); if (IsEncrypted) { /* Bitstream NAND/SD encrypted */ if (((FlashReadBaseAddress & 0xFF000000) == XPS_NAND_BASEADDR) || (FlashReadBaseAddress == XPS_SDIO0_BASEADDR)) { fsbl_printf(DEBUG_INFO,"Bitstream NAND/SD encrypted \r\n"); Status = WritePcapXferData( (u32 *)(SourceAddr), (u32 *)XDCFG_DMA_INVALID_ADDRESS, (ImageLength), 0, XDCFG_SECURE_PCAP_WRITE); } else { /* Bitstream QSPI/NOR Encrypted */ fsbl_printf(DEBUG_INFO,"Bit stream QSPI/NOR encrypted \r\n"); Status = WritePcapXferData( (u32 *)(FlashReadBaseAddress + SourceAddr), (u32 *)XDCFG_DMA_INVALID_ADDRESS, (ImageLength), 0, XDCFG_SECURE_PCAP_WRITE); } } else { /* Bitstream NAND/SD Unencrypted */ if (((FlashReadBaseAddress & 0xFF000000) == XPS_NAND_BASEADDR) || (FlashReadBaseAddress == XPS_SDIO0_BASEADDR)) { fsbl_printf(DEBUG_INFO,"Bit stream NAND/SD Unencrypted \r\n"); Status = WritePcapXferData( (u32 *)(SourceAddr), (u32 *)XDCFG_DMA_INVALID_ADDRESS, (ImageLength), 0, XDCFG_NON_SECURE_PCAP_WRITE); } else { /* Bitstream QSPI/NOR - unencrypted */ fsbl_printf(DEBUG_INFO,"Bitstream QSPI/NOR Unencrypted \r\n"); Status = WritePcapXferData( (u32 *)(FlashReadBaseAddress + SourceAddr), (u32 *)XDCFG_DMA_INVALID_ADDRESS, (ImageLength), 0, XDCFG_NON_SECURE_PCAP_WRITE); } } if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"BITSTREAM_DOWNLOAD_FAIL"); OutputStatus(BITSTREAM_DOWNLOAD_FAIL); return MOVE_IMAGE_FAIL; } else { fsbl_printf(DEBUG_GENERAL,"Bitstream download successful!\r\n"); } /* FSBL user hook call after bitstream download. */ Status = FsblHookAfterBitstreamDload(); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"FSBL_AFTER_BSTREAM_HOOK_FAIL"); /* Error Handling here */ OutputStatus(FSBL_AFTER_BSTREAM_HOOK_FAIL); FsblFallback(); } /* We will skip soft reset and start loading the next partition */ SkipPartition = 1; /* Go to the next partition */ goto update_status_reg; } /* End of bitstream */ /* Process all the partitions of application */ while(SectionCount-- > 0) { /* If image length not equal to data length, encrypted */ if (ImageLength != DataLength) { IsEncrypted = 1; fsbl_printf(DEBUG_INFO,"Application encrypted\n\r"); /* NAND and SD do not support encrypted partitions */ if (((FlashReadBaseAddress & 0xFF000000) == XPS_NAND_BASEADDR) || (FlashReadBaseAddress == XPS_SDIO0_BASEADDR)) { fsbl_printf(DEBUG_INFO,"Images on NAND or SD encrypted\r\n"); Status = WritePcapXferData( (u32 *)SourceAddr, (u32 *)LoadAddr, ImageLength, DataLength, XDCFG_SECURE_PCAP_WRITE); } else { Status = WritePcapXferData( (u32 *)(FlashReadBaseAddress + SourceAddr), (u32 *)LoadAddr, ImageLength, DataLength, XDCFG_SECURE_PCAP_WRITE); } if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"DECRYPTION_FAIL \r\n"); OutputStatus(DECRYPTION_FAIL); return MOVE_IMAGE_FAIL; } fsbl_printf(DEBUG_INFO,"Transfer is completed \r\n"); if (SectionCount != 0) { fsbl_printf(DEBUG_INFO,"load_next_partition\n\r"); goto load_next_partition; } goto update_status_reg; } else {/*End of if ImageLength != DataLength */ fsbl_printf(DEBUG_INFO,"Start transfer data into DDR\n\r"); /* Copy the flash contents to DDR */ MoveImage(SourceAddr, LoadAddr, (DataLength << WORD_LENGTH_SHIFT)); } load_next_partition: //JM detect cpu1 boot vector as last partiton and finish up if (LoadAddr == 0xFFFFFFF0) { goto update_status_reg; } PartitionNum += 1; /* Read the next partition */ fsbl_printf(DEBUG_INFO,"Get next partition header\n\r"); NextPartitionAddr = GoToPartition(ImageAddress, PartitionNum); GetHeader(NextPartitionAddr, &Header); fsbl_printf(DEBUG_INFO,"Next partition header dump\r\n"); DumpHeader(&Header); Status = ValidateHeader(&Header); if(Status != XST_SUCCESS) { fsbl_printf(DEBUG_INFO,"Validation of Header failed\r\n"); return Status; } /* Don't re-initialize ExecAddr & SectionCount */ ImageLength = Header.ImageWordLen; DataLength = Header.DataWordLen; PartitionLength = Header.PartitionWordLen; LoadAddr = Header.LoadAddr; SourceAddr = Header.PartitionStart; //JM reinit SectionCount if this is a new sub-partition if (SectionCount == 0) { SectionCount = Header.SectionCount; } /* The offset in header is word offset */ SourceAddr = SourceAddr << WORD_LENGTH_SHIFT; /* Consider image offset */ SourceAddr += ImageAddress; fsbl_printf(DEBUG_INFO,"Partition Start %08x, Partition Length %08x\r\n", PartitionStart, PartitionLength); fsbl_printf(DEBUG_INFO,"Source addr %08x, Load addr %08x, Exec addr %08x\r\n", SourceAddr, LoadAddr, ExecAddr); } /* End of while Section count > 0 */ update_status_reg: NextPartition = PartitionNum + 1; fsbl_printf(DEBUG_INFO,"Get next partition header\n\r"); NextPartitionAddr = GoToPartition(ImageAddress, PartitionNum + 1); GetHeader(NextPartitionAddr, &Header); Hap = (struct HeaderArray *)&Header; fsbl_printf(DEBUG_INFO,"Next Header dump:\n\r"); DumpHeader(&Header); /* If it is the last partition, then we will keep on running this one */ if (IsLastPartition(Hap)) { fsbl_printf(DEBUG_INFO,"There are no more partitions to load\r\n"); NextPartition = PartitionNum; /* * Fix for CR #663277 * Review : Since we donot support OCM remap, * any elf whose execution address is 0x0 * We will do a JTAG exit */ if (ExecAddr == 0) { fsbl_printf(DEBUG_INFO,"No Execution Address JTAG handoff \r\n"); /* Stop the Watchdog before JTAG handoff */ #ifdef XPAR_XWDTPS_0_BASEADDR XWdtPs_Stop(&Watchdog); #endif ClearFSBLIn(); FsblHandoffJtagExit(); } } else if(IsEmptyHeader(Hap)) { fsbl_printf(DEBUG_GENERAL,"Empty partition header \r\n"); OutputStatus(EMPTY_PARTITION_HEADER); return MOVE_IMAGE_FAIL; } Status = FsblSetNextPartition(NextPartition); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_INFO,"Next partition number %d is not valid\n", NextPartition); OutputStatus(TOO_MANY_PARTITIONS); return MOVE_IMAGE_FAIL; } fsbl_printf(DEBUG_INFO,"end of partition move, reboot status reg %x, " "Next partition %d\r\n", MoverIn32(REBOOT_STATUS_REG), NextPartition); /* Returning Execution Address */ return ExecAddr; } /* End of Partition Move */
/** * * 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%08x\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%08x\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%08x\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: %d\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 %0x\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; } /* * 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(); 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; }