/** * This function is initializes the processor and system. * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return * - returns the error codes described in xfsbl_error.h on any error * - returns XFSBL_SUCCESS on success * *****************************************************************************/ u32 XFsbl_Initialize(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; u32 ResetReason; ResetReason = XFsbl_GetResetReason(); if (ResetReason == PS_ONLY_RESET) { FsblInstancePtr->ResetReason = PS_ONLY_RESET; } /** * Configure the system as in PSU */ Status = XFsbl_SystemInit(FsblInstancePtr); if (XFSBL_SUCCESS != Status) { goto END; } /** * Print the FSBL banner */ XFsbl_PrintFsblBanner(); /* Do ECC Initialization of DDR if required */ Status = XFsbl_DdrEccInit(); if (XFSBL_SUCCESS != Status) { goto END; } /* Do board specific initialization if any */ Status = XFsbl_BoardInit(); if (XFSBL_SUCCESS != Status) { goto END; } /** * Initialize the processor */ Status = XFsbl_ProcessorInit(FsblInstancePtr); if (XFSBL_SUCCESS != Status) { goto END; } /** * Validate the reset reason */ Status = XFsbl_ResetValidation(FsblInstancePtr); if (XFSBL_SUCCESS != Status) { goto END; } XFsbl_Printf(DEBUG_INFO,"Processor Initialization Done \n\r"); END: return Status; }
void XFsbl_PrintFsblBanner(void ) { /** * Print the FSBL Banner */ XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Xilinx Zynq MP First Stage Boot Loader \n\r"); XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Release %d.%d %s - %s\r\n", SDK_RELEASE_YEAR, SDK_RELEASE_QUARTER,__DATE__,__TIME__); /** * Print the platform */ if (XFSBL_PLATFORM == XFSBL_PLATFORM_QEMU) { XFsbl_Printf(DEBUG_GENERAL, "Platform: QEMU, "); } else if (XFSBL_PLATFORM == XFSBL_PLATFORM_REMUS) { XFsbl_Printf(DEBUG_GENERAL, "Platform: REMUS, "); } else if (XFSBL_PLATFORM == XFSBL_PLATFORM_SILICON) { XFsbl_Printf(DEBUG_GENERAL, "Platform: Silicon, "); } else { XFsbl_Printf(DEBUG_GENERAL, "Platform Not identified \r\n"); } return ; }
/** * * * * @param None * * @return None * ******************************************************************************/ void XFsbl_MakeSdFileName(char *XFsbl_SdEmmcFileName, u32 MultibootReg, u32 DrvNum) { u32 Index; u32 Value; u32 FileNameLen; u32 MultiBootNum = MultibootReg; if (0x0U == MultiBootNum) { /* SD file name is BOOT.BIN when Multiboot register value is 0 */ if (DrvNum == XFSBL_SD_DRV_NUM_0) { (void)XFsbl_Strcpy(XFsbl_SdEmmcFileName, "BOOT.BIN"); } else { /* For second SD instance, include drive number 1 as well */ (void)XFsbl_Strcpy(XFsbl_SdEmmcFileName, "1:/BOOT.BIN"); } } else { /* set default SD file name as BOOT0000.BIN */ if (DrvNum == XFSBL_SD_DRV_NUM_0) { (void)XFsbl_Strcpy(XFsbl_SdEmmcFileName, "BOOT0000.BIN"); FileNameLen = XFSBL_BASE_FILE_NAME_LEN_SD_0; } else { /* For second SD instance, include drive number 1 as well */ (void)XFsbl_Strcpy(XFsbl_SdEmmcFileName, "1:/BOOT0000.BIN"); FileNameLen = XFSBL_BASE_FILE_NAME_LEN_SD_1; } /* Update file name (to BOOTXXXX.BIN) based on Multiboot register value */ for(Index = FileNameLen - 1U; Index >= (FileNameLen - XFSBL_NUM_DIGITS_IN_FILE_NAME); Index--) { Value = MultiBootNum % 10U; MultiBootNum = MultiBootNum / 10U; XFsbl_SdEmmcFileName[Index] += (char)Value; if (MultiBootNum == 0U) { break; } } } XFsbl_Printf(DEBUG_INFO, "File name is %s\r\n",XFsbl_SdEmmcFileName); }
static u32 XFsbl_ResetValidation(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; u32 FsblErrorStatus=0U; u32 ResetReasonValue=0U; u32 ErrStatusRegValue; /** * Read the Error Status register * If WDT reset, do fallback */ FsblErrorStatus = XFsbl_In32(XFSBL_ERROR_STATUS_REGISTER_OFFSET); ResetReasonValue = XFsbl_In32(CRL_APB_RESET_REASON); ErrStatusRegValue = XFsbl_In32(PMU_GLOBAL_ERROR_STATUS_1); /** * Check if the reset is due to system WDT during * previous FSBL execution */ if (((ResetReasonValue & CRL_APB_RESET_REASON_PMU_SYS_RESET_MASK) == CRL_APB_RESET_REASON_PMU_SYS_RESET_MASK) && ((ErrStatusRegValue & PMU_GLOBAL_ERROR_STATUS_1_LPD_SWDT_MASK) == PMU_GLOBAL_ERROR_STATUS_1_LPD_SWDT_MASK) && (FsblErrorStatus == XFSBL_RUNNING)) { /** * reset is due to System WDT. * Do a fallback */ Status = XFSBL_ERROR_SYSTEM_WDT_RESET; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_SYSTEM_WDT_RESET\n\r"); goto END; } /** * Mark FSBL running in error status register to * detect the WDT reset while FSBL execution */ if (FsblErrorStatus != XFSBL_RUNNING) { XFsbl_Out32(XFSBL_ERROR_STATUS_REGISTER_OFFSET, XFSBL_RUNNING); } /** * Read system error status register * provide FsblHook function for any action */ END: return Status; }
/** * This function waits for PL Done bit to be set or till timeout and resets * PCAP after this. * * @param None * * @return error status based on implemented functionality (SUCCESS by default) * *****************************************************************************/ u32 XFsbl_PLWaitForDone(void) { u32 Status = XFSBL_SUCCESS; u32 PollCount; u32 RegVal; PollCount = (PL_DONE_POLL_COUNT); while (PollCount) { /* Read PCAP Status register and check for PL_DONE bit */ RegVal = XFsbl_In32(CSU_PCAP_STATUS); RegVal &= CSU_PCAP_STATUS_PL_DONE_MASK; if (RegVal == CSU_PCAP_STATUS_PL_DONE_MASK) { break; } PollCount--; } if (RegVal == CSU_PCAP_STATUS_PL_DONE_MASK) { XFsbl_Printf(DEBUG_GENERAL, "PL Configuration done successfully \r\n"); } else { Status = XFSBL_ERROR_BITSTREAM_LOAD_FAIL; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_BITSTREAM_LOAD_FAIL\r\n"); goto END; } /* Reset PCAP after data transfer */ RegVal = XFsbl_In32(CSU_PCAP_RESET); RegVal = RegVal | CSU_PCAP_RESET_RESET_MASK; XFsbl_Out32(CSU_PCAP_RESET, RegVal); do { RegVal = XFsbl_In32(CSU_PCAP_RESET); RegVal = RegVal & CSU_PCAP_RESET_RESET_MASK; } while (RegVal != CSU_PCAP_RESET_RESET_MASK); END: return Status; }
void XFsbl_EccInitialize(u32 Address, u32 Length) { u32 Index=0U; /* Disable cache to ensure proper ECC initialization */ Xil_DCacheDisable(); while (Index<Length) { XFsbl_Out32(Address+Index, 1U) ; Index += 4U; } Xil_DCacheEnable(); XFsbl_Printf(DEBUG_INFO, "Address 0x%0lx, Length %0lx, ECC initialized \r\n", Address, Length); return ; }
/** * In Fallback, soft reset is applied to the system after incrementing * the multiboot register. A hook is provided to before the fallback so * that users can write their own code before soft reset * * @param none * * @return none * * @note We will not return from this function as it does soft reset *****************************************************************************/ void XFsbl_FallBack(void) { u32 RegValue; #ifdef XFSBL_WDT_PRESENT /* Stop WDT as we are restarting */ XFsbl_StopWdt(); #endif /* Hook before FSBL Fallback */ XFsbl_HookBeforeFallback(); /* Read the Multiboot register */ RegValue = XFsbl_In32(CSU_CSU_MULTI_BOOT); XFsbl_Printf(DEBUG_GENERAL,"Performing FSBL FallBack\n\r"); XFsbl_UpdateMultiBoot(RegValue+1); return; }
void XFsbl_UpdateMultiBoot(u32 MultiBootValue) { u32 RegValue; XFsbl_Out32(CSU_CSU_MULTI_BOOT, MultiBootValue); /* make sure every thing completes */ dsb(); isb(); /* Soft reset the system */ XFsbl_Printf(DEBUG_GENERAL,"Performing System Soft Reset\n\r"); RegValue = XFsbl_In32(CRL_APB_RESET_CTRL); XFsbl_Out32(CRL_APB_RESET_CTRL, RegValue|CRL_APB_RESET_CTRL_SOFT_RESET_MASK); /* wait here until reset happens */ while(1); return; }
/** * FSBL exit function before the assembly code * * @param HandoffAddress is handoff address for the FSBL running cpu * * @param Flags is to determine whether to handoff to applicatio or * to be in wfe state * * @return None * * *****************************************************************************/ void XFsbl_HandoffExit(u64 HandoffAddress, u32 Flags) { /** * Flush the L1 data cache and L2 cache, Disable Data Cache */ Xil_DCacheDisable(); XFsbl_Printf(DEBUG_GENERAL,"Exit from FSBL \n\r"); /** * Exit to handoff address * PTRSIZE is used since handoff is in same running cpu * and address is of PTRSIZE */ XFsbl_Exit((PTRSIZE) HandoffAddress, Flags); /** * should not reach here */ return ; }
/** * This function is initializes the processor and system. * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return * - returns the error codes described in xfsbl_error.h on any error * - returns XFSBL_SUCCESS on success * *****************************************************************************/ u32 XFsbl_Initialize(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; /** * Configure the system as in PSU */ Status = XFsbl_SystemInit(FsblInstancePtr); if (XFSBL_SUCCESS != Status) { goto END; } /** * Print the FSBL banner */ XFsbl_PrintFsblBanner(); /** * Initialize the processor */ Status = XFsbl_ProcessorInit(FsblInstancePtr); if (XFSBL_SUCCESS != Status) { goto END; } /** * Validate the reset reason */ Status = XFsbl_ResetValidation(FsblInstancePtr); if (XFSBL_SUCCESS != Status) { goto END; } XFsbl_Printf(DEBUG_INFO,"Processor Initialization Done \n\r"); END: return Status; }
/** * * @param * * @return * * @note * * *****************************************************************************/ static void XFsbl_UndefHandler (void) { XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_UNDEFINED_EXCEPTION\n\r"); XFsbl_ErrorLockDown(XFSBL_ERROR_UNDEFINED_EXCEPTION); }
/** * This function initializes the processor and updates the cluster id * which indicates CPU on which fsbl is running * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_ProcessorInit(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; //u64 ClusterId=0U; PTRSIZE ClusterId=0U; u32 RegValue; u32 Index=0U; /** * Read the cluster ID and Update the Processor ID * Initialize the processor settings that are not done in * BSP startup code */ #ifdef ARMA53_64 ClusterId = mfcp(MPIDR_EL1); #else ClusterId = mfcp(XREG_CP15_MULTI_PROC_AFFINITY); #endif XFsbl_Printf(DEBUG_INFO,"Cluster ID 0x%0lx\n\r", ClusterId); if (XGet_Zynq_UltraMp_Platform_info() == XPLAT_ZYNQ_ULTRA_MPQEMU) { /** * Remmaping for R5 in QEMU */ if (ClusterId == 0x80000004U) { ClusterId = 0xC0000100U; } else if (ClusterId == 0x80000005U) { /* this corresponds to R5-1 */ Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } else { /* For MISRA C compliance */ } } /* store the processor ID based on the cluster ID */ if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_A53_PROCESSOR) { XFsbl_Printf(DEBUG_GENERAL,"Running on A53-0 "); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_A53_0; #ifdef __aarch64__ /* Running on A53 64-bit */ XFsbl_Printf(DEBUG_GENERAL,"(64-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA64; #else /* Running on A53 32-bit */ XFsbl_Printf(DEBUG_GENERAL,"(32-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA32; #endif } else if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_R5_PROCESSOR) { /* A53ExecState is not valid for R5 */ FsblInstancePtr->A53ExecState = XIH_INVALID_EXEC_ST; RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); if ((RegValue & RPU_RPU_GLBL_CNTL_SLSPLIT_MASK) == 0U) { XFsbl_Printf(DEBUG_GENERAL, "Running on R5 Processor in Lockstep \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_L; } else { XFsbl_Printf(DEBUG_GENERAL, "Running on R5-0 Processor \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_0; } /** * Update the Vector locations in R5 TCM */ while (Index<32U) { XFsbl_Out32(Index, XFSBL_R5_VECTOR_VALUE); Index += 4; } } else { Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } /** * Register the exception handlers */ XFsbl_RegisterHandlers(); /* Prints for the perf measurement */ #ifdef XFSBL_PERF #if !defined(ARMR5) if (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_A53_0) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Proc: A53-0 Freq: %d Hz", XPAR_CPU_CORTEXA53_0_CPU_CLK_FREQ_HZ); if (FsblInstancePtr->A53ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, " Arch: 32 \r\n"); } else if (FsblInstancePtr->A53ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA64) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, " Arch: 64 \r\n"); } } #else if (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_0) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Proc: R5-0 Freq: %d Hz \r\n", XPAR_PSU_CORTEXR5_0_CPU_CLK_FREQ_HZ) } else if (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_L) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Proc: R5-Lockstep " "Freq: %d Hz \r\n", XPAR_PSU_CORTEXR5_0_CPU_CLK_FREQ_HZ); } #endif #endif END: return Status; }
/** * This function is used to perform GT configuration for ZCU102 board. * It also provides reset to GEM, enables FMC ADJ * * @param none * * @return * - XFSBL_SUCCESS for successful configuration * - errors as mentioned in xfsbl_error.h * *****************************************************************************/ static s32 XFsbl_BoardConfig(void) { u8 WriteBuffer[BUF_LEN] = {0}; XIicPs_Config *I2c0CfgPtr; s32 Status = XFSBL_SUCCESS; u32 ICMCfg0; u32 ICMCfg1; /* Initialize the IIC0 driver so that it is ready to use */ I2c0CfgPtr = XIicPs_LookupConfig(XPAR_XIICPS_0_DEVICE_ID); if (I2c0CfgPtr == NULL) { Status = XFSBL_ERROR_I2C_INIT; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_I2C_INIT\r\n"); goto END; } Status = XIicPs_CfgInitialize(&I2c0InstancePtr, I2c0CfgPtr, I2c0CfgPtr->BaseAddress); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_I2C_INIT; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_I2C_INIT\r\n"); goto END; } /* Set the IIC serial clock rate */ XIicPs_SetSClk(&I2c0InstancePtr, IIC_SCLK_RATE_IOEXP); /* Configure I/O pins as Output */ WriteBuffer[0] = CMD_CFG_0_REG; WriteBuffer[1] = DATA_OUTPUT; Status = XIicPs_MasterSendPolled(&I2c0InstancePtr, WriteBuffer, 2, IOEXPANDER1_ADDR); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_I2C_WRITE; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_I2C_WRITE\r\n"); goto END; } /* Wait until bus is idle to start another transfer */ while (XIicPs_BusIsBusy(&I2c0InstancePtr)); /* * Deasserting I2C_MUX_RESETB * And GEM3 Resetb * Selecting lanes based on configuration */ WriteBuffer[0] = CMD_OUTPUT_0_REG; /* Populate WriteBuffer[1] based on ICM_CFG configuration */ ICMCfg0 = XFsbl_In32(SERDES_ICM_CFG0) & (SERDES_ICM_CFG0_L0_ICM_CFG_MASK | SERDES_ICM_CFG0_L1_ICM_CFG_MASK); ICMCfg1 = XFsbl_In32(SERDES_ICM_CFG1) & (SERDES_ICM_CFG1_L2_ICM_CFG_MASK | SERDES_ICM_CFG1_L3_ICM_CFG_MASK); if ((ICMCfg0 == ICM_CFG0_PCIE_DP) && (ICMCfg1 == ICM_CFG1_USB_SATA)) { /* gt1110 */ WriteBuffer[1] = DATA_COMMON_CFG | DATA_GT_1110_CFG; } else if ((ICMCfg0 == ICM_CFG0_DP_DP) && (ICMCfg1 == ICM_CFG1_USB_SATA)) { /* gt1111 */ WriteBuffer[1] = DATA_COMMON_CFG | DATA_GT_1111_CFG; } else if ((ICMCfg0 == ICM_CFG0_PCIE_PCIE) && (ICMCfg1 == ICM_CFG1_USB_SATA)) { /* gt1100 */ WriteBuffer[1] = DATA_COMMON_CFG | DATA_GT_1100_CFG; } else { /* gt0000 or no GT configuration */ WriteBuffer[1] = DATA_COMMON_CFG | DATA_GT_0000_CFG; } /* Send the Data */ Status = XIicPs_MasterSendPolled(&I2c0InstancePtr, WriteBuffer, 2, IOEXPANDER1_ADDR); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_I2C_WRITE; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_I2C_WRITE\r\n"); goto END; } /* Wait until bus is idle */ while (XIicPs_BusIsBusy(&I2c0InstancePtr)); /* Change the IIC serial clock rate */ XIicPs_SetSClk(&I2c0InstancePtr, IIC_SCLK_RATE_I2CMUX); /* Set I2C Mux for channel-2 (MAXIM_PMBUS) */ WriteBuffer[0] = CMD_CH_2_REG; Status = XIicPs_MasterSendPolled(&I2c0InstancePtr, WriteBuffer, 1, PCA9544A_ADDR); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_I2C_WRITE; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_I2C_WRITE\r\n"); goto END; } /* Wait until bus is idle */ while (XIicPs_BusIsBusy(&I2c0InstancePtr)); /* Enable Regulator (FMC ADJ) */ WriteBuffer[0] = CMD_ON_OFF_CFG; WriteBuffer[1] = ON_OFF_CFG_VAL; Status = XIicPs_MasterSendPolled(&I2c0InstancePtr, WriteBuffer, 2, MAX15301_ADDR); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_I2C_WRITE; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_I2C_WRITE\r\n"); goto END; } /* Wait until bus is idle */ while (XIicPs_BusIsBusy(&I2c0InstancePtr)); XFsbl_Printf(DEBUG_INFO,"Board Configuration successful \n\r"); END: return Status; }
/** * This function validates the partition * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @param PartitionNum is the partition number in the image to be loaded * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * *****************************************************************************/ static u32 XFsbl_PartitionValidation(XFsblPs * FsblInstancePtr, u32 PartitionNum) { u32 Status=XFSBL_SUCCESS; u32 ChecksumType=0U; s32 IsEncryptionEnabled=FALSE; s32 IsAuthenticationEnabled=FALSE; u32 DestinationDevice=0U; u32 DestinationCpu=0U; u32 ExecState=0U; u32 CpuNo=0U; XFsblPs_PartitionHeader * PartitionHeader; #if defined(XFSBL_RSA) u32 HashLen=0U; #endif #if defined(XFSBL_AES) u32 ImageOffset = 0U; u32 FsblIv[XIH_BH_IV_LENGTH / 4U]; u32 UnencryptedLength = 0; u32 IvLocation; #endif #if defined(XFSBL_RSA) || defined(XFSBL_AES) u32 Length=0U; #endif #if defined(XFSBL_RSA) || defined(XFSBL_AES) || defined(XFSBL_BS) PTRSIZE LoadAddress=0U; #endif #if defined(XFSBL_BS) u32 BitstreamWordSize = 0; #endif /** * Update the variables */ PartitionHeader = &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]; ChecksumType = XFsbl_GetChecksumType(PartitionHeader); /** * Check the encryption status */ if (XFsbl_IsEncrypted(PartitionHeader) == XIH_PH_ATTRB_ENCRYPTION ) { IsEncryptionEnabled = TRUE; #ifdef XFSBL_AES /* Copy the Iv from Flash into local memory */ IvLocation = ImageOffset + XIH_BH_IV_OFFSET; Status = FsblInstancePtr->DeviceOps.DeviceCopy(IvLocation, (PTRSIZE) FsblIv, XIH_BH_IV_LENGTH); if (Status != XFSBL_SUCCESS) { XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_DECRYPTION_IV_COPY_FAIL \r\n"); Status = XFSBL_ERROR_DECRYPTION_IV_COPY_FAIL; goto END; } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_AES_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_AES_NOT_ENABLED; goto END; #endif } /** * check the authentication status */ if (XFsbl_IsRsaSignaturePresent(PartitionHeader) == XIH_PH_ATTRB_RSA_SIGNATURE ) { IsAuthenticationEnabled = TRUE; } DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); DestinationCpu = XFsbl_GetDestinationCpu(PartitionHeader); /** * Get the execution state */ ExecState = XFsbl_GetA53ExecState(PartitionHeader); /** * if destination cpu is not present, it means it is for same cpu */ if (DestinationCpu == XIH_PH_ATTRB_DEST_CPU_NONE) { DestinationCpu = FsblInstancePtr->ProcessorID; } /** * Checksum Validation */ if (ChecksumType == XIH_PH_ATTRB_CHECKSUM_MD5) { /** * Do the checksum validation */ } #if defined(XFSBL_RSA) || defined(XFSBL_AES) if ((IsAuthenticationEnabled == TRUE) || (IsEncryptionEnabled == TRUE)) { LoadAddress = PartitionHeader->DestinationLoadAddress; Length = PartitionHeader->TotalDataWordLength * 4U; Status = XFsbl_GetLoadAddress(DestinationCpu, &LoadAddress, Length); if (XFSBL_SUCCESS != Status) { goto END; } } #endif #ifdef XFSBL_BS if ((DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) && (LoadAddress == 0U)) { LoadAddress = XFSBL_DDR_TEMP_ADDRESS; } #endif /** * Authentication Check */ if (IsAuthenticationEnabled == TRUE) { XFsbl_Printf(DEBUG_INFO,"Authentication Enabled\r\n"); #ifdef XFSBL_RSA /** * Get the Sha type to be used from * boot header attributes */ if ((FsblInstancePtr->BootHdrAttributes & XIH_BH_IMAGE_ATTRB_SHA2_MASK) == XIH_BH_IMAGE_ATTRB_SHA2_MASK) { HashLen = XFSBL_HASH_TYPE_SHA2; } else { HashLen = XFSBL_HASH_TYPE_SHA3; } /** * cache disbale can be removed */ Xil_DCacheDisable(); /** * Do the authentication validation */ Status = XFsbl_Authentication(FsblInstancePtr, LoadAddress, Length, (LoadAddress + Length) - XFSBL_AUTH_CERT_MIN_SIZE, HashLen); if (Status != XFSBL_SUCCESS) { goto END; } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_RSA_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_RSA_NOT_ENABLED; goto END; #endif } /** * Decrypt image through CSU DMA */ if (IsEncryptionEnabled == TRUE) { XFsbl_Printf(DEBUG_INFO, "Decryption Enabled\r\n"); #ifdef XFSBL_AES /* AES expects IV in big endian form */ FsblIv[0] = Xil_Htonl(FsblIv[0]); FsblIv[1] = Xil_Htonl(FsblIv[1]); FsblIv[2] = Xil_Htonl(FsblIv[2]); /* Initialize the Aes Instance so that it's ready to use */ XSecure_AesInitialize(&SecureAes, &CsuDma, XSECURE_CSU_AES_KEY_SRC_DEV, FsblIv, NULL); XFsbl_Printf(DEBUG_INFO, " Aes initialized \r\n"); UnencryptedLength = PartitionHeader->UnEncryptedDataWordLength * 4U; if (DestinationDevice != XIH_PH_ATTRB_DEST_DEVICE_PL) { Status = XSecure_AesDecrypt(&SecureAes, (u8 *) LoadAddress, (u8 *) LoadAddress, UnencryptedLength); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_DECRYPTION_FAIL; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_DECRYPTION_FAIL\r\n"); goto END; } else { XFsbl_Printf(DEBUG_GENERAL, "Decryption Successful\r\n"); } } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_AES_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_AES_NOT_ENABLED; goto END; #endif } #ifdef XFSBL_BS /** * for PL image use CSU DMA to route to PL */ if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) { /** * Fsbl hook before bit stream download */ Status = XFsbl_HookBeforeBSDownload(); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_HOOK_BEFORE_BITSTREAM_DOWNLOAD; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_HOOK_BEFORE_BITSTREAM_DOWNLOAD\r\n"); goto END; } XFsbl_Printf(DEBUG_GENERAL, "Bitstream download to start now\r\n"); Status = XFsbl_PcapInit(); if (Status != XFSBL_SUCCESS) { goto END; } if (IsEncryptionEnabled == TRUE) { #ifdef XFSBL_AES /* * The secure bitstream would be sent through CSU DMA to AES * and the decrypted bitstream is sent directly to PCAP * by configuring SSS appropriately */ Status = XSecure_AesDecrypt(&SecureAes, (u8 *) XFSBL_DESTINATION_PCAP_ADDR, (u8 *) LoadAddress, UnencryptedLength); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_BITSTREAM_DECRYPTION_FAIL; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_BITSTREAM_DECRYPTION_FAIL\r\n"); /* Reset PL */ XFsbl_Out32(CSU_PCAP_PROG, 0x0); goto END; } else { XFsbl_Printf(DEBUG_GENERAL, "Bitstream decryption Successful\r\n"); } #endif } else { /* Use CSU DMA to load Bit stream to PL */ BitstreamWordSize = PartitionHeader->UnEncryptedDataWordLength; Status = XFsbl_WriteToPcap(BitstreamWordSize, (u8 *) LoadAddress); if (Status != XFSBL_SUCCESS) { goto END; } } Status = XFsbl_PLWaitForDone(); if (Status != XFSBL_SUCCESS) { goto END; } /** * Fsbl hook after bit stream download */ Status = XFsbl_HookAfterBSDownload(); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_HOOK_AFTER_BITSTREAM_DOWNLOAD; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_HOOK_AFTER_BITSTREAM_DOWNLOAD\r\n"); goto END; } } #endif /** * Update the handoff details */ if ((DestinationDevice != XIH_PH_ATTRB_DEST_DEVICE_PL) && (DestinationDevice != XIH_PH_ATTRB_DEST_DEVICE_PMU)) { CpuNo = FsblInstancePtr->HandoffCpuNo; if (XFsbl_CheckHandoffCpu(FsblInstancePtr, DestinationCpu) == XFSBL_SUCCESS) { FsblInstancePtr->HandoffValues[CpuNo].CpuSettings = DestinationCpu | ExecState; FsblInstancePtr->HandoffValues[CpuNo].HandoffAddress = PartitionHeader->DestinationExecutionAddress; FsblInstancePtr->HandoffCpuNo += 1U; } } END: return Status; }
static u32 XFsbl_SetCpuPwrSettings (u32 CpuSettings, u32 Flags) { u32 RegValue; u32 Status; u32 CpuId; u32 ExecState; u32 PwrStateMask; /** * Reset the CPU */ if ((Flags & XFSBL_CPU_SWRST) != 0U) { CpuId = CpuSettings & XIH_PH_ATTRB_DEST_CPU_MASK; ExecState = CpuSettings & XIH_PH_ATTRB_A53_EXEC_ST_MASK; switch(CpuId) { case XIH_PH_ATTRB_DEST_CPU_A53_0: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU0_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_0_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_0_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU0); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU0_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU0_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_A53_1: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU1_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_1_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_1_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU1); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU1_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU1_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_A53_2: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU2_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_2_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_2_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU2); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU2_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU2_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_A53_3: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU3_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_3_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_3_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU3); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU3_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU3_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_R5_0: Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_R5_0_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_0_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_0_POWER_UP\r\n"); goto END; } /** * Place R5, TCM's in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= (RPU_RPU_GLBL_CNTL_SLSPLIT_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= (CRL_APB_CPU_R5_CTRL_CLKACT_MASK); XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void)usleep(0x50U); /** * Release reset to R5-0 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); /** * Take R5-0 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue |= RPU_RPU_0_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_0_CFG, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_R5_1: Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_R5_1_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_1_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_1_POWER_UP\r\n"); goto END; } /** * Place R5, TCM's in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLSPLIT_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void)usleep(0x50U); /** * Release reset to R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); /** * Take R5-1 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue |= RPU_RPU_1_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_1_CFG, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_R5_L: Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_R5_0_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_L_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_L_POWER_UP\r\n"); goto END; } /** * Place R5, TCM's in safe mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLSPLIT_MASK); RegValue |= RPU_RPU_GLBL_CNTL_TCM_COMB_MASK; RegValue |= RPU_RPU_GLBL_CNTL_SLCLAMP_MASK; XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void )usleep(0x50U); /** * Release reset to R5-0, R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); /** * Take R5-0 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue |= RPU_RPU_0_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Take R5-1 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue |= RPU_RPU_1_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_1_CFG, RegValue); break; default: XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_HANDOFF_CPUID\n\r"); Status = XFSBL_ERROR_HANDOFF_CPUID; break; } } else { Status = XFSBL_SUCCESS; } END: return Status; }
u32 XFsbl_GetLoadAddress(u32 DestinationCpu, PTRSIZE * LoadAddressPtr, u32 Length) { u32 Status = XFSBL_SUCCESS; PTRSIZE Address=0U; Address = *LoadAddressPtr; /** * Update for R50 TCM address */ if ((DestinationCpu == XIH_PH_ATTRB_DEST_CPU_R5_0) && (Address <= XFSBL_R5_TCM_END_ADDRESS)) { /** * Check if fits to TCM or not */ if ((Address + Length) > XFSBL_R5_TCM_END_ADDRESS) { Status = XFSBL_ERROR_LOAD_ADDRESS; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_LOAD_ADDRESS\r\n"); goto END; } /** * Update Address to the higher TCM address */ Address = XFSBL_R50_HIGH_TCM_START_ADDRESS + Address; } else /** * Update for R5-1 TCM address */ if ((DestinationCpu == XIH_PH_ATTRB_DEST_CPU_R5_1) && (Address <= XFSBL_R5_TCM_END_ADDRESS)) { /** * Check if fits to TCM or not */ if ((Address + Length) > XFSBL_R5_TCM_END_ADDRESS) { Status = XFSBL_ERROR_LOAD_ADDRESS; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_LOAD_ADDRESS\r\n"); goto END; } /** * Update Address to the higher TCM address */ Address = XFSBL_R51_HIGH_TCM_START_ADDRESS + Address; } else /** * Update for the R5-L TCM address */ if ((DestinationCpu == XIH_PH_ATTRB_DEST_CPU_R5_L) && (Address <= XFSBL_R5L_TCM_END_ADDRESS)) { /** * Check if fits to TCM or not */ if ((Address + Length) > XFSBL_R5L_TCM_END_ADDRESS) { Status = XFSBL_ERROR_LOAD_ADDRESS; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_LOAD_ADDRESS\r\n"); goto END; } /** * Update Address to the higher TCM address */ Address = XFSBL_R50_HIGH_TCM_START_ADDRESS + Address; } else { /** * For MISRA complaince */ } /** * Update the LoadAddress */ *LoadAddressPtr = Address; END: return Status; }
/** * This function copies the partition to specified destination * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @param PartitionNum is the partition number in the image to be loaded * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success *****************************************************************************/ static u32 XFsbl_PartitionCopy(XFsblPs * FsblInstancePtr, u32 PartitionNum) { u32 Status=XFSBL_SUCCESS; u32 DestinationCpu=0U; u32 CpuNo=0U; u32 DestinationDevice=0U; u32 ExecState=0U; XFsblPs_PartitionHeader * PartitionHeader; u32 SrcAddress=0U; PTRSIZE LoadAddress=0U; u32 Length=0U; u32 RunningCpu=0U; /** * Assign the partition header to local variable */ PartitionHeader = &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]; RunningCpu = FsblInstancePtr->ProcessorID; /** * Check for XIP image * No need to copy for XIP image */ DestinationCpu = XFsbl_GetDestinationCpu(PartitionHeader); /** * Get the execution state */ ExecState = XFsbl_GetA53ExecState(PartitionHeader); /** * if destination cpu is not present, it means it is for same cpu */ if (DestinationCpu == XIH_PH_ATTRB_DEST_CPU_NONE) { DestinationCpu = FsblInstancePtr->ProcessorID; } if (PartitionHeader->UnEncryptedDataWordLength == 0U) { /** * Update the Handoff address only for the first application * of that cpu * This is for XIP image. For other partitions it handoff * address is updated after partition validation */ CpuNo = FsblInstancePtr->HandoffCpuNo; if (XFsbl_CheckHandoffCpu(FsblInstancePtr, DestinationCpu) == XFSBL_SUCCESS) { FsblInstancePtr->HandoffValues[CpuNo].CpuSettings = DestinationCpu | ExecState; FsblInstancePtr->HandoffValues[CpuNo].HandoffAddress = PartitionHeader->DestinationExecutionAddress; FsblInstancePtr->HandoffCpuNo += 1U; } else { /** * * if two partitions has same destination cpu, error can * be triggered here */ } Status = XFSBL_SUCCESS; goto END; } /** * Copy the PL to temporary DDR Address * Copy the PS to Load Address * Copy the PMU firmware to PMU RAM */ DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); LoadAddress = PartitionHeader->DestinationLoadAddress; if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) { #ifdef XFSBL_BS if (LoadAddress == XFSBL_DUMMY_PL_ADDR) { LoadAddress = XFSBL_DDR_TEMP_ADDRESS; } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_PL_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_PL_NOT_ENABLED; goto END; #endif } /** * Get the source(flash offset) address where it needs to copy */ SrcAddress = FsblInstancePtr->ImageOffsetAddress + ((PartitionHeader->DataWordOffset) * XIH_PARTITION_WORD_LENGTH); /** * Length of the partition to be copied */ Length = (PartitionHeader->TotalDataWordLength) * XIH_PARTITION_WORD_LENGTH; /** * When destination device is R5-0/R5-1/R5-L and load address is in TCM * copy to high address of TCM address map * Update the LoadAddress */ Status = XFsbl_GetLoadAddress(DestinationCpu, &LoadAddress, Length); if (XFSBL_SUCCESS != Status) { goto END; } /** * Configure the memory */ XFsbl_ConfigureMemory(RunningCpu, DestinationCpu, LoadAddress, Length); /** * * Do not copy the IVT if FSBL is running in R5-0/R5-L at 0x0 TCM * Update the SrcAddress, LoadAddress and Len based on the * above condition */ #if 1 if (((FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_0) || (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_L)) && ((LoadAddress > XFSBL_R50_HIGH_TCM_START_ADDRESS) && (LoadAddress < XFSBL_R50_HIGH_TCM_START_ADDRESS + XFSBL_IVT_LENGTH))) { /** * Get the length of the IVT area to be * skipped from Load Address */ TcmSkipAddress = LoadAddress/XFSBL_IVT_LENGTH; TcmSkipLength = XFSBL_IVT_LENGTH - TcmSkipAddress; /** * Check if Length is less than SkipLength */ if (TcmSkipLength > Length) { TcmSkipLength = Length; } /** * Copy the Skip length to a local array */ Status = FsblInstancePtr->DeviceOps.DeviceCopy(SrcAddress, (PTRSIZE )TcmVectorArray, TcmSkipLength); if (XFSBL_SUCCESS != Status) { goto END; } SrcAddress += TcmSkipLength; LoadAddress += TcmSkipLength; Length -= TcmSkipLength; } #endif if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PMU) { /* Enable PMU_0 IPI */ XFsbl_Out32(IPI_PMU_0_IER, IPI_PMU_0_IER_PMU_0_MASK); /* Trigger PMU0 IPI in PMU IPI TRIG Reg */ XFsbl_Out32(IPI_PMU_0_TRIG, IPI_PMU_0_TRIG_PMU_0_MASK); /** * Wait until PMU Microblaze goes to sleep state, * before starting firmware download to PMU RAM */ while((XFsbl_In32(PMU_GLOBAL_GLOBAL_CNTRL) & PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK) != PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK ) {;} } /** * Copy the partition to PS_DDR/PL_DDR/TCM */ Status = FsblInstancePtr->DeviceOps.DeviceCopy(SrcAddress, LoadAddress, Length); if (XFSBL_SUCCESS != Status) { goto END; } END: return Status; }
/** * This function checks the power state and reset for the memory type * and release the reset if required * * @param MemoryType is the memory to be checked * - XFSBL_R5_0_TCM * - XFSBL_R5_1_TCM * (to be added) * - XFSBL_R5_0_TCMA * - XFSBL_R5_0_TCMB * - XFSBL_PS_DDR * - XFSBL_PL_DDR * * @return none *****************************************************************************/ static u32 XFsbl_PowerUpMemory(u32 MemoryType) { u32 RegValue; u32 Status = XFSBL_SUCCESS; u32 PwrStateMask; /** * Check the power status of the memory * Power up if required * * Release the reset of the memory if present */ switch (MemoryType) { case XFSBL_R5_0_TCM: { PwrStateMask = PMU_GLOBAL_PWR_STATE_R5_0_MASK | PMU_GLOBAL_PWR_STATE_TCM0A_MASK | PMU_GLOBAL_PWR_STATE_TCM0B_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_0_TCM_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_0_TCM_POWER_UP\r\n"); goto END; } /** * To access TCM, * Release reset to R5 and enable the clk * R5 is under halt state * * If R5 are out of reset and clk is enabled so doing * again is no issue. R5 might be under running state */ /** * Place R5, TCM in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLSPLIT_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void)usleep(0x50U); /** * Release reset to R5-0 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); } break; case XFSBL_R5_1_TCM: { PwrStateMask = PMU_GLOBAL_PWR_STATE_R5_1_MASK | PMU_GLOBAL_PWR_STATE_TCM1A_MASK | PMU_GLOBAL_PWR_STATE_TCM1B_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_1_TCM_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_1_TCM_POWER_UP\r\n"); goto END; } /** * Place R5 in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLSPLIT_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void )usleep(0x50U); /** * Release reset to R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); } break; case XFSBL_R5_L_TCM: { PwrStateMask = PMU_GLOBAL_PWR_STATE_R5_0_MASK | PMU_GLOBAL_PWR_STATE_TCM0A_MASK | PMU_GLOBAL_PWR_STATE_TCM0B_MASK | PMU_GLOBAL_PWR_STATE_TCM1A_MASK | PMU_GLOBAL_PWR_STATE_TCM1B_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_L_TCM_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_L_TCM_POWER_UP\r\n"); goto END; } /** * Place R5 in lock step mode * Combine TCM's */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLCLAMP_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_SLSPLIT_MASK); RegValue |= RPU_RPU_GLBL_CNTL_TCM_COMB_MASK; XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void )usleep(0x50U); /** * Release reset to R5-0,R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); } break; default: /* nothing to do */ break; } END: return Status; }
/** * This function initializes the system using the psu_init() * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_SystemInit(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; #if defined (XPAR_PSU_DDR_0_S_AXI_BASEADDR) && !defined (ARMR5) u32 BlockNum; #endif /** * MIO33 can be used to control power to PL through PMU. * For 1.0 and 2.0 Silicon, a workaround is needed to Powerup PL * before MIO33 is configured. Hence, before MIO configuration, * Powerup PL (but restore isolation). */ if (XGetPSVersion_Info() <= XPS_VERSION_2) { Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_PL_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_PL_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_PL_POWER_UP\r\n"); goto END; } /* For PS only reset, make sure FSBL exits with isolation removed */ if (FsblInstancePtr->ResetReason != PS_ONLY_RESET) { XFsbl_IsolationRestore(PMU_GLOBAL_REQ_ISO_INT_EN_PL_NONPCAP_MASK); } } /** * psu initialization */ Status = (u32)psu_init(); if (XFSBL_SUCCESS != Status) { XFsbl_Printf(DEBUG_GENERAL,"XFSBL_PSU_INIT_FAILED\n\r"); /** * Need to check a way to communicate both FSBL code * and PSU init error code */ Status = XFSBL_PSU_INIT_FAILED + Status; goto END; } #ifdef XFSBL_PERF XTime_GetTime(&(FsblInstancePtr->PerfTime.tFsblStart)); #endif #if defined (XPAR_PSU_DDR_0_S_AXI_BASEADDR) && !defined (ARMR5) /* For A53, mark DDR region as "Memory" as DDR initialization is done */ #ifdef ARMA53_64 /* For A53 64bit*/ for(BlockNum = 0; BlockNum < NUM_BLOCKS_A53_64; BlockNum++) { XFsbl_SetTlbAttributes(BlockNum * BLOCK_SIZE_A53_64, ATTRIB_MEMORY_A53_64); } Xil_DCacheFlush(); #else /* For A53 32bit*/ for(BlockNum = 0; BlockNum < NUM_BLOCKS_A53_32; BlockNum++) { XFsbl_SetTlbAttributes(BlockNum * BLOCK_SIZE_A53_32, ATTRIB_MEMORY_A53_32); } Xil_DCacheFlush(); #endif #endif /** * Forcing the SD card detection signal to bypass the debouncing logic. * This will ensure that SD controller doesn't end up waiting for long, * fixed durations for card to be stable. */ XFsbl_Out32(IOU_SLCR_SD_CDN_CTRL, (IOU_SLCR_SD_CDN_CTRL_SD1_CDN_CTRL_MASK | IOU_SLCR_SD_CDN_CTRL_SD0_CDN_CTRL_MASK)); /** * DDR Check if present */ /** * Poweroff the unused blocks as per PSU */ END: return Status; }
/** * This function does ECC Initialization of DDR memory * * @param none * * @return * - XFSBL_SUCCESS for successful ECC Initialization * - or ECC is not enabled for DDR * - errors as mentioned in xfsbl_error.h * *****************************************************************************/ u32 XFsbl_DdrEccInit(void) { u32 Status = XFSBL_SUCCESS; #if XPAR_PSU_DDRC_0_HAS_ECC u32 LengthBytes = XFSBL_PS_DDR_END_ADDRESS - XFSBL_PS_DDR_INIT_START_ADDRESS; u32 Length = 0; u32 DestAddr = XFSBL_PS_DDR_INIT_START_ADDRESS; u32 RegVal; XFsbl_Printf(DEBUG_GENERAL,"\n\rInitializing DDR ECC\n\r"); Xil_DCacheDisable(); while (LengthBytes > 0) { if (LengthBytes > GDMA_TRANSFER_MAX_LEN) { Length = GDMA_TRANSFER_MAX_LEN; } else { Length = LengthBytes; } /* Wait until the DMA is in idle state */ do { RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_STATUS); RegVal &= GDMA_CH0_ZDMA_CH_STATUS_STATE_MASK; } while ((RegVal != GDMA_CH0_ZDMA_CH_STATUS_STATE_DONE) && (RegVal != GDMA_CH0_ZDMA_CH_STATUS_STATE_ERR)); /* Enable Simple (Write Only) Mode */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_CTRL0); RegVal &= (GDMA_CH0_ZDMA_CH_CTRL0_POINT_TYPE_MASK | GDMA_CH0_ZDMA_CH_CTRL0_MODE_MASK); RegVal |= (GDMA_CH0_ZDMA_CH_CTRL0_POINT_TYPE_NORMAL | GDMA_CH0_ZDMA_CH_CTRL0_MODE_WR_ONLY); XFsbl_Out32(GDMA_CH0_ZDMA_CH_CTRL0, RegVal); /* Fill in the data to be written */ XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD0, XFSBL_ECC_INIT_VAL_WORD); XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD1, XFSBL_ECC_INIT_VAL_WORD); XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD2, XFSBL_ECC_INIT_VAL_WORD); XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD3, XFSBL_ECC_INIT_VAL_WORD); /* Write Destination Address */ XFsbl_Out32(GDMA_CH0_ZDMA_CH_DST_DSCR_WORD0, DestAddr); /* Size to be Transferred (for write-only mode, only dest is needed)*/ XFsbl_Out32(GDMA_CH0_ZDMA_CH_DST_DSCR_WORD2, Length); /* DMA Enable */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_CTRL2); RegVal |= GDMA_CH0_ZDMA_CH_CTRL2_EN_MASK; XFsbl_Out32(GDMA_CH0_ZDMA_CH_CTRL2, RegVal); /* Check the status of the transfer by polling on DMA Done */ do { RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_ISR); RegVal &= GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK; } while (RegVal != GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK); /* Clear DMA status */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_ISR); RegVal |= GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK; XFsbl_Out32(GDMA_CH0_ZDMA_CH_ISR, GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK); /* Read the channel status for errors */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_STATUS); if (RegVal == GDMA_CH0_ZDMA_CH_STATUS_STATE_ERR) { Status = XFSBL_ERROR_DDR_ECC_INIT; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_DDR_ECC_INIT\n\r"); Xil_DCacheEnable(); goto END; } LengthBytes -= Length; DestAddr += Length; } Xil_DCacheEnable(); END: #endif return Status; }
/** * * @param * * @return * * @note * * *****************************************************************************/ static void XFsbl_FiqHandler (void) { XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_FIQ_EXCEPTION\n\r"); XFsbl_ErrorLockDown(XFSBL_ERROR_FIQ_EXCEPTION); }
/** * This function initializes the primary boot device * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_PrimaryBootDeviceInit(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; u32 BootMode=0U; /** * Read Boot Mode register and update the value */ BootMode = XFsbl_In32(CRL_APB_BOOT_MODE_USER) & CRL_APB_BOOT_MODE_USER_BOOT_MODE_MASK; FsblInstancePtr->PrimaryBootDevice = BootMode; /** * Enable drivers only if they are device boot modes * Not required for JTAG modes */ if ( (BootMode == XFSBL_QSPI24_BOOT_MODE) || (BootMode == XFSBL_QSPI32_BOOT_MODE) || (BootMode == XFSBL_NAND_BOOT_MODE) || (BootMode == XFSBL_SD0_BOOT_MODE) || (BootMode == XFSBL_EMMC_BOOT_MODE) || (BootMode == XFSBL_SD1_BOOT_MODE) || (BootMode == XFSBL_SD1_LS_BOOT_MODE)) { /** * Initialize the WDT and CSU drivers */ #ifdef XFSBL_WDT_PRESENT Status = XFsbl_InitWdt(); if (XFSBL_SUCCESS != Status) { XFsbl_Printf(DEBUG_GENERAL,"WDT initialization failed \n\r"); goto END; } #endif /* Initialize CSUDMA driver */ Status = XFsbl_CsuDmaInit(); if (XFSBL_SUCCESS != Status) { goto END; } } switch(BootMode) { /** * For JTAG boot mode, it will be in while loop */ case XFSBL_JTAG_BOOT_MODE: { XFsbl_Printf(DEBUG_GENERAL,"In JTAG Boot Mode \n\r"); Status = XFSBL_STATUS_JTAG; } break; case XFSBL_QSPI24_BOOT_MODE: { XFsbl_Printf(DEBUG_GENERAL,"QSPI 24bit Boot Mode \n\r"); #ifdef XFSBL_QSPI /** * Update the deviceops structure with necessary values */ FsblInstancePtr->DeviceOps.DeviceInit = XFsbl_Qspi24Init; FsblInstancePtr->DeviceOps.DeviceCopy = XFsbl_Qspi24Copy; FsblInstancePtr->DeviceOps.DeviceRelease = XFsbl_Qspi24Release; #else /** * This bootmode is not supported in this release */ XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_BOOT_MODE\n\r"); Status = XFSBL_ERROR_UNSUPPORTED_BOOT_MODE; #endif } break; case XFSBL_QSPI32_BOOT_MODE: { XFsbl_Printf(DEBUG_GENERAL,"QSPI 32 bit Boot Mode \n\r"); #ifdef XFSBL_QSPI /** * Update the deviceops structure with necessary values * */ FsblInstancePtr->DeviceOps.DeviceInit = XFsbl_Qspi32Init; FsblInstancePtr->DeviceOps.DeviceCopy = XFsbl_Qspi32Copy; FsblInstancePtr->DeviceOps.DeviceRelease = XFsbl_Qspi32Release; #else /** * This bootmode is not supported in this release */ XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_BOOT_MODE\n\r"); Status = XFSBL_ERROR_UNSUPPORTED_BOOT_MODE; #endif } break; case XFSBL_NAND_BOOT_MODE: { XFsbl_Printf(DEBUG_GENERAL,"NAND Boot Mode \n\r"); #ifdef XFSBL_NAND /** * Update the deviceops structure with necessary values * */ FsblInstancePtr->DeviceOps.DeviceInit = XFsbl_NandInit; FsblInstancePtr->DeviceOps.DeviceCopy = XFsbl_NandCopy; FsblInstancePtr->DeviceOps.DeviceRelease = XFsbl_NandRelease; #else /** * This bootmode is not supported in this release */ XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_BOOT_MODE\n\r"); Status = XFSBL_ERROR_UNSUPPORTED_BOOT_MODE; #endif } break; case XFSBL_SD0_BOOT_MODE: case XFSBL_EMMC_BOOT_MODE: { if (BootMode == XFSBL_SD0_BOOT_MODE) { XFsbl_Printf(DEBUG_GENERAL,"SD0 Boot Mode \n\r"); } else { XFsbl_Printf(DEBUG_GENERAL,"eMMC Boot Mode \n\r"); } #ifdef XFSBL_SD_0 /** * Update the deviceops structure with necessary values */ FsblInstancePtr->DeviceOps.DeviceInit = XFsbl_SdInit; FsblInstancePtr->DeviceOps.DeviceCopy = XFsbl_SdCopy; FsblInstancePtr->DeviceOps.DeviceRelease = XFsbl_SdRelease; #else /** * This bootmode is not supported in this release */ XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_BOOT_MODE\n\r"); Status = XFSBL_ERROR_UNSUPPORTED_BOOT_MODE; #endif } break; case XFSBL_SD1_BOOT_MODE: case XFSBL_SD1_LS_BOOT_MODE: { if (BootMode == XFSBL_SD1_BOOT_MODE) { XFsbl_Printf(DEBUG_GENERAL, "SD1 Boot Mode \n\r"); } else { XFsbl_Printf(DEBUG_GENERAL, "SD1 with level shifter Boot Mode \n\r"); } #ifdef XFSBL_SD_1 /** * Update the deviceops structure with necessary values */ FsblInstancePtr->DeviceOps.DeviceInit = XFsbl_SdInit; FsblInstancePtr->DeviceOps.DeviceCopy = XFsbl_SdCopy; FsblInstancePtr->DeviceOps.DeviceRelease = XFsbl_SdRelease; #else /** * This bootmode is not supported in this release */ XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_BOOT_MODE\n\r"); Status = XFSBL_ERROR_UNSUPPORTED_BOOT_MODE; #endif } break; default: { XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_BOOT_MODE\n\r"); Status = XFSBL_ERROR_UNSUPPORTED_BOOT_MODE; } break; } /** * In case of error or Jtag boot, goto end */ if (XFSBL_SUCCESS != Status) { goto END; } /** * Initialize the Device Driver */ Status = FsblInstancePtr->DeviceOps.DeviceInit(BootMode); if (XFSBL_SUCCESS != Status) { goto END; } END: return Status; }
/** * This function initializes the processor and updates the cluster id * which indicates CPU on which fsbl is running * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_ProcessorInit(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; //u64 ClusterId=0U; PTRSIZE ClusterId=0U; u32 RegValue; u32 Index=0U; /** * Read the cluster ID and Update the Processor ID * Initialize the processor settings that are not done in * BSP startup code */ #ifdef XFSBL_A53 ClusterId = mfcp(MPIDR_EL1); #else ClusterId = mfcp(XREG_CP15_MULTI_PROC_AFFINITY); #endif XFsbl_Printf(DEBUG_INFO,"Cluster ID 0x%0lx\n\r", ClusterId); if (XFSBL_PLATFORM == XFSBL_PLATFORM_QEMU) { /** * Remmaping for R5 in QEMU */ if (ClusterId == 0x80000004U) { ClusterId = 0xC0000100U; } else if (ClusterId == 0x80000005U) { /* this corresponds to R5-1 */ Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } else { /* For MISRA C compliance */ } } /* store the processor ID based on the cluster ID */ if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_A53_PROCESSOR) { XFsbl_Printf(DEBUG_GENERAL,"Running on A53-0 "); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_A53_0; #ifdef __aarch64__ /* Running on A53 64-bit */ XFsbl_Printf(DEBUG_GENERAL,"(64-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA64; #else /* Running on A53 32-bit */ XFsbl_Printf(DEBUG_GENERAL,"(32-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA32; #endif } else if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_R5_PROCESSOR) { /* A53ExecState is not valid for R5 */ FsblInstancePtr->A53ExecState = XIH_INVALID_EXEC_ST; RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); if ((RegValue & RPU_RPU_GLBL_CNTL_SLSPLIT_MASK) == 0U) { XFsbl_Printf(DEBUG_GENERAL, "Running on R5 Processor in Lockstep \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_L; } else { XFsbl_Printf(DEBUG_GENERAL, "Running on R5-0 Processor \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_0; } /** * Update the Vector locations in R5 TCM */ while (Index<32U) { XFsbl_Out32(Index, 0U); XFsbl_Out32(Index, XFSBL_R5_VECTOR_VALUE); Index += 4; } } else { Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } /** * Register the exception handlers */ XFsbl_RegisterHandlers(); END: return Status; }
/** This is the FSBL main function and is implemented stage wise. * * @param None * * @return None * *****************************************************************************/ int main(void ) { /** * Local variables */ u32 FsblStatus = XFSBL_SUCCESS; u32 FsblStage = XFSBL_STAGE1; u32 PartitionNum=0U; u32 EarlyHandoff = FALSE; /** * Initialize globals. */ FsblInstancePtr.ErrorCode = FsblStatus; while (1) { switch (FsblStage) { case XFSBL_STAGE1: { /** * Initialize the system */ XFsbl_CfgInitialize(&FsblInstancePtr); FsblStatus = XFsbl_Initialize(&FsblInstancePtr); if (XFSBL_SUCCESS != FsblStatus) { FsblStatus += XFSBL_ERROR_STAGE_1; FsblStage = XFSBL_STAGE_ERR; } else { /** * * Include the code for FSBL time measurements * Initialize the global timer and get the value */ FsblStage = XFSBL_STAGE2; } }break; case XFSBL_STAGE2: { XFsbl_Printf(DEBUG_INFO, "================= In Stage 2 ============ \n\r"); /** * Primary Device * Secondary boot device * DeviceOps * image header * partition header */ FsblStatus = XFsbl_BootDeviceInitAndValidate(&FsblInstancePtr); if ( (XFSBL_SUCCESS != FsblStatus) && (XFSBL_STATUS_JTAG != FsblStatus) ) { XFsbl_Printf(DEBUG_GENERAL,"Boot Device " "Initialization failed 0x%0lx\n\r", FsblStatus); FsblStatus += XFSBL_ERROR_STAGE_2; FsblStage = XFSBL_STAGE_ERR; } else if (XFSBL_STATUS_JTAG == FsblStatus) { /** * This is JTAG boot mode, go to the handoff stage */ FsblStage = XFSBL_STAGE4; } else { XFsbl_Printf(DEBUG_INFO,"Initialization Success \n\r"); /** * Start the partition loading from 1 * 0th partition will be FSBL */ PartitionNum = 0x1U; FsblStage = XFSBL_STAGE3; } } break; case XFSBL_STAGE3: { XFsbl_Printf(DEBUG_INFO, "======= In Stage 3, Partition No:%d ======= \n\r", PartitionNum); /** * Load the partitions * image header * partition header * partition parameters */ FsblStatus = XFsbl_PartitionLoad(&FsblInstancePtr, PartitionNum); if (XFSBL_SUCCESS != FsblStatus) { /** * Error */ XFsbl_Printf(DEBUG_GENERAL,"Partition %d Load Failed, 0x%0lx\n\r", PartitionNum, FsblStatus); FsblStatus += XFSBL_ERROR_STAGE_3; FsblStage = XFSBL_STAGE_ERR; } else { XFsbl_Printf(DEBUG_INFO,"Partition %d Load Success \n\r", PartitionNum); /** * Check loading all partitions is completed */ FsblStatus = XFsbl_CheckEarlyHandoff(&FsblInstancePtr, PartitionNum); if (PartitionNum < (FsblInstancePtr.ImageHeader.ImageHeaderTable.NoOfPartitions-1U)) { if (TRUE == FsblStatus) { EarlyHandoff = TRUE; FsblStage = XFSBL_STAGE4; } else { /** * No need to change the Fsbl Stage * Load the next partition */ PartitionNum++; } } else { /** * No more partitions present, go to handoff stage */ XFsbl_Printf(DEBUG_INFO,"All Partitions Loaded \n\r"); FsblStage = XFSBL_STAGE4; EarlyHandoff = FsblStatus; } } /* End of else loop for Load Success */ } break; case XFSBL_STAGE4: { XFsbl_Printf(DEBUG_INFO, "================= In Stage 4 ============ \n\r"); /** * Handoff to the applications * Handoff address * xip * ps7 post config */ FsblStatus = XFsbl_Handoff(&FsblInstancePtr, PartitionNum, EarlyHandoff); if (XFSBL_STATUS_CONTINUE_PARTITION_LOAD == FsblStatus) { XFsbl_Printf(DEBUG_INFO,"Early handoff to a application complete \n\r"); XFsbl_Printf(DEBUG_INFO,"Continuing to load remaining partitions \n\r"); PartitionNum++; FsblStage = XFSBL_STAGE3; } else if (XFSBL_STATUS_CONTINUE_OTHER_HANDOFF == FsblStatus) { XFsbl_Printf(DEBUG_INFO,"Early handoff to a application complete \n\r"); XFsbl_Printf(DEBUG_INFO,"Continuing handoff to other applications, if present \n\r"); EarlyHandoff = FALSE; } else if (XFSBL_SUCCESS != FsblStatus) { /** * Error */ XFsbl_Printf(DEBUG_GENERAL,"Handoff Failed 0x%0lx\n\r", FsblStatus); FsblStatus += XFSBL_ERROR_STAGE_4; FsblStage = XFSBL_STAGE_ERR; } else { /** * we should never be here */ FsblStage = XFSBL_STAGE_DEFAULT; } } break; case XFSBL_STAGE_ERR: { XFsbl_Printf(DEBUG_INFO, "================= In Stage Err ============ \n\r"); XFsbl_ErrorLockDown(FsblStatus); /** * we should never be here */ FsblStage = XFSBL_STAGE_DEFAULT; }break; case XFSBL_STAGE_DEFAULT: default: { /** * we should never be here */ XFsbl_Printf(DEBUG_GENERAL,"In default stage: " "We should never be here \n\r"); /** * Exit FSBL */ XFsbl_HandoffExit(0U, XFSBL_NO_HANDOFFEXIT); }break; } /* End of switch(FsblStage) */ } /* End of while(1) */ /** * We should never be here */ XFsbl_Printf(DEBUG_GENERAL,"In default stage: " "We should never be here \n\r"); /** * Exit FSBL */ XFsbl_HandoffExit(0U, XFSBL_NO_HANDOFFEXIT); return 0; }
/** * Configure the RSA and SHA for the SPK * Signature verification. * If SPK Signature verification fails * then return unique error code saying * XFSBL_STAGE3_SPK_SIGN_VERIF_ERROR. * * @param * * @return * ******************************************************************************/ u32 XFsbl_SpkVer(XFsblPs *FsblInstancePtr , u64 AcOffset, u32 HashLen, u32 PartitionNum) { u8 SpkHash[XFSBL_HASH_TYPE_SHA3] __attribute__ ((aligned (4))); u8 * PpkModular = (u8 *)NULL; u8 * PpkModularEx = (u8 *)NULL; u32 PpkExp = 0; u8 * AcPtr = (u8*) (PTRSIZE) AcOffset; u32 Status = XFSBL_SUCCESS; void * ShaCtx = (void * )NULL; u8 XFsbl_RsaSha3Array[512]; #ifdef XFSBL_SHA2 sha2_context ShaCtxObj; ShaCtx = &ShaCtxObj; #endif #ifndef XFSBL_PS_DDR XFsblPs_PartitionHeader * PartitionHeader; u32 DestinationDevice = 0U; PartitionHeader = &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]; DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) { /* * If it is DDR less system, bitstream chunk containing * Authentication Certificate has to be read from boot device */ if(XFSBL_SUCCESS != FsblInstancePtr->DeviceOps.DeviceCopy( (INTPTR)AcPtr, (PTRSIZE)ReadBuffer, XFSBL_AUTH_CERT_MIN_SIZE)) { XFsbl_Printf(DEBUG_GENERAL, "XFsbl_SpkVer: Device to OCM copy of certificate failed \r\n"); Status = XFSBL_ERROR_SPK_RSA_DECRYPT; goto END; } /* Repoint Auth. cert. pointer to OCM buffer beginning*/ AcPtr = ReadBuffer; } #endif /* Re-initialize CSU DMA. This is a workaround and need to be removed */ Status = XFsbl_CsuDmaInit(); if (XST_SUCCESS != Status) { goto END; } (void)XFsbl_ShaStart(ShaCtx, HashLen); /* Hash the PPK + SPK choice */ XFsbl_ShaUpdate(ShaCtx, AcPtr, 8, HashLen); /* Set PPK pointer */ AcPtr += XFSBL_RSA_AC_ALIGN; PpkModular = (u8 *)AcPtr; AcPtr += XFSBL_PPK_MOD_SIZE; PpkModularEx = (u8 *)AcPtr; AcPtr += XFSBL_PPK_MOD_EXT_SIZE; PpkExp = *((u32 *)AcPtr); AcPtr += XFSBL_RSA_AC_ALIGN; XFsbl_Printf(DEBUG_DETAILED, "XFsbl_SpkVer: Ppk Mod %0x, Ppk Mod Ex %0x, Ppk Exp %0x\r\n", PpkModular, PpkModularEx, PpkExp); /* Calculate SPK + Auth header Hash */ XFsbl_ShaUpdate(ShaCtx, (u8 *)AcPtr, XFSBL_SPK_SIZE, HashLen); XFsbl_ShaFinish(ShaCtx, (u8 *)SpkHash, HashLen); /* Set SPK Signature pointer */ AcPtr += XFSBL_SPK_SIZE; XSecure_RsaInitialize(&SecureRsa, PpkModular, PpkModularEx, (u8 *)&PpkExp); /* Decrypt SPK Signature */ if(XFSBL_SUCCESS != XSecure_RsaDecrypt(&SecureRsa, AcPtr, XFsbl_RsaSha3Array)) { XFsbl_Printf(DEBUG_GENERAL, "XFsbl_SpkVer: XFSBL_ERROR_SPK_RSA_DECRYPT\r\n"); Status = XFSBL_ERROR_SPK_RSA_DECRYPT; goto END; } /* Authenticate SPK Signature */ if(XFSBL_SUCCESS != XSecure_RsaSignVerification(XFsbl_RsaSha3Array, SpkHash, HashLen)) { XFsbl_PrintArray(DEBUG_INFO, SpkHash, HashLen, "Calculated SPK Hash"); XFsbl_PrintArray(DEBUG_INFO, XFsbl_RsaSha3Array, 512, "RSA decrypted Hash"); XFsbl_Printf(DEBUG_GENERAL, "XFsbl_SpkVer: XFSBL_ERROR_SPK_SIGNATURE\r\n"); Status = XFSBL_ERROR_SPK_SIGNATURE; } END: return Status; }
/** * Configure the RSA and SHA for the * Boot Header Signature verification. * If Boot Header Signature verification * fails then return unique error code saying * XFSBL_STAGE3_BOOT_HDR_SIGN_VERIF_ERROR. * * @param * * @return * ******************************************************************************/ u32 XFsbl_PartitionSignVer(XFsblPs *FsblInstancePtr, u64 PartitionOffset, u32 PartitionLen, u64 AcOffset, u32 HashLen, u32 PartitionNum) { u8 PartitionHash[XFSBL_HASH_TYPE_SHA3] __attribute__ ((aligned (4))); u8 * SpkModular = (u8 *)NULL; u8 * SpkModularEx = (u8 *)NULL; u32 SpkExp = 0; u8 * AcPtr = (u8*)(PTRSIZE) AcOffset; u32 Status = XFSBL_SUCCESS; u32 HashDataLen=0U; #ifndef XFSBL_PS_DDR void * ShaCtx = (void * )NULL; #endif u8 XFsbl_RsaSha3Array[512]; #ifdef XFSBL_SHA2 sha2_context ShaCtxObj; ShaCtx = &ShaCtxObj; #endif XFsbl_Printf(DEBUG_INFO, "Doing Partition Sign verification\r\n"); /** * hash to be calculated will be total length with AC minus * signature size */ HashDataLen = PartitionLen - XFSBL_FSBL_SIG_SIZE; /* Calculate Partition Hash */ #ifndef XFSBL_PS_DDR XFsblPs_PartitionHeader * PartitionHeader; u32 DestinationDevice = 0U; PartitionHeader = &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]; DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) { /** * bitstream partion in DDR less system, Chunk by chunk copy * into OCM and update SHA module */ u32 NumChunks = 0U; u32 RemainingBytes = 0U; u32 Index = 0U; u32 StartAddrByte = PartitionOffset; NumChunks = HashDataLen / READ_BUFFER_SIZE; RemainingBytes = (HashDataLen % READ_BUFFER_SIZE); /* Start the SHA engine */ (void)XFsbl_ShaStart(ShaCtx, HashLen); XFsbl_Printf(DEBUG_INFO, "XFsbl_PartitionVer: NumChunks :%0d, RemainingBytes : %0d \r\n", NumChunks, RemainingBytes); for(Index = 0; Index < NumChunks; Index++) { if(XFSBL_SUCCESS !=FsblInstancePtr->DeviceOps.DeviceCopy( StartAddrByte, (PTRSIZE)ReadBuffer, READ_BUFFER_SIZE)) { XFsbl_Printf(DEBUG_GENERAL, "XFsblPartitionVer: Device " "to OCM copy of partition failed \r\n"); XFsbl_Printf(DEBUG_GENERAL, "XFsbl_PartitionVer: XFSBL_ERROR_PART_RSA_DECRYPT\r\n"); Status = XFSBL_ERROR_PART_RSA_DECRYPT; goto END; } XFsbl_ShaUpdate(ShaCtx, (u8 *)ReadBuffer, READ_BUFFER_SIZE, HashLen); StartAddrByte += READ_BUFFER_SIZE; } /* Send the residual bytes if Size is not buffer size multiple */ if(RemainingBytes != 0) { if(XFSBL_SUCCESS!=FsblInstancePtr->DeviceOps.DeviceCopy( StartAddrByte, (PTRSIZE)ReadBuffer, RemainingBytes)) { XFsbl_Printf(DEBUG_GENERAL, "XFsbl_PartitionVer: XFSBL_ERROR_PART_RSA_DECRYPT\r\n"); Status = XFSBL_ERROR_PART_RSA_DECRYPT; goto END; } XFsbl_ShaUpdate(ShaCtx, (u8 *)ReadBuffer, RemainingBytes, HashLen); } XFsbl_ShaFinish(ShaCtx, PartitionHash, HashLen); /** * Copy Auth. Certificate to OCM buffer location * Assign AcPtr to OCM buffer location */ if(XFSBL_SUCCESS != FsblInstancePtr->DeviceOps.DeviceCopy( (u32)(INTPTR)AcPtr, (PTRSIZE)ReadBuffer, XFSBL_AUTH_CERT_MIN_SIZE)) { XFsbl_Printf(DEBUG_GENERAL, "XFsbl_PartitionVer: Flash to OCM copy failed \r\n"); Status = XFSBL_ERROR_SPK_RSA_DECRYPT; goto END; } /* Repoint Auth. Certificate pointer to start of OCM buffer */ AcPtr = ReadBuffer; } else { XFsbl_Printf(DEBUG_INFO, "partver: sha calc. " "for non bs DDR less part \r\n"); /* SHA calculation for non-bitstream, DDR less partitions */ XFsbl_ShaDigest((const u8 *)(PTRSIZE)PartitionOffset, HashDataLen, PartitionHash, HashLen); } #else /* SHA calculation in DDRful systems */ XFsbl_ShaDigest((const u8 *)(PTRSIZE)PartitionOffset, HashDataLen, PartitionHash, HashLen); #endif /* Set SPK pointer */ AcPtr += (XFSBL_RSA_AC_ALIGN + XFSBL_PPK_SIZE); SpkModular = (u8 *)AcPtr; AcPtr += XFSBL_SPK_MOD_SIZE; SpkModularEx = (u8 *)AcPtr; AcPtr += XFSBL_SPK_MOD_EXT_SIZE; SpkExp = *((u32 *)AcPtr); AcPtr += XFSBL_RSA_AC_ALIGN; /* Increment by SPK Signature pointer */ AcPtr += XFSBL_SPK_SIG_SIZE; /* Increment by BHDR Signature pointer */ AcPtr += XFSBL_BHDR_SIG_SIZE; XFsbl_Printf(DEBUG_DETAILED, "XFsbl_PartVer: Spk Mod %0x, Spk Mod Ex %0x, Spk Exp %0x\r\n", SpkModular, SpkModularEx, SpkExp); XFsbl_Printf(DEBUG_INFO, "Partition Verification done \r\n"); XSecure_RsaInitialize(&SecureRsa, SpkModular, SpkModularEx, (u8 *)&SpkExp); /* Decrypt Partition Signature. */ if(XFSBL_SUCCESS != XSecure_RsaDecrypt(&SecureRsa, AcPtr, XFsbl_RsaSha3Array)) { XFsbl_Printf(DEBUG_GENERAL, "XFsbl_SpkVer: XFSBL_ERROR_PART_RSA_DECRYPT\r\n"); Status = XFSBL_ERROR_PART_RSA_DECRYPT; goto END; } /* Authenticate Partition Signature */ if(XFSBL_SUCCESS != XSecure_RsaSignVerification(XFsbl_RsaSha3Array, PartitionHash, HashLen)) { XFsbl_PrintArray(DEBUG_INFO, PartitionHash, HashLen, "Calculated Partition Hash"); XFsbl_PrintArray(DEBUG_INFO, XFsbl_RsaSha3Array, 512, "RSA decrypted Hash"); XFsbl_Printf(DEBUG_GENERAL, "XFsbl_PartVer: XFSBL_ERROR_PART_SIGNATURE\r\n"); Status = XFSBL_ERROR_PART_SIGNATURE; goto END; } END: return Status; }
/** * * @param * * @return * * @note * *****************************************************************************/ static void XFsbl_PreFetchAbortHandler (void) { XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_PREFETCH_ABORT_EXCEPTION\n\r"); XFsbl_ErrorLockDown(XFSBL_ERROR_PREFETCH_ABORT_EXCEPTION); }
/** * * @param * * @return * * @note * * *****************************************************************************/ static void XFsbl_DataAbortHandler (void) { XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_DATA_ABORT_EXCEPTION\n\r"); XFsbl_ErrorLockDown(XFSBL_ERROR_DATA_ABORT_EXCEPTION); }
/** * This function validates the image header * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_ValidateHeader(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; u32 MultiBootOffset=0U; u32 BootHdrAttrb=0U; u32 FlashImageOffsetAddress=0U; u32 EfuseCtrl=0U; /** * Read the Multiboot Register */ MultiBootOffset = XFsbl_In32(CSU_CSU_MULTI_BOOT); XFsbl_Printf(DEBUG_INFO,"Multiboot Reg : 0x%0lx \n\r", MultiBootOffset); /** * Calculate the Flash Offset Address * For file system based devices, Flash Offset Address should be 0 always */ if ((FsblInstancePtr->PrimaryBootDevice == XFSBL_SD0_BOOT_MODE) || (FsblInstancePtr->PrimaryBootDevice == XFSBL_EMMC_BOOT_MODE) || (FsblInstancePtr->PrimaryBootDevice == XFSBL_SD1_BOOT_MODE) || (FsblInstancePtr->PrimaryBootDevice == XFSBL_SD1_LS_BOOT_MODE)) { FsblInstancePtr->ImageOffsetAddress = 0x0U; } else { FsblInstancePtr->ImageOffsetAddress = MultiBootOffset * XFSBL_IMAGE_SEARCH_OFFSET; } FlashImageOffsetAddress = FsblInstancePtr->ImageOffsetAddress; /** * Read Boot Image attributes */ Status = FsblInstancePtr->DeviceOps.DeviceCopy(FlashImageOffsetAddress + XIH_BH_IMAGE_ATTRB_OFFSET, (PTRSIZE ) &BootHdrAttrb, XIH_FIELD_LEN); if (XFSBL_SUCCESS != Status) { XFsbl_Printf(DEBUG_GENERAL,"Device Copy Failed \n\r"); goto END; } FsblInstancePtr->BootHdrAttributes = BootHdrAttrb; /** * Read Image Header and validate Image Header Table */ Status = XFsbl_ReadImageHeader(&FsblInstancePtr->ImageHeader, &FsblInstancePtr->DeviceOps, FlashImageOffsetAddress, FsblInstancePtr->ProcessorID); if (XFSBL_SUCCESS != Status) { goto END; } /** * Read Efuse bit and check Boot Header for Authentication */ EfuseCtrl = XFsbl_In32(EFUSE_SEC_CTRL); if (((EfuseCtrl & EFUSE_SEC_CTRL_RSA_EN_MASK) != 0) || ((BootHdrAttrb & XIH_BH_IMAGE_ATTRB_RSA_MASK) == XIH_BH_IMAGE_ATTRB_RSA_MASK)) { XFsbl_Printf(DEBUG_INFO,"Authentication Enabled\r\n"); #ifdef XFSBL_RSA /** * Authenticate the image header */ #else XFsbl_Printf(DEBUG_GENERAL,"Rsa code not Enabled\r\n"); Status = XFSBL_ERROR_RSA_NOT_ENABLED; goto END; #endif } END: return Status; }
/** * This function is used to copy the data from QSPI flash to destination * address * * @param SrcAddress is the address of the QSPI flash where copy should * start from * * @param DestAddress is the address of the destination where it * should copy to * * @param Length Length of the bytes to be copied * * @return * - XFSBL_SUCCESS for successful copy * - errors as mentioned in xfsbl_error.h * *****************************************************************************/ u32 XFsbl_Qspi32Copy(u32 SrcAddress, PTRSIZE DestAddress, u32 Length) { u32 Status = XFSBL_SUCCESS; u32 QspiAddr=0; u32 RemainingBytes=0; u32 TransferBytes=0; u32 DiscardByteCnt; XFsbl_Printf(DEBUG_INFO,"QSPI Reading Src 0x%0lx, Dest %0lx, Length %0lx\r\n", SrcAddress, DestAddress, Length); /** * Check the read length with Qspi flash size */ if ((SrcAddress + Length) > QspiFlashSize) { Status = XFSBL_ERROR_QSPI_LENGTH; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_LENGTH\r\n"); goto END; } /** * Update no of bytes to be copied */ RemainingBytes = Length; while(RemainingBytes > 0) { if (RemainingBytes > DMA_DATA_TRAN_SIZE) { TransferBytes = DMA_DATA_TRAN_SIZE; } else { TransferBytes = RemainingBytes; } /** * Translate address based on type of connection * If stacked assert the slave select based on address */ QspiAddr = XFsbl_GetQspiAddr((u32 )SrcAddress); XFsbl_Printf(DEBUG_INFO,"."); XFsbl_Printf(DEBUG_DETAILED, "QSPI Read Src 0x%0lx, Dest %0lx, Length %0lx\r\n", QspiAddr, DestAddress, TransferBytes); /** * Setup the read command with the specified address and data for the * Flash */ WriteBuffer[COMMAND_OFFSET] = ReadCommand; WriteBuffer[ADDRESS_1_OFFSET] = (u8)((QspiAddr & 0xFF000000) >> 24); WriteBuffer[ADDRESS_2_OFFSET] = (u8)((QspiAddr & 0xFF0000) >> 16); WriteBuffer[ADDRESS_3_OFFSET] = (u8)((QspiAddr & 0xFF00) >> 8); WriteBuffer[ADDRESS_4_OFFSET] = (u8)(QspiAddr & 0xFF); DiscardByteCnt = 5; FlashMsg[0].TxBfrPtr = WriteBuffer; FlashMsg[0].RxBfrPtr = NULL; FlashMsg[0].ByteCount = DiscardByteCnt; FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; /* * It is recommended to have a separate entry for dummy */ if ((ReadCommand == FAST_READ_CMD_32BIT) || (ReadCommand == DUAL_READ_CMD_32BIT) || (ReadCommand == QUAD_READ_CMD_32BIT)) { /* Update Dummy cycles as per flash specs for QUAD IO */ /* * It is recommended that Bus width value during dummy * phase should be same as data phase */ if (ReadCommand == FAST_READ_CMD_32BIT) { FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; } if (ReadCommand == DUAL_READ_CMD_32BIT) { FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; } if (ReadCommand == QUAD_READ_CMD_32BIT) { FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; } FlashMsg[1].TxBfrPtr = NULL; FlashMsg[1].RxBfrPtr = NULL; FlashMsg[1].ByteCount = DUMMY_CLOCKS; FlashMsg[1].Flags = 0; } if (ReadCommand == FAST_READ_CMD_32BIT) { FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI; } if (ReadCommand == DUAL_READ_CMD_32BIT) { FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; } if (ReadCommand == QUAD_READ_CMD_32BIT) { FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; } FlashMsg[2].TxBfrPtr = NULL; FlashMsg[2].RxBfrPtr = (u8 *)DestAddress; FlashMsg[2].ByteCount = TransferBytes; FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX; if(QspiPsuInstancePtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ FlashMsg[2].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; } /** * Send the read command to the Flash to read the specified number * of bytes from the Flash, send the read command and address and * receive the specified number of bytes of data in the data buffer */ Status = XQspiPsu_PolledTransfer(QspiPsuInstancePtr, FlashMsg, 3); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_QSPI_READ; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n"); goto END; } /** * Update the variables */ RemainingBytes -= TransferBytes; DestAddress += TransferBytes; SrcAddress += TransferBytes; } END: return Status; }