Example #1
0
/**
*
* 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;
}