diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ffecc36a82..4d77d7b549 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -739,6 +739,7 @@ config ARCH_CORTEXM33 select ARCH_HAVE_MEMFAULT_DEBUG select ARCH_HAVE_BUSFAULT_DEBUG select ARCH_HAVE_USAGEFAULT_DEBUG + select ARCH_HAVE_SECUREFAULT_DEBUG if ARCH_TRUSTZONE_SECURE config ARCH_CORTEXM35P bool @@ -755,6 +756,7 @@ config ARCH_CORTEXM35P select ARCH_HAVE_MEMFAULT_DEBUG select ARCH_HAVE_BUSFAULT_DEBUG select ARCH_HAVE_USAGEFAULT_DEBUG + select ARCH_HAVE_SECUREFAULT_DEBUG if ARCH_TRUSTZONE_SECURE config ARCH_CORTEXM55 bool @@ -771,6 +773,7 @@ config ARCH_CORTEXM55 select ARCH_HAVE_MEMFAULT_DEBUG select ARCH_HAVE_BUSFAULT_DEBUG select ARCH_HAVE_USAGEFAULT_DEBUG + select ARCH_HAVE_SECUREFAULT_DEBUG if ARCH_TRUSTZONE_SECURE config ARCH_FAMILY string @@ -1006,6 +1009,19 @@ config DEBUG_USAGEFAULT output is sometimes helpful when debugging difficult usage fault problems, but may be more than you typically want to see. +config ARCH_HAVE_SECUREFAULT_DEBUG + bool + default n + +config DEBUG_SECUREFAULT + bool "Verbose Secure-Fault Debug" + default n + depends on ARCH_HAVE_SECUREFAULT_DEBUG && DEBUG_ALERT + ---help--- + Enables verbose debug output when a usage fault is occurs. This verbose + output is sometimes helpful when debugging difficult usage fault problems, + but may be more than you typically want to see. + config ARM_SEMIHOSTING_SYSLOG bool "Semihosting SYSLOG support" select ARCH_SYSLOG diff --git a/arch/arm/src/armv8-m/arm_hardfault.c b/arch/arm/src/armv8-m/arm_hardfault.c index dd413c30e8..c730d1e87c 100644 --- a/arch/arm/src/armv8-m/arm_hardfault.c +++ b/arch/arm/src/armv8-m/arm_hardfault.c @@ -34,6 +34,7 @@ #include "arm_arch.h" #include "nvic.h" +#include "sau.h" #include "arm_internal.h" /**************************************************************************** @@ -75,6 +76,9 @@ int arm_hardfault(int irq, FAR void *context, FAR void *arg) { uint32_t hfsr = getreg32(NVIC_HFAULTS); uint32_t cfsr = getreg32(NVIC_CFAULTS); +#ifdef CONFIG_DEBUG_SECUREFAULT + uint32_t sfsr = getreg32(SAU_SFSR); +#endif /* CONFIG_DEBUG_SECUREFAULT */ UNUSED(cfsr); @@ -146,6 +150,13 @@ int arm_hardfault(int irq, FAR void *context, FAR void *arg) return arm_usagefault(irq, context, arg); } #endif /* CONFIG_DEBUG_USAGEFAULT */ + +#ifdef CONFIG_DEBUG_SECUREFAULT + if (sfsr & SAU_SFSR_MASK) + { + return arm_securefault(irq, context, arg); + } +#endif /* CONFIG_DEBUG_SECUREFAULT */ } /* Dump some hard fault info */ diff --git a/arch/arm/src/armv8-m/arm_securefault.c b/arch/arm/src/armv8-m/arm_securefault.c new file mode 100644 index 0000000000..39adb9f4ee --- /dev/null +++ b/arch/arm/src/armv8-m/arm_securefault.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * arch/arm/src/armv8-m/arm_securefault.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "arm_arch.h" +#include "nvic.h" +#include "sau.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_SECUREFAULT +# define sfalert(format, ...) _alert(format, ##__VA_ARGS__) +#else +# define sfalert(...) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_securefault + * + * Description: + * This is Secure Fault exception handler. It also catches SVC call + * exceptions that are performed in bad contexts. + * + ****************************************************************************/ + +int arm_securefault(int irq, FAR void *context, FAR void *arg) +{ + uint32_t sfsr = getreg32(SAU_SFSR); + + sfalert("PANIC!!! Secure Fault:\n"); + sfalert("\tIRQ: %d regs: %p\n", irq, context); + sfalert("\tBASEPRI: %08x PRIMASK: %08x IPSR: %08x CONTROL: %08x\n", + getbasepri(), getprimask(), getipsr(), getcontrol()); + sfalert("\tCFSR: %08x HFSR: %08x DFSR: %08x\n", getreg32(NVIC_CFAULTS), + getreg32(NVIC_HFAULTS), getreg32(NVIC_DFAULTS)); + sfalert("\tBFAR: %08x AFSR: %08x SFAR: %08x\n", + getreg32(NVIC_BFAULT_ADDR), getreg32(NVIC_AFAULTS), + getreg32(SAU_SFAR)); + + sfalert("Secure Fault Reason:\n"); + if (sfsr & SAU_SFSR_INVEP) + { + sfalert("\tInvalid entry point\n"); + } + + if (sfsr & SAU_SFSR_INVIS) + { + sfalert("\tInvalid integrity signature\n"); + } + + if (sfsr & SAU_SFSR_INVER) + { + sfalert("\tInvalid exception return\n"); + } + + if (sfsr & SAU_SFSR_AUVIOL) + { + sfalert("\tAttribution unit violation\n"); + } + + if (sfsr & SAU_SFSR_INVTRAN) + { + sfalert("\tInvalid transition\n"); + } + + if (sfsr & SAU_SFSR_LSPERR) + { + sfalert("\tLazy state preservation\n"); + } + + if (sfsr & SAU_SFSR_LSERR) + { + sfalert("\tLazy state error\n"); + } + + /* clear SFSR sticky bits */ + + putreg32(0xff, SAU_SFSR); + + up_irq_save(); + PANIC(); + return OK; +} diff --git a/arch/arm/src/armv8-m/sau.h b/arch/arm/src/armv8-m/sau.h index 2fcefd8f9e..9c3601d06b 100644 --- a/arch/arm/src/armv8-m/sau.h +++ b/arch/arm/src/armv8-m/sau.h @@ -81,6 +81,19 @@ #define SAU_RLAR_NSC (1 << 1) /* Bit 1: Non-secure callable */ #define SAU_RLAR_LIMIT_MASK 0xffffffe0 /* Bits 5-31: Region limit address */ +/* Secure Fault Status Register Definitions */ + +#define SAU_SFSR_MASK (0xf) /* Secure Fault Status Register Mask */ + +#define SAU_SFSR_INVEP (1 << 0) /* Bit 0: INVEP Mask */ +#define SAU_SFSR_INVIS (1 << 1) /* Bit 1: INVIS Mask */ +#define SAU_SFSR_INVER (1 << 2) /* Bit 2: INVER Mask */ +#define SAU_SFSR_AUVIOL (1 << 3) /* Bit 3: AUVIOL Mask */ +#define SAU_SFSR_INVTRAN (1 << 4) /* Bit 4: INVTRAN Mask */ +#define SAU_SFSR_LSPERR (1 << 5) /* Bit 5: LSPERR Mask */ +#define SAU_SFSR_SFARVALID (1 << 6) /* Bit 6: SFARVALID Mask */ +#define SAU_SFSR_LSERR (1 << 7) /* Bit 7: LSERR Mask */ + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/arch/arm/src/common/arm_internal.h b/arch/arm/src/common/arm_internal.h index 457a146976..9ce2afd1fb 100644 --- a/arch/arm/src/common/arm_internal.h +++ b/arch/arm/src/common/arm_internal.h @@ -345,6 +345,7 @@ int arm_hardfault(int irq, FAR void *context, FAR void *arg); int arm_memfault(int irq, FAR void *context, FAR void *arg); int arm_busfault(int irq, FAR void *context, FAR void *arg); int arm_usagefault(int irq, FAR void *context, FAR void *arg); +int arm_securefault(int irq, FAR void *context, FAR void *arg); # endif /* CONFIG_ARCH_CORTEXM3,4,7 */