/** * * 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 validates the partition header. * * @param Partition header pointer * * @return * - MOVE_IMAGE_FAIL if bad header. * - XST_SUCCESS if successful. * * @note None * *******************************************************************************/ u32 ValidateHeader(struct PartHeader *Header) { struct HeaderArray *Hap; u32 ImageLength; u32 PartitionLength; Hap = (struct HeaderArray *)Header; /* If there are no partitions to load, fail */ if (IsLastPartition(Hap) || IsEmptyHeader(Hap)) { fsbl_printf(DEBUG_GENERAL,"IMAGE_HAS_NO_PARTITIONS\r\n"); OutputStatus(IMAGE_HAS_NO_PARTITIONS); return MOVE_IMAGE_FAIL; } /* Validate Checksum of partition header */ if (PartitionHeaderChecksum(Hap) == XST_FAILURE) { fsbl_printf(DEBUG_GENERAL,"PARTITION_HEADER_CORRUPTION\r\n"); OutputStatus(PARTITION_HEADER_CORRUPTION); return MOVE_IMAGE_FAIL; } ImageLength = Header->ImageWordLen; PartitionLength = Header->PartitionWordLen; if (ImageLength > MAXIMUM_IMAGE_WORD_LEN) { fsbl_printf(DEBUG_GENERAL,"INVALID_PARTITION_LENGTH\r\n"); OutputStatus(INVALID_PARTITION_LENGTH); return MOVE_IMAGE_FAIL; } /* For current tool implementation, partition header is not * encrypted. If the tool will encrypt the partition header, * the following should be overwritten after header decryption */ if (ImageLength == 0) { /* if it is an empty partition, it is OK */ if (PartitionLength != 0) { fsbl_printf(DEBUG_INFO,"PartitionImageMove:" "0 Image Length, " "non-zero partition Length\r\n"); fsbl_printf(DEBUG_GENERAL,"INVALID_PARTITION_HEADER\r\n"); OutputStatus(INVALID_PARTITION_HEADER); return MOVE_IMAGE_FAIL; } } return XST_SUCCESS; } /* end of ValidateHeader */
/** * * 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 */