/***************************************************************************//**
* @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