| /* |
| * Copyright (c) 2018 Nordic Semiconductor ASA. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h> |
| #include <aarch32/cortex_m/tz.h> |
| #include <aarch32/cortex_m/exc.h> |
| |
| static void configure_nonsecure_vtor_offset(uint32_t vtor_ns) |
| { |
| SCB_NS->VTOR = vtor_ns; |
| } |
| |
| static void configure_nonsecure_msp(uint32_t msp_ns) |
| { |
| __TZ_set_MSP_NS(msp_ns); |
| } |
| |
| static void configure_nonsecure_psp(uint32_t psp_ns) |
| { |
| __TZ_set_PSP_NS(psp_ns); |
| } |
| |
| static void configure_nonsecure_control(uint32_t spsel_ns, uint32_t npriv_ns) |
| { |
| uint32_t control_ns = __TZ_get_CONTROL_NS(); |
| |
| /* Only nPRIV and SPSEL bits are banked between security states. */ |
| control_ns &= ~(CONTROL_SPSEL_Msk | CONTROL_nPRIV_Msk); |
| |
| if (spsel_ns) { |
| control_ns |= CONTROL_SPSEL_Msk; |
| } |
| if (npriv_ns) { |
| control_ns |= CONTROL_nPRIV_Msk; |
| } |
| |
| __TZ_set_CONTROL_NS(control_ns); |
| } |
| |
| #if defined(CONFIG_ARMV8_M_MAINLINE) |
| |
| /* Only ARMv8-M Mainline implementations have Non-Secure instances of |
| * Stack Pointer Limit registers. |
| */ |
| |
| void tz_nonsecure_msplim_set(uint32_t val) |
| { |
| __TZ_set_MSPLIM_NS(val); |
| } |
| |
| void tz_nonsecure_psplim_set(uint32_t val) |
| { |
| __TZ_set_PSPLIM_NS(val); |
| } |
| #endif /* CONFIG_ARMV8_M_MAINLINE */ |
| |
| void tz_nonsecure_state_setup(const tz_nonsecure_setup_conf_t *p_ns_conf) |
| { |
| configure_nonsecure_vtor_offset(p_ns_conf->vtor_ns); |
| configure_nonsecure_msp(p_ns_conf->msp_ns); |
| configure_nonsecure_psp(p_ns_conf->psp_ns); |
| /* Select which stack-pointer to use (MSP or PSP) and |
| * the privilege level for thread mode. |
| */ |
| configure_nonsecure_control(p_ns_conf->control_ns.spsel, |
| p_ns_conf->control_ns.npriv); |
| } |
| |
| void tz_nbanked_exception_target_state_set(int secure_state) |
| { |
| uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); |
| if (secure_state) { |
| aircr_payload &= ~(SCB_AIRCR_BFHFNMINS_Msk); |
| } else { |
| aircr_payload |= SCB_AIRCR_BFHFNMINS_Msk; |
| } |
| SCB->AIRCR = ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) |
| & SCB_AIRCR_VECTKEY_Msk) |
| | aircr_payload; |
| } |
| |
| void tz_nonsecure_exception_prio_config(int secure_boost) |
| { |
| uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); |
| if (secure_boost) { |
| aircr_payload |= SCB_AIRCR_PRIS_Msk; |
| } else { |
| aircr_payload &= ~(SCB_AIRCR_PRIS_Msk); |
| } |
| SCB->AIRCR = ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) |
| & SCB_AIRCR_VECTKEY_Msk) |
| | aircr_payload; |
| } |
| |
| void tz_nonsecure_system_reset_req_block(int block) |
| { |
| uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); |
| if (block) { |
| aircr_payload |= SCB_AIRCR_SYSRESETREQS_Msk; |
| } else { |
| aircr_payload &= ~(SCB_AIRCR_SYSRESETREQS_Msk); |
| } |
| SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
| & SCB_AIRCR_VECTKEY_Msk) |
| | aircr_payload; |
| } |
| |
| #if defined(CONFIG_ARMV7_M_ARMV8_M_FP) |
| void tz_nonsecure_fpu_access_enable(void) |
| { |
| SCB->NSACR |= |
| (1UL << SCB_NSACR_CP10_Pos) | (1UL << SCB_NSACR_CP11_Pos); |
| } |
| #endif /* CONFIG_ARMV7_M_ARMV8_M_FP */ |
| |
| void tz_sau_configure(int enable, int allns) |
| { |
| if (enable) { |
| TZ_SAU_Enable(); |
| } else { |
| TZ_SAU_Disable(); |
| if (allns) { |
| SAU->CTRL |= SAU_CTRL_ALLNS_Msk; |
| } else { |
| SAU->CTRL &= ~(SAU_CTRL_ALLNS_Msk); |
| } |
| } |
| } |
| |
| uint32_t tz_sau_number_of_regions_get(void) |
| { |
| return SAU->TYPE & SAU_TYPE_SREGION_Msk; |
| } |
| |
| #if defined(CONFIG_CPU_HAS_ARM_SAU) |
| #if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) |
| int tz_sau_region_configure_enable(tz_sau_conf_t *p_sau_conf) |
| { |
| uint32_t regions = tz_sau_number_of_regions_get(); |
| |
| if ((p_sau_conf->region_num == 0) || |
| (p_sau_conf->region_num > (regions - 1))) { |
| return 0; |
| } |
| |
| /* Valid region */ |
| SAU->RNR = p_sau_conf->region_num & SAU_RNR_REGION_Msk; |
| |
| if (p_sau_conf->enable) { |
| SAU->RLAR = SAU_RLAR_ENABLE_Msk |
| | (SAU_RLAR_LADDR_Msk & p_sau_conf->limit_addr) |
| | (p_sau_conf->nsc ? SAU_RLAR_NSC_Msk : 0); |
| SAU->RBAR = p_sau_conf->base_addr & SAU_RBAR_BADDR_Msk; |
| } else { |
| SAU->RLAR &= ~(SAU_RLAR_ENABLE_Msk); |
| } |
| |
| return 1; |
| } |
| #else |
| #error "ARM SAU not implemented" |
| #endif |
| #endif /* CONFIG_CPU_HAS_ARM_SAU */ |