/* * Copyright (c) 2018-2024, Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "tfm_hal_device_header.h" #include "target_cfg.h" #include "Driver_MPC.h" #include "platform_retarget_dev.h" #include "region_defs.h" #include "tfm_plat_defs.h" #include "region.h" #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) /* The section names come from the scatter file */ REGION_DECLARE(Load$$LR$$, LR_NS_PARTITION, $$Base); REGION_DECLARE(Image$$, ER_VENEER, $$Base); REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit); #ifdef BL2 REGION_DECLARE(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base); #endif /* BL2 */ const struct memory_region_limits memory_regions = { .non_secure_code_start = (uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) + BL2_HEADER_SIZE, .non_secure_partition_base = (uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base), .non_secure_partition_limit = (uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) + NS_PARTITION_SIZE - 1, .veneer_base = (uint32_t)®ION_NAME(Image$$, ER_VENEER, $$Base), .veneer_limit = (uint32_t)®ION_NAME(Image$$, VENEER_ALIGN, $$Limit), #ifdef BL2 .secondary_partition_base = (uint32_t)®ION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base), .secondary_partition_limit = (uint32_t)®ION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base) + SECONDARY_PARTITION_SIZE - 1, #endif /* BL2 */ }; /* Allows software, via SAU, to define the code region as a NSC */ #define NSCCFG_CODENSC 1 /* Import MPC driver */ extern ARM_DRIVER_MPC Driver_SRAM1_MPC, Driver_SRAM2_MPC; /* Define Peripherals NS address range for the platform */ #define PERIPHERALS_BASE_NS_START (0x40000000) #define PERIPHERALS_BASE_NS_END (0x4FFFFFFF) /* Enable system reset request for CPU 0 */ #define ENABLE_CPU0_SYSTEM_RESET_REQUEST (1U << 4U) /* To write into AIRCR register, 0x5FA value must be write to the VECTKEY field, * otherwise the processor ignores the write. */ #define SCB_AIRCR_WRITE_MASK ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)) /* Debug configuration flags */ #define SPNIDEN_SEL_STATUS (0x01u << 7) #define SPNIDEN_STATUS (0x01u << 6) #define SPIDEN_SEL_STATUS (0x01u << 5) #define SPIDEN_STATUS (0x01u << 4) #define NIDEN_SEL_STATUS (0x01u << 3) #define NIDEN_STATUS (0x01u << 2) #define DBGEN_SEL_STATUS (0x01u << 1) #define DBGEN_STATUS (0x01u << 0) #define All_SEL_STATUS (SPNIDEN_SEL_STATUS | SPIDEN_SEL_STATUS | \ NIDEN_SEL_STATUS | DBGEN_SEL_STATUS) struct platform_data_t tfm_peripheral_std_uart = { UART0_BASE_NS, UART0_BASE_NS + 0xFFF, PPC_SP_DO_NOT_CONFIGURE, -1 }; struct platform_data_t tfm_peripheral_uart1 = { UART1_BASE_S, UART1_BASE_S + 0xFFF, PPC_SP_APB_PPC_EXP1, CMSDK_UART1_APB_PPC_POS }; struct platform_data_t tfm_peripheral_timer0 = { CMSDK_TIMER0_BASE_S, CMSDK_TIMER1_BASE_S - 1, PPC_SP_APB_PPC0, CMSDK_TIMER0_APB_PPC_POS }; enum tfm_plat_err_t enable_fault_handlers(void) { /* Secure fault is not present in the Baseline implementation. */ /* Fault handler enable registers are not present in a Baseline * implementation. */ return TFM_PLAT_ERR_SUCCESS; } enum tfm_plat_err_t system_reset_cfg(void) { struct sysctrl_t *sysctrl = (struct sysctrl_t *)CMSDK_SYSCTRL_BASE_S; uint32_t reg_value = SCB->AIRCR; /* Enable system reset request for CPU 0, to be triggered via * NVIC_SystemReset function. */ sysctrl->resetmask |= ENABLE_CPU0_SYSTEM_RESET_REQUEST; /* Clear SCB_AIRCR_VECTKEY value */ reg_value &= ~(uint32_t)(SCB_AIRCR_VECTKEY_Msk); /* Enable system reset request for the secure world only */ reg_value |= (uint32_t)(SCB_AIRCR_WRITE_MASK | SCB_AIRCR_SYSRESETREQS_Msk); SCB->AIRCR = reg_value; return TFM_PLAT_ERR_SUCCESS; } enum tfm_plat_err_t init_debug(void) { volatile struct sysctrl_t *sys_ctrl = (struct sysctrl_t *)CMSDK_SYSCTRL_BASE_S; #if defined(DAUTH_NONE) /* Set all the debug enable selector bits to 1 */ sys_ctrl->secdbgset = All_SEL_STATUS; /* Set all the debug enable bits to 0 */ sys_ctrl->secdbgclr = DBGEN_STATUS | NIDEN_STATUS | SPIDEN_STATUS | SPNIDEN_STATUS; #elif defined(DAUTH_NS_ONLY) /* Set all the debug enable selector bits to 1 */ sys_ctrl->secdbgset = All_SEL_STATUS; /* Set the debug enable bits to 1 for NS, and 0 for S mode */ sys_ctrl->secdbgset = DBGEN_STATUS | NIDEN_STATUS; sys_ctrl->secdbgclr = SPIDEN_STATUS | SPNIDEN_STATUS; #elif defined(DAUTH_FULL) /* Set all the debug enable selector bits to 1 */ sys_ctrl->secdbgset = All_SEL_STATUS; /* Set all the debug enable bits to 1 */ sys_ctrl->secdbgset = DBGEN_STATUS | NIDEN_STATUS | SPIDEN_STATUS | SPNIDEN_STATUS; #else #if !defined(DAUTH_CHIP_DEFAULT) #error "No debug authentication setting is provided." #endif /* Set all the debug enable selector bits to 0 */ sys_ctrl->secdbgclr = All_SEL_STATUS; /* No need to set any enable bits because the value depends on * input signals. */ #endif return TFM_PLAT_ERR_SUCCESS; } /*----------------- NVIC interrupt target state to NS configuration ----------*/ enum tfm_plat_err_t nvic_interrupt_target_state_cfg(void) { /* Target every interrupt to NS; unimplemented interrupts will be WI */ for (uint8_t i=0; iITNS)/sizeof(NVIC->ITNS[0]); i++) { NVIC->ITNS[i] = 0xFFFFFFFF; } /* Make sure that MPC and PPC are targeted to S state */ NVIC_ClearTargetState(MPC_IRQn); NVIC_ClearTargetState(PPC_IRQn); #ifdef SECURE_UART1 /* UART1 is a secure peripheral, so its IRQs have to target S state */ NVIC_ClearTargetState(UARTRX1_IRQn); NVIC_ClearTargetState(UARTTX1_IRQn); NVIC_ClearTargetState(UART1_IRQn); #endif return TFM_PLAT_ERR_SUCCESS; } /*----------------- NVIC interrupt enabling for S peripherals ----------------*/ enum tfm_plat_err_t nvic_interrupt_enable(void) { struct spctrl_def* spctrl = CMSDK_SPCTRL; int32_t ret = ARM_DRIVER_OK; /* MPC interrupt enabling */ ret = Driver_SRAM1_MPC.EnableInterrupt(); if (ret != ARM_DRIVER_OK) { return TFM_PLAT_ERR_SYSTEM_ERR; } ret = Driver_SRAM2_MPC.EnableInterrupt(); if (ret != ARM_DRIVER_OK) { return TFM_PLAT_ERR_SYSTEM_ERR; } NVIC_EnableIRQ(MPC_IRQn); /* PPC interrupt enabling */ /* Clear pending PPC interrupts */ /* In the PPC configuration function, we have used the Non-Secure * Privilege Control Block to grant unprivilged NS access to some * peripherals used by NS. That triggers a PPC0 exception as that * register is meant for NS privileged access only. Clear it here */ spctrl->secppcintclr = CMSDK_APB_PPC0_INT_POS_MASK; /* Enable PPC interrupts for APB PPC */ spctrl->secppcinten |= CMSDK_APB_PPC0_INT_POS_MASK | CMSDK_APB_PPC1_INT_POS_MASK | CMSDK_APB_PPCEXP0_INT_POS_MASK | CMSDK_APB_PPCEXP1_INT_POS_MASK | CMSDK_APB_PPCEXP2_INT_POS_MASK | CMSDK_APB_PPCEXP3_INT_POS_MASK; NVIC_EnableIRQ(PPC_IRQn); return TFM_PLAT_ERR_SUCCESS; } /*------------------- SAU/IDAU configuration functions -----------------------*/ struct sau_cfg_t { uint32_t RBAR; uint32_t RLAR; bool nsc; }; const struct sau_cfg_t sau_cfg[] = { { ((uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base)), ((uint32_t)®ION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) + NS_PARTITION_SIZE - 1), false, }, { NS_DATA_START, NS_DATA_LIMIT, false, }, { (uint32_t)®ION_NAME(Image$$, ER_VENEER, $$Base), (uint32_t)®ION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1, true, }, { PERIPHERALS_BASE_NS_START, #ifdef SECURE_UART1 (UART1_BASE_NS - 1), false, }, { UART2_BASE_NS, #endif PERIPHERALS_BASE_NS_END, false, }, #ifdef BL2 { (uint32_t)®ION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base), (uint32_t)®ION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base) + SECONDARY_PARTITION_SIZE - 1, false, }, #endif }; void sau_and_idau_cfg(void) { struct spctrl_def *spctrl = CMSDK_SPCTRL; uint32_t i; /* Ensure all memory accesses are completed */ __DMB(); /* Enables SAU */ TZ_SAU_Enable(); for (i = 0; i < ARRAY_SIZE(sau_cfg); i++) { SAU->RNR = i; SAU->RBAR = sau_cfg[i].RBAR & SAU_RBAR_BADDR_Msk; SAU->RLAR = (sau_cfg[i].RLAR & SAU_RLAR_LADDR_Msk) | (sau_cfg[i].nsc ? SAU_RLAR_NSC_Msk : 0U) | SAU_RLAR_ENABLE_Msk; } /* Allows SAU to define the code region as a NSC */ spctrl->nsccfg |= NSCCFG_CODENSC; /* Ensure the write is completed and flush pipeline */ __DSB(); __ISB(); } /*------------------- Memory configuration functions -------------------------*/ int32_t mpc_init_cfg(void) { int32_t ret = ARM_DRIVER_OK; ret = Driver_SRAM1_MPC.Initialize(); if (ret != ARM_DRIVER_OK) { return ret; } ret = Driver_SRAM1_MPC.ConfigRegion( memory_regions.non_secure_partition_base, memory_regions.non_secure_partition_limit, ARM_MPC_ATTR_NONSECURE); if (ret != ARM_DRIVER_OK) { return ret; } #ifdef BL2 /* Secondary image region */ ret = Driver_SRAM1_MPC.ConfigRegion(memory_regions.secondary_partition_base, memory_regions.secondary_partition_limit, ARM_MPC_ATTR_NONSECURE); if (ret != ARM_DRIVER_OK) { return ret; } #endif /* BL2 */ ret = Driver_SRAM2_MPC.Initialize(); if (ret != ARM_DRIVER_OK) { return ret; } ret = Driver_SRAM2_MPC.ConfigRegion(NS_DATA_START, NS_DATA_LIMIT, ARM_MPC_ATTR_NONSECURE); if (ret != ARM_DRIVER_OK) { return ret; } /* Lock down the MPC configuration */ ret = Driver_SRAM1_MPC.LockDown(); if (ret != ARM_DRIVER_OK) { return ret; } ret = Driver_SRAM2_MPC.LockDown(); if (ret != ARM_DRIVER_OK) { return ret; } /* Add barriers to assure the MPC configuration is done before continue * the execution. */ __DSB(); __ISB(); return ARM_DRIVER_OK; } /*---------------------- PPC configuration functions -------------------------*/ void ppc_init_cfg(void) { struct spctrl_def* spctrl = CMSDK_SPCTRL; struct nspctrl_def* nspctrl = CMSDK_NSPCTRL; /* Grant non-secure access to peripherals in the PPC0 * (timer0 and 1, dualtimer, watchdog, mhu 0 and 1) */ spctrl->apbnsppc0 |= (1U << CMSDK_TIMER0_APB_PPC_POS) | (1U << CMSDK_TIMER1_APB_PPC_POS) | (1U << CMSDK_DTIMER_APB_PPC_POS) | (1U << CMSDK_MHU0_APB_PPC_POS) | (1U << CMSDK_MHU1_APB_PPC_POS); /* Grant non-secure access for APB peripherals on EXP1 */ spctrl->apbnsppcexp1 |= (1U << CMSDK_SPI0_APB_PPC_POS) | (1U << CMSDK_SPI1_APB_PPC_POS) | (1U << CMSDK_SPI2_APB_PPC_POS) | (1U << CMSDK_SPI3_APB_PPC_POS) | (1U << CMSDK_SPI4_APB_PPC_POS) | (1U << CMSDK_UART0_APB_PPC_POS) | #ifdef SECURE_UART1 /* To statically configure a peripheral as secure, skip PPC NS peripheral * configuration for the given device. */ #else (1U << CMSDK_UART1_APB_PPC_POS) | #endif (1U << CMSDK_UART2_APB_PPC_POS) | (1U << CMSDK_UART3_APB_PPC_POS) | (1U << CMSDK_UART4_APB_PPC_POS) | (1U << CMSDK_I2C0_APB_PPC_POS) | (1U << CMSDK_I2C1_APB_PPC_POS) | (1U << CMSDK_I2C2_APB_PPC_POS) | (1U << CMSDK_I2C3_APB_PPC_POS); /* Grant non-secure access for APB peripherals on EXP2 */ spctrl->apbnsppcexp2 |= (1U << CMSDK_FPGA_SCC_PPC_POS) | (1U << CMSDK_FPGA_AUDIO_PPC_POS) | (1U << CMSDK_FPGA_IO_PPC_POS); /* Grant non-secure access to all peripherals on AHB EXP: * Make sure that all possible peripherals are enabled by default */ spctrl->ahbnsppcexp0 |= (1U << CMSDK_VGA_PPC_POS) | (1U << CMSDK_GPIO0_PPC_POS) | (1U << CMSDK_GPIO1_PPC_POS) | (1U << CMSDK_GPIO2_PPC_POS) | (1U << CMSDK_GPIO3_PPC_POS) | (1U << MPS2_ETHERNET_PPC_POS); spctrl->ahbnsppcexp1 |= (1U << CMSDK_DMA0_PPC_POS) | (1U << CMSDK_DMA1_PPC_POS) | (1U << CMSDK_DMA2_PPC_POS) | (1U << CMSDK_DMA3_PPC_POS); /* in NS, grant un-privileged for UART0 */ nspctrl->apbnspppcexp1 |= (1U << CMSDK_UART0_APB_PPC_POS); /* in NS, grant un-privileged access for LEDs */ nspctrl->apbnspppcexp2 |= (1U << CMSDK_FPGA_SCC_PPC_POS) | (1U << CMSDK_FPGA_IO_PPC_POS); /* Configure the response to a security violation as a * bus error instead of RAZ/WI */ spctrl->secrespcfg |= 1U; } void ppc_configure_to_non_secure(enum ppc_bank_e bank, uint16_t pos) { /* Setting NS flag for peripheral to enable NS access */ struct spctrl_def* spctrl = CMSDK_SPCTRL; ((uint32_t*)&(spctrl->ahbnsppc0))[bank] |= (1U << pos); } void ppc_configure_to_secure(enum ppc_bank_e bank, uint16_t pos) { /* Clear NS flag for peripheral to prevent NS access */ struct spctrl_def* spctrl = CMSDK_SPCTRL; ((uint32_t*)&(spctrl->ahbnsppc0))[bank] &= ~(1U << pos); } void ppc_en_secure_unpriv(enum ppc_bank_e bank, uint16_t pos) { struct spctrl_def* spctrl = CMSDK_SPCTRL; ((uint32_t*)&(spctrl->ahbspppc0))[bank] |= (1U << pos); } void ppc_clr_secure_unpriv(enum ppc_bank_e bank, uint16_t pos) { struct spctrl_def* spctrl = CMSDK_SPCTRL; ((uint32_t*)&(spctrl->ahbspppc0))[bank] &= ~(1U << pos); } void ppc_clear_irq(void) { struct spctrl_def* spctrl = CMSDK_SPCTRL; /* Clear APB PPC EXP2 IRQ */ spctrl->secppcintclr = CMSDK_APB_PPCEXP2_INT_POS_MASK; }