diff --git a/arch/arm/core/cortex_m/vector_table.S b/arch/arm/core/cortex_m/vector_table.S index 99092df24b9..b3f039f1ba7 100644 --- a/arch/arm/core/cortex_m/vector_table.S +++ b/arch/arm/core/cortex_m/vector_table.S @@ -53,7 +53,11 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table) .word __mpu_fault .word __bus_fault .word __usage_fault +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + .word __secure_fault +#else .word __reserved +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ .word __reserved .word __reserved .word __reserved diff --git a/arch/arm/core/cortex_m/vector_table.h b/arch/arm/core/cortex_m/vector_table.h index 4d696e1092d..3189f2ba9aa 100644 --- a/arch/arm/core/cortex_m/vector_table.h +++ b/arch/arm/core/cortex_m/vector_table.h @@ -44,6 +44,9 @@ GTEXT(__svc) GTEXT(__mpu_fault) GTEXT(__bus_fault) GTEXT(__usage_fault) +#if defined(CONFIG_ARM_SECURE_FIRMWARE) +GTEXT(__secure_fault) +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ GTEXT(__svc) GTEXT(__debug_monitor) #else diff --git a/arch/arm/core/fault.c b/arch/arm/core/fault.c index 14eec0e5d0e..702023c3918 100644 --- a/arch/arm/core/fault.c +++ b/arch/arm/core/fault.c @@ -74,6 +74,9 @@ void _FaultDump(const NANO_ESF *esf, int fault) PR_EXC("MMFSR: 0x%x, BFSR: 0x%x, UFSR: 0x%x\n", SCB_MMFSR, SCB_BFSR, SCB_MMFSR); +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + PR_EXC("SFSR: 0x%x\n", SAU->SFSR); +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ /* In a fault handler, to determine the true faulting address: * 1. Read and save the MMFAR or BFAR value. @@ -85,6 +88,9 @@ void _FaultDump(const NANO_ESF *esf, int fault) */ STORE_xFAR(mmfar, SCB->MMFAR); STORE_xFAR(bfar, SCB->BFAR); +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + STORE_xFAR(sfar, SAU->SFAR); +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ if (SCB->CFSR & CFSR_MMARVALID_Msk) { PR_EXC("MMFAR: 0x%x\n", mmfar); @@ -100,6 +106,18 @@ void _FaultDump(const NANO_ESF *esf, int fault) SCB->CFSR &= ~CFSR_BFARVALID_Msk; } } +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + if (SAU->SFSR & SAU_SFSR_SFARVALID_Msk) { + PR_EXC("SFAR: 0x%x\n", sfar); + if (escalation) { + /* clear SFSR_SFAR[VALID] to reset */ + SAU->SFSR &= ~SAU_SFSR_SFARVALID_Msk; + } + } + + /* clear SFSR sticky bits */ + SAU->SFSR |= 0xFF; +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ /* clear USFR sticky bits */ SCB->CFSR |= SCB_CFSR_USGFAULTSR_Msk; @@ -274,6 +292,61 @@ static void _UsageFault(const NANO_ESF *esf) SCB->CFSR |= SCB_CFSR_USGFAULTSR_Msk; } +#if defined(CONFIG_ARM_SECURE_FIRMWARE) +/** + * + * @brief Dump secure fault information + * + * See _FaultDump() for example. + * + * @return N/A + */ +static void _SecureFault(const NANO_ESF *esf) +{ + PR_EXC("***** SECURE FAULT *****\n"); + + _FaultThreadShow(esf); + + STORE_xFAR(sfar, SAU->SFAR); + if (SAU->SFSR & SAU_SFSR_SFARVALID_Msk) { + PR_EXC(" Address: 0x%x\n", sfar); + } + + /* bits are sticky: they stack and must be reset */ + if (SAU->SFSR & SAU_SFSR_INVEP_Msk) { + PR_EXC(" Invalid entry point\n"); + } else if (SAU->SFSR & SAU_SFSR_INVIS_Msk) { + PR_EXC(" Invalid integrity signature\n"); + } else if (SAU->SFSR & SAU_SFSR_INVER_Msk) { + PR_EXC(" Invalid exception return\n"); + } else if (SAU->SFSR & SAU_SFSR_AUVIOL_Msk) { + PR_EXC(" Attribution unit violation\n"); + } else if (SAU->SFSR & SAU_SFSR_INVTRAN_Msk) { + PR_EXC(" Invalid transition\n"); + } else if (SAU->SFSR & SAU_SFSR_LSPERR_Msk) { + PR_EXC(" Lazy state preservation\n"); + } else if (SAU->SFSR & SAU_SFSR_LSERR_Msk) { + PR_EXC(" Lazy state error\n"); + } + + /* SecureFault is never banked between security states. Therefore, + * we may wish to, additionally, inspect the state of the Non-Secure + * execution (program counter), to gain more information regarding + * the root cause of the fault. + */ + NANO_ESF *esf_ns; + if (SCB_NS->ICSR & SCB_ICSR_RETTOBASE_Msk) { + esf_ns = (NANO_ESF *)__TZ_get_PSP_NS(); + } else { + esf_ns = (NANO_ESF *)__TZ_get_MSP_NS(); + } + PR_EXC(" NS instruction address: 0x%x\n", esf_ns->pc); + + /* clear SFSR sticky bits */ + SAU->SFSR |= 0xFF; +} +#endif /* defined(CONFIG_ARM_SECURE_FIRMWARE) */ + /** * * @brief Dump debug monitor exception information @@ -318,6 +391,10 @@ static void _HardFault(const NANO_ESF *esf) _BusFault(esf, 1); } else if (SCB_UFSR) { _UsageFault(esf); +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + } else if (SAU->SFSR) { + _SecureFault(esf); +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ } } #else @@ -379,6 +456,11 @@ static void _FaultDump(const NANO_ESF *esf, int fault) case 6: _UsageFault(esf); break; +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + case 7: + _SecureFault(esf); + break; +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ case 12: _DebugMonitor(esf); break; diff --git a/arch/arm/core/fault_s.S b/arch/arm/core/fault_s.S index 1615acf468a..ff6ca3b06d8 100644 --- a/arch/arm/core/fault_s.S +++ b/arch/arm/core/fault_s.S @@ -26,6 +26,9 @@ GTEXT(__hard_fault) GTEXT(__mpu_fault) GTEXT(__bus_fault) GTEXT(__usage_fault) +#if defined(CONFIG_ARM_SECURE_FIRMWARE) +GTEXT(__secure_fault) +#endif /* CONFIG_ARM_SECURE_FIRMWARE*/ GTEXT(__debug_monitor) #else #error Unknown ARM architecture @@ -51,6 +54,7 @@ GTEXT(__reserved) * __mpu_fault * __bus_fault * __usage_fault + * __secure_fault * __debug_monitor * __reserved */ @@ -62,6 +66,9 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__hard_fault) SECTION_SUBSEC_FUNC(TEXT,__fault,__mpu_fault) SECTION_SUBSEC_FUNC(TEXT,__fault,__bus_fault) SECTION_SUBSEC_FUNC(TEXT,__fault,__usage_fault) +#if defined(CONFIG_ARM_SECURE_FIRMWARE) +SECTION_SUBSEC_FUNC(TEXT,__fault,__secure_fault) +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ SECTION_SUBSEC_FUNC(TEXT,__fault,__debug_monitor) #else #error Unknown ARM architecture diff --git a/arch/arm/include/cortex_m/exc.h b/arch/arm/include/cortex_m/exc.h index 5b35b157638..c61d1371e17 100644 --- a/arch/arm/include/cortex_m/exc.h +++ b/arch/arm/include/cortex_m/exc.h @@ -102,10 +102,24 @@ static ALWAYS_INLINE void _ExcSetup(void) NVIC_SetPriority(MemoryManagement_IRQn, _EXC_FAULT_PRIO); NVIC_SetPriority(BusFault_IRQn, _EXC_FAULT_PRIO); NVIC_SetPriority(UsageFault_IRQn, _EXC_FAULT_PRIO); +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + NVIC_SetPriority(SecureFault_IRQn, _EXC_FAULT_PRIO); +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ /* Enable Usage, Mem, & Bus Faults */ SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk; +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + /* Enable Secure Fault */ + SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk; + /* Clear BFAR before setting BusFaults to target Non-Secure state. */ + SCB->BFAR = 0; + /* Set NMI, Hard, and Bus Faults as Non-Secure. + * NMI and Bus Faults targeting the Secure state will + * escalate to a SecureFault or SecureHardFault. + */ + SCB->AIRCR |= SCB_AIRCR_BFHFNMINS_Msk; +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ #endif }