/***************************************************************************//** * @file * @brief Application interface to the bootloader. ******************************************************************************* * # License * Copyright 2021 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * The licensor of this software is Silicon Laboratories Inc. Your use of this * software is governed by the terms of Silicon Labs Master Software License * Agreement (MSLA) available at * www.silabs.com/about-us/legal/master-software-license-agreement. This * software is distributed to you in Source Code format and is governed by the * sections of the MSLA applicable to Source Code. * ******************************************************************************/ #include "btl_interface.h" #include "em_core.h" #include "btl_interface_cfg.h" #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #endif #if defined(SL_COMPONENT_CATALOG_PRESENT) #include "sl_component_catalog.h" #endif #if defined(__GNUC__) extern uint32_t __ResetReasonStart__; #elif defined(__ICCARM__) #pragma section = "BOOTLOADER_RESET_REASON" #endif #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) // ----------------------------------------------------------------------------- // Configurations #if ((!defined(BOOTLOADER_DISABLE_NVM3_FAULT_HANDLING) \ || (defined(BOOTLOADER_DISABLE_NVM3_FAULT_HANDLING) \ && (BOOTLOADER_DISABLE_NVM3_FAULT_HANDLING == 0))) && defined(SL_CATALOG_NVM3_PRESENT)) #define BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING #endif // BOOTLOADER_DISABLE_NVM3_FAULT_HANDLING && SL_CATALOG_NVM3_PRESENT #if !defined(BOOTLOADER_MANUAL_OVERRIDE_SECURITY_STATE) \ || (defined(BOOTLOADER_MANUAL_OVERRIDE_SECURITY_STATE) \ && (BOOTLOADER_MANUAL_OVERRIDE_SECURITY_STATE == 0)) #define BOOTLOADER_ENABLE_USART_AUTO_DETECTION #endif // BOOTLOADER_MANUAL_OVERRIDE_SECURITY_STATE #if (defined(BOOTLOADER_DISABLE_OLD_BOOTLOADER_MITIGATION) \ && (BOOTLOADER_DISABLE_OLD_BOOTLOADER_MITIGATION == 1)) #define BOOTLOADER_DISABLE_MULTI_TIERED_FALLBACK #undef BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING #undef BOOTLOADER_ENABLE_USART_AUTO_DETECTION #endif // BOOTLOADER_DISABLE_OLD_BOOTLOADER_MITIGATION #if defined(SL_TRUSTZONE_SECURE) #undef BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING #endif // SL_TRUSTZONE_SECURE // ----------------------------------------------------------------------------- // Configuration spesifics #if defined(BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING) // Allocated range of NVM3 IDs for bootloader usage */ #define BL_NVM3_RESERVED_ID (0x87100UL) #include #include "nvm3_default.h" static bool blPPUSATDnStateCacheSet = false; static uint32_t blPPUSATDnStateCache[2] = { 0 }; #endif // BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING #if defined(BOOTLOADER_ENABLE_USART_AUTO_DETECTION) static void preConfigureUsartPPUSATD(void); static void storeUsartInUse(void); static int32_t usartNumberSpi = -1; #endif // BOOTLOADER_ENABLE_USART_AUTO_DETECTION #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE // ----------------------------------------------------------------------------- // Static variables #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) #if !defined(BOOTLOADER_TEST_UNPRIVILEGED_ACCESS) static CORE_DECLARE_IRQ_STATE; #endif static Bootloader_PPUSATDnCLKENnState_t blPPUSATDnCLKENnState = { 0 }; typedef enum { IDLE, SAVE, TIERED } ppusatdConfigurationState_t; static ppusatdConfigurationState_t bootloader_ppusatdConfigstate = IDLE; #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE // ----------------------------------------------------------------------------- // Enums typedef enum { RESET, INITIALIZED, DEINITIALIZED } initState_t; static initState_t bootloader_InitState = RESET; // ----------------------------------------------------------------------------- // Test helpers #if defined(BOOTLOADER_TEST_UNPRIVILEGED_ACCESS) extern bool enabled; extern void enterUnprivilegedMode(bool); extern void exitUnprivilegedMode(void); #endif // BOOTLOADER_TEST_UNPRIVILEGED_ACCESS // ----------------------------------------------------------------------------- // Functions void bootloader_getInfo(BootloaderInformation_t *info) { #if defined(BOOTLOADER_HAS_FIRST_STAGE) if (!bootloader_pointerToFirstStageValid(firstBootloaderTable) || !bootloader_pointerValid(mainBootloaderTable)) { // No bootloader is present (first stage or main stage invalid) info->type = NO_BOOTLOADER; info->capabilities = 0; } else if ((firstBootloaderTable->header.type == BOOTLOADER_MAGIC_FIRST_STAGE) && (mainBootloaderTable->header.type == BOOTLOADER_MAGIC_MAIN)) { info->type = SL_BOOTLOADER; info->version = mainBootloaderTable->header.version; info->capabilities = mainBootloaderTable->capabilities; } else { info->type = NO_BOOTLOADER; info->capabilities = 0; } #else if (!bootloader_pointerValid(mainBootloaderTable)) { // No bootloader is present (first stage or main stage invalid) info->type = NO_BOOTLOADER; info->capabilities = 0; } else if (mainBootloaderTable->header.type == BOOTLOADER_MAGIC_MAIN) { info->type = SL_BOOTLOADER; info->version = mainBootloaderTable->header.version; info->capabilities = mainBootloaderTable->capabilities; } else { info->type = NO_BOOTLOADER; info->capabilities = 0; } #endif } int32_t bootloader_init(void) { int32_t retVal; if (!bootloader_pointerValid(mainBootloaderTable)) { return BOOTLOADER_ERROR_INIT_TABLE; } if (mainBootloaderTable->header.type != BOOTLOADER_MAGIC_MAIN) { return BOOTLOADER_ERROR_INIT_TABLE; } if (bootloader_InitState == RESET || bootloader_InitState == DEINITIALIZED) { #if defined(SL_TRUSTZONE_SECURE) if (bootloader_InitState == RESET) { // Enable SMU bus clock at the start-up of the TZ secure application // to make it possible to configure the SMU peripheral. Since the CMU address // is known. Otherwise, delegate the SMU bus clock enablement to the NS application. #if defined(_CMU_CLKEN1_SMU_MASK) CMU->CLKEN1_SET = CMU_CLKEN1_SMU; #endif // _CMU_CLKEN1_SMU_MASK } #endif // SL_TRUSTZONE_SECURE #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnSaveReconfigureState(&blPPUSATDnCLKENnState); #endif #if defined(BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING) NVIC_ClearPendingIRQ(SMU_SECURE_IRQn); SMU->IF_CLR = SMU_IEN_PPUSEC; NVIC_EnableIRQ(SMU_SECURE_IRQn); SMU->IEN_SET = SMU_IEN_PPUSEC; #endif retVal = mainBootloaderTable->init(); #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnRestoreState(&blPPUSATDnCLKENnState); #endif if (retVal == BOOTLOADER_OK) { bootloader_InitState = INITIALIZED; } } else { retVal = BOOTLOADER_OK; } return retVal; } int32_t bootloader_deinit(void) { int32_t retVal; if (!bootloader_pointerValid(mainBootloaderTable)) { return BOOTLOADER_ERROR_INIT_TABLE; } if (mainBootloaderTable->header.type != BOOTLOADER_MAGIC_MAIN) { return BOOTLOADER_ERROR_INIT_TABLE; } if (bootloader_InitState == INITIALIZED) { #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnSaveReconfigureState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE #if defined(BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING) SMU->IF_CLR = SMU_IEN_PPUSEC; SMU->IEN_CLR = SMU_IEN_PPUSEC; NVIC_ClearPendingIRQ(SMU_SECURE_IRQn); NVIC_DisableIRQ(SMU_SECURE_IRQn); #endif retVal = mainBootloaderTable->deinit(); if (retVal == BOOTLOADER_OK) { bootloader_InitState = DEINITIALIZED; } #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnRestoreState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE } else { retVal = BOOTLOADER_OK; } return retVal; } BootloaderResetCause_t bootloader_getResetReason(void) { #if defined(__GNUC__) uint32_t resetReasonBase = (uint32_t)&__ResetReasonStart__; #elif defined(__ICCARM__) void *resetReasonBase = __section_begin("BOOTLOADER_RESET_REASON"); #endif volatile BootloaderResetCause_t *resetCause = (BootloaderResetCause_t *)(resetReasonBase); return *resetCause; } void bootloader_rebootAndInstall(void) { // Set reset reason to bootloader entry #if defined(__GNUC__) uint32_t resetReasonBase = (uint32_t)&__ResetReasonStart__; #elif defined(__ICCARM__) void *resetReasonBase = __section_begin("BOOTLOADER_RESET_REASON"); #endif BootloaderResetCause_t *resetCause = (BootloaderResetCause_t *) (resetReasonBase); resetCause->reason = BOOTLOADER_RESET_REASON_BOOTLOAD; resetCause->signature = BOOTLOADER_RESET_SIGNATURE_VALID; #if defined(RMU_PRESENT) // Clear resetcause RMU->CMD = RMU_CMD_RCCLR; // Trigger a software system reset RMU->CTRL = (RMU->CTRL & ~_RMU_CTRL_SYSRMODE_MASK) | RMU_CTRL_SYSRMODE_FULL; #endif NVIC_SystemReset(); } int32_t bootloader_initParser(BootloaderParserContext_t *context, size_t contextSize) { if (!bootloader_pointerValid(mainBootloaderTable)) { return BOOTLOADER_ERROR_PARSE_FAILED; } #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnSaveReconfigureState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE int32_t retVal = mainBootloaderTable->initParser(context, contextSize); #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnRestoreState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE return retVal; } int32_t bootloader_parseBuffer(BootloaderParserContext_t *context, BootloaderParserCallbacks_t *callbacks, uint8_t data[], size_t numBytes) { if (!bootloader_pointerValid(mainBootloaderTable)) { return BOOTLOADER_ERROR_PARSE_FAILED; } #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnSaveReconfigureState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE int32_t retVal = mainBootloaderTable->parseBuffer(context, callbacks, data, numBytes); #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnRestoreState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE return retVal; } int32_t bootloader_parseImageInfo(BootloaderParserContext_t *context, uint8_t data[], size_t numBytes, ApplicationData_t *appInfo, uint32_t *bootloaderVersion) { if (!bootloader_pointerValid(mainBootloaderTable)) { return BOOTLOADER_ERROR_PARSE_FAILED; } BootloaderInformation_t info = { .type = SL_BOOTLOADER, .version = 0U, .capabilities = 0U }; bootloader_getInfo(&info); uint32_t blMajorVersion = ((info.version & BOOTLOADER_VERSION_MAJOR_MASK) >> BOOTLOADER_VERSION_MAJOR_SHIFT); uint32_t blMinorVersion = ((info.version & BOOTLOADER_VERSION_MINOR_MASK) >> BOOTLOADER_VERSION_MINOR_SHIFT); if ((blMajorVersion < 1UL) || (blMajorVersion == 1UL && blMinorVersion < 11UL)) { return BOOTLOADER_ERROR_PARSE_FAILED; } #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnSaveReconfigureState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE int32_t retVal = mainBootloaderTable->parseImageInfo(context, data, numBytes, appInfo, bootloaderVersion); #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnRestoreState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE return retVal; } uint32_t bootloader_parserContextSize(void) { if (!bootloader_pointerValid(mainBootloaderTable)) { return 0UL; } BootloaderInformation_t info = { .type = SL_BOOTLOADER, .version = 0U, .capabilities = 0U }; bootloader_getInfo(&info); uint32_t blMajorVersion = ((info.version & BOOTLOADER_VERSION_MAJOR_MASK) >> BOOTLOADER_VERSION_MAJOR_SHIFT); uint32_t blMinorVersion = ((info.version & BOOTLOADER_VERSION_MINOR_MASK) >> BOOTLOADER_VERSION_MINOR_SHIFT); if (blMajorVersion < 1UL) { return 384UL; } if (blMajorVersion == 1UL && blMinorVersion < 11UL) { #if defined(_SILICON_LABS_32B_SERIES_2) if (blMinorVersion == 10UL) { return 524UL; } else { return 384UL; } #else return 384UL; #endif } return (uint32_t)mainBootloaderTable->parserContextSize(); } bool bootloader_verifyApplication(uint32_t startAddress) { if (!bootloader_pointerValid(mainBootloaderTable)) { return false; } #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnSaveReconfigureState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE bool retVal = mainBootloaderTable->verifyApplication(startAddress); #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) bootloader_ppusatdnRestoreState(&blPPUSATDnCLKENnState); #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE return retVal; } bool bootloader_secureBootEnforced(void) { BootloaderInformation_t info = { .type = SL_BOOTLOADER, .version = 0U, .capabilities = 0U }; bootloader_getInfo(&info); if (info.capabilities & BOOTLOADER_CAPABILITY_ENFORCE_SECURE_BOOT) { return true; } return false; } bool bootloader_getUpgradeLocation(uint32_t *location) { if (!bootloader_pointerValid(mainBootloaderTable)) { return false; } BootloaderInformation_t info = { .type = SL_BOOTLOADER, .version = 0U, .capabilities = 0U }; bootloader_getInfo(&info); uint32_t blMajorVersion = ((info.version & BOOTLOADER_VERSION_MAJOR_MASK) >> BOOTLOADER_VERSION_MAJOR_SHIFT); uint32_t blMinorVersion = ((info.version & BOOTLOADER_VERSION_MINOR_MASK) >> BOOTLOADER_VERSION_MINOR_SHIFT); if (blMajorVersion > 2UL || (blMajorVersion == 2UL && blMinorVersion >= 1UL)) { *location = mainBootloaderTable->getUpgradeLocation(); return true; } return false; } #if !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) uint32_t bootloader_remainingApplicationUpgrades(void) { if (!bootloader_pointerValid(mainBootloaderTable)) { return 0UL; } BootloaderInformation_t info = { .type = SL_BOOTLOADER, .version = 0U, .capabilities = 0U }; bootloader_getInfo(&info); uint32_t blMajorVersion = ((info.version & BOOTLOADER_VERSION_MAJOR_MASK) >> BOOTLOADER_VERSION_MAJOR_SHIFT); uint32_t blMinorVersion = ((info.version & BOOTLOADER_VERSION_MINOR_MASK) >> BOOTLOADER_VERSION_MINOR_SHIFT); if ((blMajorVersion < 1UL) || (blMajorVersion == 1UL && blMinorVersion < 11UL)) { return 0UL; } return (uint32_t)mainBootloaderTable->remainingApplicationUpgrades(); } #endif #if defined(_SILICON_LABS_32B_SERIES_2) bool bootloader_getCertificateVersion(uint32_t *version) { // Access word 13 to read sl_app_properties of the bootloader. ApplicationProperties_t *blProperties = (ApplicationProperties_t *)(*(uint32_t *)(BTL_MAIN_STAGE_BASE + 52UL)); if (!bootloader_pointerValid(blProperties)) { return false; } // Compatibility check of the application properties struct. if (((blProperties->structVersion & APPLICATION_PROPERTIES_VERSION_MAJOR_MASK) >> APPLICATION_PROPERTIES_VERSION_MAJOR_SHIFT) < 1UL) { return false; } if (((blProperties->structVersion & APPLICATION_PROPERTIES_VERSION_MINOR_MASK) >> APPLICATION_PROPERTIES_VERSION_MINOR_SHIFT) < 1UL) { return false; } if (blProperties->cert == NULL) { return false; } *version = blProperties->cert->version; return true; } #endif // _SILICON_LABS_32B_SERIES_2 #if defined(BOOTLOADER_INTERFACE_TRUSTZONE_AWARE) #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) void bootloader_getPeripheralList(uint32_t *ppusatd0, uint32_t *ppusatd1, uint32_t *ppusatd2) { if (!bootloader_pointerValid(mainBootloaderTable)) { return; } BootloaderInformation_t info = { .type = SL_BOOTLOADER, .version = 0U, .capabilities = 0U }; bootloader_getInfo(&info); if (info.capabilities & BOOTLOADER_CAPABILITY_PERIPHERAL_LIST) { mainBootloaderTable->getPeripheralList(ppusatd0, ppusatd1, ppusatd2); } } #else void bootloader_getPeripheralList(uint32_t *ppusatd0, uint32_t *ppusatd1) { if (!bootloader_pointerValid(mainBootloaderTable)) { return; } BootloaderInformation_t info = { .type = SL_BOOTLOADER, .version = 0U, .capabilities = 0U }; bootloader_getInfo(&info); if (info.capabilities & BOOTLOADER_CAPABILITY_PERIPHERAL_LIST) { mainBootloaderTable->getPeripheralList(ppusatd0, ppusatd1); } } #endif void bootloader_ppusatdnSaveReconfigureState(Bootloader_PPUSATDnCLKENnState_t *ctx) { if (bootloader_ppusatdConfigstate != IDLE) { // This function is called from a bootloader callback function bootloader_ppusatdConfigstate = TIERED; return; } uint32_t ppusatd0 = 0u; uint32_t ppusatd1 = 0u; #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) uint32_t ppusatd2 = 0u; #endif if (ctx == NULL) { return; } bootloader_ppusatdConfigstate = SAVE; // Enter ATOMIC section. The ATOMIC section is exited when // the restore function is called. #if !defined(BOOTLOADER_TEST_UNPRIVILEGED_ACCESS) CORE_ENTER_ATOMIC(); #endif sli_bootloader_preHook(); #if defined(BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING) // Read the stored PPUSATD state from NVM3 if (!blPPUSATDnStateCacheSet) { Ecode_t status; status = nvm3_initDefault(); if (status == ECODE_NVM3_OK) { nvm3_ObjectKey_t object_id = BL_NVM3_RESERVED_ID; status = nvm3_readData(nvm3_defaultHandle, object_id, blPPUSATDnStateCache, sizeof(blPPUSATDnStateCache)); if (status == ECODE_NVM3_OK) { blPPUSATDnStateCacheSet = true; } } } #endif // BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING // Store the CLKENn states #if defined(_CMU_CLKEN0_MASK) ctx->CLKEN0 = CMU->CLKEN0; ctx->CLKEN1 = CMU->CLKEN1; #endif #if defined(_CMU_CLKEN1_SMU_MASK) CMU->CLKEN1_SET = CMU_CLKEN1_SMU; #endif // _CMU_CLKEN1_SMU_MASK ctx->SMU_STATUS = SMU->STATUS; // Unlock SMU before re-configuration SMU->LOCK = SMU_LOCK_SMULOCKKEY_UNLOCK; // Store the PPUSATDn states ctx->PPUSATD0 = SMU->PPUSATD0; ctx->PPUSATD1 = SMU->PPUSATD1; #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) ctx->PPUSATD2 = SMU->PPUSATD2; #endif ctx->BMPUSATD0 = SMU->BMPUSATD0; #if defined(SMU_NS_CFGNS_BASE) // Store the PPUPATDn states ctx->PPUPATD0 = SMU->PPUPATD0; ctx->PPUPATD1 = SMU->PPUPATD1; #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) ctx->PPUPATD2 = SMU->PPUPATD2; #endif SMU->PPUPATD0 = SMU_NS_CFGNS->PPUNSPATD0; SMU->PPUPATD1 = SMU_NS_CFGNS->PPUNSPATD1; #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) SMU->PPUPATD2 = SMU_NS_CFGNS->PPUNSPATD2; #endif #endif // SMU_NS_CFGNS_BASE #if defined(CMU_CLKEN0_LDMA) CMU->CLKEN0_SET = CMU_CLKEN0_LDMA; #endif // CMU_CLKEN0_LDMA #if defined(CRYPTOACC_PRESENT) CMU->CLKEN1_SET = CMU_CLKEN1_CRYPTOACC; #endif // Wait for any active transition of other busmasters to finish if (SMU->PPUSATD0 & SMU_PPUSATD0_LDMA) { while (LDMA_S->STATUS & LDMA_STATUS_ANYBUSY) ; } else { while (LDMA_NS->STATUS & LDMA_STATUS_ANYBUSY) ; } #if defined(CRYPTOACC_PRESENT) if (SMU->PPUSATD1 & SMU_PPUSATD1_CRYPTOACC) { #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_230) while (CRYPTOACC_S->DMACTRL_STATUS & (CRYPTOACC_DMACTRL_STATUS_FETCH_BUSY | CRYPTOACC_DMACTRL_STATUS_PUSH_BUSY | CRYPTOACC_DMACTRL_STATUS_SOFT_RST_BUSY)) ; #else while (CRYPTOACC_S->STATUS & (CRYPTOACC_STATUS_FETCHERBSY | CRYPTOACC_STATUS_PUSHERBSY | CRYPTOACC_STATUS_SOFTRSTBSY)) ; #endif } else { #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_230) while (CRYPTOACC_NS->DMACTRL_STATUS & (CRYPTOACC_DMACTRL_STATUS_FETCH_BUSY | CRYPTOACC_DMACTRL_STATUS_PUSH_BUSY | CRYPTOACC_DMACTRL_STATUS_SOFT_RST_BUSY)) ; #else while (CRYPTOACC_NS->STATUS & (CRYPTOACC_STATUS_FETCHERBSY | CRYPTOACC_STATUS_PUSHERBSY | CRYPTOACC_STATUS_SOFTRSTBSY)) ; #endif } #endif // CRYPTOACC_PRESENT // Configure the peripheral secure access state before calling into the bootloader. #if !defined(BOOTLOADER_DISABLE_MULTI_TIERED_FALLBACK) #if defined(BOOTLOADER_ENABLE_USART_AUTO_DETECTION) // If we do not know which USART is used by the bootloader, // and the bootloader is not initialized, // Configure PPUSATDn bits for all the USART not in use. preConfigureUsartPPUSATD(); #else SMU->PPUSATD0_SET = BOOTLOADER_PPUSATD0_MASK; SMU->PPUSATD1_SET = BOOTLOADER_PPUSATD1_MASK; #endif // BOOTLOADER_ENABLE_USART_AUTO_DETECTION SMU->PPUSATD0_SET = SMU_PPUSATD0_CMU; SMU->PPUSATD0_SET = SMU_PPUSATD0_MSC; if (bootloader_getAllocatedDMAChannel() != -1 && bootloader_getAllocatedDMAChannel() != BOOTLOADER_ERROR_INIT_STORAGE) { SMU->PPUSATD0_SET = SMU_PPUSATD0_LDMA; SMU->PPUSATD0_SET = SMU_PPUSATD0_LDMAXBAR; SMU->BMPUSATD0_SET = SMU_BMPUSATD0_LDMA; } SMU->PPUSATD0_SET = SMU_PPUSATD0_HFRCO0; #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) && !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) \ && !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8) && !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9) SMU->PPUSATD0_SET = SMU_PPUSATD0_GPIO; #endif #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) SMU->PPUSATD1_SET = SMU_PPUSATD1_GPCRC; #else SMU->PPUSATD0_SET = SMU_PPUSATD0_GPCRC; #endif #if defined(SMU_PPUSATD1_CRYPTOACC) SMU->PPUSATD1_SET = SMU_PPUSATD1_CRYPTOACC; #endif // SMU_PPUSATD1_CRYPTOACC #if defined(SMU_PPUSATD1_SEMAILBOX) SMU->PPUSATD1_SET = SMU_PPUSATD1_SEMAILBOX; #elif defined(SMU_PPUSATD2_SEMAILBOX) SMU->PPUSATD2_SET = SMU_PPUSATD2_SEMAILBOX; #endif // SMU_PPUSATD1_SEMAILBOX #elif defined(SL_TRUSTZONE_SECURE) #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) SMU->BMPUSATD0_SET = SMU_BMPUSATD0_LDMA0; SMU->BMPUSATD0_SET = SMU_BMPUSATD0_LDMA1; #else SMU->BMPUSATD0_SET = SMU_BMPUSATD0_LDMA; #endif #endif // BOOTLOADER_DISABLE_MULTI_TIERED_FALLBACK #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) bootloader_getPeripheralList(&ppusatd0, &ppusatd1, &ppusatd2); SMU->PPUSATD0_SET = ppusatd0; SMU->PPUSATD1_SET = ppusatd1; SMU->PPUSATD2_SET = ppusatd2; #else bootloader_getPeripheralList(&ppusatd0, &ppusatd1); SMU->PPUSATD0_SET = ppusatd0; SMU->PPUSATD1_SET = ppusatd1; #endif #if defined(BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING) // Update the peripheral secure access state of // the "unknown" peripheral that triggered a fault earlier if (blPPUSATDnStateCacheSet == true) { SMU->PPUSATD0_SET = blPPUSATDnStateCache[0]; SMU->PPUSATD1_SET = blPPUSATDnStateCache[1]; } #endif // BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING #if defined(BOOTLOADER_TEST_UNPRIVILEGED_ACCESS) enterUnprivilegedMode(enabled); #endif } void bootloader_ppusatdnRestoreState(Bootloader_PPUSATDnCLKENnState_t *ctx) { #if defined(BOOTLOADER_TEST_UNPRIVILEGED_ACCESS) exitUnprivilegedMode(); #endif if (bootloader_ppusatdConfigstate != SAVE) { // This function is called from a bootloader callback function bootloader_ppusatdConfigstate = SAVE; return; } if (ctx == NULL) { return; } // Wait for any active transition of other busmasters to finish if (bootloader_getAllocatedDMAChannel() != -1 && bootloader_getAllocatedDMAChannel() != BOOTLOADER_ERROR_INIT_STORAGE) { #if defined(CMU_CLKEN0_LDMA) CMU_S->CLKEN0_SET = CMU_CLKEN0_LDMA; #endif // CMU_CLKEN0_LDMA while (LDMA_S->STATUS & LDMA_STATUS_ANYBUSY) ; } #if defined(CRYPTOACC_PRESENT) if (SMU->PPUSATD0 & SMU_PPUSATD0_CMU) { CMU_S->CLKEN1_SET = CMU_CLKEN1_CRYPTOACC; } else { CMU_NS->CLKEN1_SET = CMU_CLKEN1_CRYPTOACC; } #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_230) while (CRYPTOACC_S->DMACTRL_STATUS & (CRYPTOACC_DMACTRL_STATUS_FETCH_BUSY | CRYPTOACC_DMACTRL_STATUS_PUSH_BUSY | CRYPTOACC_DMACTRL_STATUS_SOFT_RST_BUSY)) ; #else while (CRYPTOACC_S->STATUS & (CRYPTOACC_STATUS_FETCHERBSY | CRYPTOACC_STATUS_PUSHERBSY | CRYPTOACC_STATUS_SOFTRSTBSY)) ; #endif #endif // CRYPTOACC_PRESENT SMU->PPUSATD0 = ctx->PPUSATD0; SMU->PPUSATD1 = ctx->PPUSATD1; #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) SMU->PPUSATD2 = ctx->PPUSATD2; #endif SMU->BMPUSATD0 = ctx->BMPUSATD0; #if defined(SMU_NS_CFGNS_BASE) SMU->PPUPATD0 = ctx->PPUPATD0; SMU->PPUPATD1 = ctx->PPUPATD1; #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) SMU->PPUPATD2 = ctx->PPUPATD2; #endif #endif // SMU_NS_CFGNS_BASE if (ctx->SMU_STATUS & SMU_STATUS_SMULOCK) { SMU->LOCK = 0u; } #if defined(BOOTLOADER_ENABLE_USART_AUTO_DETECTION) storeUsartInUse(); #endif // BOOTLOADER_ENABLE_USART_AUTO_DETECTION // Restore the CLKENn states #if defined(_CMU_CLKEN0_MASK) CMU->CLKEN0 = ctx->CLKEN0; CMU->CLKEN1 = ctx->CLKEN1; #endif sli_bootloader_postHook(); #if !defined(BOOTLOADER_TEST_UNPRIVILEGED_ACCESS) CORE_EXIT_ATOMIC(); #endif // Update the state after the critical section has been // exited to ensure that the SMU interrupt gets fired, // before the state change happens. bootloader_ppusatdConfigstate = IDLE; } __attribute__ ((weak)) void sli_bootloader_preHook(void) { } __attribute__ ((weak)) void sli_bootloader_postHook(void) { } #if defined(BOOTLOADER_ENABLE_USART_AUTO_DETECTION) static void preConfigureUsartPPUSATD(void) { if (usartNumberSpi != -1) { #if defined(SMU_PPUSATD1_USART0) SMU->PPUSATD1_SET = (SMU_PPUSATD1_USART0 << usartNumberSpi); #else SMU->PPUSATD0_SET = (SMU_PPUSATD0_USART0 << usartNumberSpi); #endif return; } if (bootloader_InitState != RESET) { // The USART taken by the bootloader // is still unknown, do nothing. return; } #if defined(USART0_BASE) #if defined(CMU_CLKEN0_USART0) CMU->CLKEN0_SET = CMU_CLKEN0_USART0; #endif // CMU_CLKEN0_USART0 #if defined(SL_TRUSTZONE_SECURE) if (USART0_NS->EN == _USART_EN_RESETVALUE) { #else if (USART0->EN == _USART_EN_RESETVALUE) { #endif // SL_TRUSTZONE_SECURE #if defined(SMU_PPUSATD1_USART0) SMU->PPUSATD1_SET = SMU_PPUSATD1_USART0; #else SMU->PPUSATD0_SET = SMU_PPUSATD0_USART0; #endif } #endif // USART0_BASE #if defined(USART1_BASE) #if defined(CMU_CLKEN0_USART1) CMU->CLKEN0_SET = CMU_CLKEN0_USART1; #elif defined(CMU_CLKEN2_USART1) CMU->CLKEN2_SET = CMU_CLKEN2_USART1; #endif #if defined(SL_TRUSTZONE_SECURE) if (USART1_NS->EN == _USART_EN_RESETVALUE) { #else if (USART1->EN == _USART_EN_RESETVALUE) { #endif // SL_TRUSTZONE_SECURE #if defined(SMU_PPUSATD1_USART1) SMU->PPUSATD1_SET = SMU_PPUSATD1_USART1; #else SMU->PPUSATD0_SET = SMU_PPUSATD0_USART1; #endif } #endif // USART1_BASE #if defined(USART2_BASE) #if defined(CMU_CLKEN0_USART2) CMU->CLKEN0_SET = CMU_CLKEN0_USART2; #elif defined(CMU_CLKEN2_USART2) CMU->CLKEN2_SET = CMU_CLKEN2_USART2; #endif #if defined(SL_TRUSTZONE_SECURE) if (USART2_NS->EN == _USART_EN_RESETVALUE) { #else if (USART2->EN == _USART_EN_RESETVALUE) { #endif // SL_TRUSTZONE_SECURE #if defined(SMU_PPUSATD1_USART2) SMU->PPUSATD1_SET = SMU_PPUSATD1_USART2; #else SMU->PPUSATD0_SET = SMU_PPUSATD0_USART2; #endif } #endif // USART2_BASE } static void storeUsartInUse(void) { if ((usartNumberSpi != -1) || (bootloader_InitState != RESET)) { return; } #if defined(USART0_BASE) #if defined(SL_TRUSTZONE_SECURE) if (USART0_NS->EN & USART_EN_EN) { #else if (USART0->EN & USART_EN_EN) { #endif // SL_TRUSTZONE_SECURE usartNumberSpi = 0; } #endif // USART0_BASE #if defined(USART1_BASE) #if defined(SL_TRUSTZONE_SECURE) if (USART1_NS->EN & USART_EN_EN) { #else if (USART1->EN & USART_EN_EN) { #endif // SL_TRUSTZONE_SECURE usartNumberSpi = 1; } #endif // USART1_BASE #if defined(USART2_BASE) #if defined(SL_TRUSTZONE_SECURE) if (USART2_NS->EN & USART_EN_EN) { #else if (USART2->EN & USART_EN_EN) { #endif // SL_TRUSTZONE_SECURE usartNumberSpi = 2; } #endif // USART2_BASE } #endif // BOOTLOADER_ENABLE_USART_AUTO_DETECTION #if defined(BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING) void SMU_SECURE_IRQHandler(void) { #if !defined(BOOTLOADER_TEST_FAULT_HANDLING) if (bootloader_ppusatdConfigstate == IDLE) { // If none of the bootloader interface operations are active, // the fault is not caused by the bootloader. Just park in the while loop. while (true) ; } #endif // BOOTLOADER_TEST_FAULT_HANDLING Ecode_t status; uint32_t PPUSATDn_state[2] = { 0 }; nvm3_ObjectKey_t object_id = BL_NVM3_RESERVED_ID; // First read the pre-existing configuration status = nvm3_readData(nvm3_defaultHandle, object_id, PPUSATDn_state, sizeof(PPUSATDn_state)); if (status == ECODE_NVM3_OK) { if (SMU->PPUFS > 31) { PPUSATDn_state[1] |= 1 << (SMU->PPUFS - 32); } else { PPUSATDn_state[0] |= 1 << SMU->PPUFS; } // Nothing to do to recover if this fails, just continue and perform a reset. (void)nvm3_writeData(nvm3_defaultHandle, object_id, PPUSATDn_state, sizeof(PPUSATDn_state)); } else if (status == ECODE_NVM3_ERR_KEY_NOT_FOUND) { if (SMU->PPUFS > 31) { PPUSATDn_state[1] = 1 << (SMU->PPUFS - 32); } else { PPUSATDn_state[0] = 1 << SMU->PPUFS; } (void)nvm3_writeData(nvm3_defaultHandle, object_id, PPUSATDn_state, sizeof(PPUSATDn_state)); } else { // Do nothing. If NVM3 read fails for an unknown reason, // perform a reset to recover from the failure state. } #if defined(__GNUC__) uint32_t resetReasonBase = (uint32_t)&__ResetReasonStart__; #elif defined(__ICCARM__) void *resetReasonBase = __section_begin("BOOTLOADER_RESET_REASON"); #endif BootloaderResetCause_t *resetCause = (BootloaderResetCause_t *) (resetReasonBase); resetCause->reason = BOOTLOADER_RESET_REASON_FAULT; resetCause->signature = BOOTLOADER_RESET_SIGNATURE_VALID; NVIC_SystemReset(); } #endif // BOOTLOADER_ENABLE_NVM3_FAULT_HANDLING #endif // BOOTLOADER_INTERFACE_TRUSTZONE_AWARE #if defined(__GNUC__) #pragma GCC diagnostic pop #endif