diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 663276c727f..525f741a78a 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -129,6 +129,10 @@ config XTENSA_HAVE_DCACHE_LOCK bool default n +config XTENSA_HAVE_EXCEPTION_HOOKS + bool + default n + config XTENSA_ICACHE bool "Use I-Cache" default n diff --git a/arch/xtensa/include/irq.h b/arch/xtensa/include/irq.h index fdad3b8211b..3f5afa43f9c 100644 --- a/arch/xtensa/include/irq.h +++ b/arch/xtensa/include/irq.h @@ -113,10 +113,19 @@ #ifndef __XTENSA_CALL0_ABI__ /* Temporary space for saving stuff during window spill. */ -# define REG_TMP0 (_REG_WINDOW_TMPS + 0) -# define _REG_OVLY_START (_REG_WINDOW_TMPS + 1) +# define REG_TMP0 (_REG_WINDOW_TMPS + 0) +# define _REG_INT_CTX_START (_REG_WINDOW_TMPS + 1) #else -# define _REG_OVLY_START _REG_WINDOW_TMPS +# define _REG_INT_CTX_START _REG_WINDOW_TMPS +#endif + +#ifndef CONFIG_BUILD_FLAT +/* Temporary space for saving Interrupt Context information */ + +# define REG_INT_CTX (_REG_INT_CTX_START + 0) +# define _REG_OVLY_START (_REG_INT_CTX_START + 1) +#else +# define _REG_OVLY_START _REG_INT_CTX_START #endif #ifdef CONFIG_XTENSA_USE_OVLY @@ -155,6 +164,9 @@ struct xcpt_syscall_s { uintptr_t sysreturn; /* The return PC */ +#ifndef CONFIG_BUILD_FLAT + uintptr_t int_ctx; /* Interrupt context */ +#endif }; #endif diff --git a/arch/xtensa/src/common/xtensa_int_handlers.S b/arch/xtensa/src/common/xtensa_int_handlers.S index e4f40f75515..bc61bfe1932 100644 --- a/arch/xtensa/src/common/xtensa_int_handlers.S +++ b/arch/xtensa/src/common/xtensa_int_handlers.S @@ -517,6 +517,55 @@ _xtensa_level6_handler: #endif /* XCHAL_EXCM_LEVEL >= 6 */ +#if XCHAL_HAVE_NMI + .section HANDLER_SECTION, "ax" + .type _xtensa_nmi_handler, @function + .global _xtensa_nmi_handler + .align 4 + +_xtensa_nmi_handler: + /* For now, just panic */ + + exception_entry XCHAL_NMILEVEL + + movi a2, XTENSA_NMI_EXCEPTION /* Argument 1: Error code */ + call0 _xtensa_panic /* Does not return */ + + .size _xtensa_nmi_handler, . -_xtensa_nmi_handler + +#endif /* XCHAL_HAVE_NMI */ + +#if XCHAL_HAVE_DEBUG + .section HANDLER_SECTION, "ax" + .type _xtensa_debug_handler, @function + .global _xtensa_debug_handler + .align 4 + +_xtensa_debug_handler: + + exception_entry XCHAL_DEBUGLEVEL + + movi a2, XTENSA_DEBUG_EXCEPTION /* Argument 1: Error code */ + call0 _xtensa_panic /* Does not return */ + + .size _xtensa_debug_handler, . -_xtensa_debug_handler + +#endif /* XCHAL_HAVE_DEBUG */ + + .section HANDLER_SECTION, "ax" + .type _xtensa_kernel_handler, @function + .global _xtensa_kernel_handler + .align 4 + +_xtensa_kernel_handler: + + exception_entry 1 + + movi a2, XTENSA_KERNEL_EXCEPTION /* Argument 1: Error code */ + call0 _xtensa_panic /* Does not return */ + + .size _xtensa_kernel_handler, . -_xtensa_kernel_handler + /**************************************************************************** * HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) LOW-LEVEL HANDLERS * diff --git a/arch/xtensa/src/common/xtensa_macros.S b/arch/xtensa/src/common/xtensa_macros.S index b101c8b843c..5519a60ad61 100644 --- a/arch/xtensa/src/common/xtensa_macros.S +++ b/arch/xtensa/src/common/xtensa_macros.S @@ -178,6 +178,13 @@ s32i a0, sp, (4 * REG_PS) rsr a0, EPC_1 + \level - 1 /* Save interruptee's PC */ s32i a0, sp, (4 * REG_PC) + +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + /* Perform chip-specific exception entry operations */ + + exception_entry_hook \level sp a0 +#endif + rsr a0, EXCSAVE_1 + \level - 1 /* Save interruptee's a0 */ s32i a0, sp, (4 * REG_A0) s32i a2, sp, (4 * REG_A2) @@ -199,6 +206,13 @@ ps_excp_write a0 \level l32i a0, a2, (4 * REG_PC) /* Retrieve interruptee's PC */ wsr a0, EPC_1 + \level - 1 + +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + /* Perform chip-specific exception exit operations */ + + exception_exit_hook \level a2 a0 a1 +#endif + l32i a0, a2, (4 * REG_A0) /* Retrieve interruptee's A0 */ l32i sp, a2, (4 * REG_A1) /* Retrieve interrupt stack frame */ l32i a2, a2, (4 * REG_A2) /* Retrieve interruptee's A2 */ diff --git a/arch/xtensa/src/common/xtensa_schedsigaction.c b/arch/xtensa/src/common/xtensa_schedsigaction.c index 41c8dfcf72d..fcfb906edae 100644 --- a/arch/xtensa/src/common/xtensa_schedsigaction.c +++ b/arch/xtensa/src/common/xtensa_schedsigaction.c @@ -32,10 +32,11 @@ #include #include -#include "sched/sched.h" -#include "xtensa.h" - #include "irq/irq.h" +#include "sched/sched.h" + +#include "chip.h" +#include "xtensa.h" /**************************************************************************** * Public Functions @@ -155,6 +156,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE | PS_CALLINC(1)); #endif +#ifndef CONFIG_BUILD_FLAT + xtensa_raiseprivilege(CURRENT_REGS); +#endif CURRENT_REGS[REG_A1] = (uint32_t)CURRENT_REGS + XCPTCONTEXT_SIZE; @@ -200,6 +204,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_PS] = (uint32_t) (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE | PS_CALLINC(1)); +#endif +#ifndef CONFIG_BUILD_FLAT + xtensa_raiseprivilege(tcb->xcp.regs); #endif } } @@ -306,6 +313,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_PS] = (uint32_t) (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE | PS_CALLINC(1)); +#endif +#ifndef CONFIG_BUILD_FLAT + xtensa_raiseprivilege(tcb->xcp.regs); #endif } else @@ -348,6 +358,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_PS] = (uint32_t) (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE | PS_CALLINC(1)); +#endif +#ifndef CONFIG_BUILD_FLAT + xtensa_raiseprivilege(CURRENT_REGS); #endif } @@ -422,6 +435,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_PS] = (uint32_t) (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE | PS_CALLINC(1)); +#endif +#ifndef CONFIG_BUILD_FLAT + xtensa_raiseprivilege(tcb->xcp.regs); #endif } } diff --git a/arch/xtensa/src/common/xtensa_swint.c b/arch/xtensa/src/common/xtensa_swint.c index 731bf804c3b..682f65c6be0 100644 --- a/arch/xtensa/src/common/xtensa_swint.c +++ b/arch/xtensa/src/common/xtensa_swint.c @@ -24,16 +24,16 @@ #include -#include #include #include +#include -#include #include +#include #include +#include "chip.h" #include "signal/signal.h" -#include "syscall.h" #include "xtensa.h" /**************************************************************************** @@ -84,13 +84,8 @@ int xtensa_swint(int irq, void *context, void *arg) */ #ifdef CONFIG_DEBUG_SYSCALL_INFO -# ifndef CONFIG_DEBUG_SYSCALL - if (cmd > SYS_switch_context) -# endif - { - svcinfo("SYSCALL Entry: regs: %p cmd: %d\n", regs, cmd); - xtensa_registerdump(regs); - } + svcinfo("SYSCALL Entry: regs: %p cmd: %" PRIu32 "\n", regs, cmd); + xtensa_registerdump(regs); #endif /* Handle the syscall according to the command in A2 */ @@ -193,6 +188,9 @@ int xtensa_swint(int irq, void *context, void *arg) */ regs[REG_PC] = rtcb->xcp.syscall[index].sysreturn; +#ifndef CONFIG_BUILD_FLAT + xtensa_restoreprivilege(regs, rtcb->xcp.syscall[index].int_ctx); +#endif /* The return value must be in A2-A5. * xtensa_dispatch_syscall() temporarily moved the value into A3. @@ -249,6 +247,10 @@ int xtensa_swint(int irq, void *context, void *arg) regs[REG_A7] = regs[REG_A5]; /* argv */ #endif + /* Execute the task in User mode */ + + xtensa_lowerprivilege(regs); /* User mode */ + /* User task rotates window, so pretend task was 'call4'd */ regs[REG_PS] = PS_UM | PS_WOE | PS_CALLINC(1); @@ -285,6 +287,10 @@ int xtensa_swint(int irq, void *context, void *arg) regs[REG_A6] = regs[REG_A4]; /* pthread entry */ regs[REG_A7] = regs[REG_A5]; /* arg */ + /* Execute the pthread in User mode */ + + xtensa_lowerprivilege(regs); /* User mode */ + /* Startup task rotates window, so pretend task was 'call4'd */ regs[REG_PS] = PS_UM | PS_WOE | PS_CALLINC(1); @@ -322,6 +328,8 @@ int xtensa_swint(int irq, void *context, void *arg) regs[REG_PC] = (uintptr_t)USERSPACE->signal_handler; + xtensa_lowerprivilege(regs); /* User mode */ + /* Change the parameter ordering to match the expectation of struct * userpace_s signal_handler. */ @@ -353,6 +361,8 @@ int xtensa_swint(int irq, void *context, void *arg) DEBUGASSERT(rtcb->xcp.sigreturn != 0); regs[REG_PC] = rtcb->xcp.sigreturn; + xtensa_raiseprivilege(regs); /* Privileged mode */ + rtcb->xcp.sigreturn = 0; } break; @@ -382,11 +392,18 @@ int xtensa_swint(int irq, void *context, void *arg) /* Setup to return to xtensa_dispatch_syscall in privileged mode. */ rtcb->xcp.syscall[index].sysreturn = regs[REG_PC]; +#ifndef CONFIG_BUILD_FLAT + xtensa_saveprivilege(regs, rtcb->xcp.syscall[index].int_ctx); +#endif rtcb->xcp.nsyscalls = index + 1; regs[REG_PC] = (uintptr_t)xtensa_dispatch_syscall; +#ifndef CONFIG_BUILD_FLAT + xtensa_raiseprivilege(regs); /* Privileged mode */ +#endif + /* Offset A2 to account for the reserved values */ regs[REG_A2] -= CONFIG_SYS_RESERVED; @@ -428,21 +445,15 @@ int xtensa_swint(int irq, void *context, void *arg) */ #ifdef CONFIG_DEBUG_SYSCALL_INFO -# ifndef CONFIG_DEBUG_SYSCALL - if (cmd > SYS_switch_context) -# else if (regs != CURRENT_REGS) -# endif { svcinfo("SYSCALL Return: Context switch!\n"); xtensa_registerdump((const uintptr_t *)CURRENT_REGS); } -# ifdef CONFIG_DEBUG_SYSCALL else { svcinfo("SYSCALL Return: %" PRIu32 "\n", cmd); } -# endif #endif return OK; diff --git a/arch/xtensa/src/common/xtensa_vectors.S b/arch/xtensa/src/common/xtensa_vectors.S index 2b4ae270048..46a24ab47ac 100644 --- a/arch/xtensa/src/common/xtensa_vectors.S +++ b/arch/xtensa/src/common/xtensa_vectors.S @@ -183,30 +183,16 @@ _xtensa_level6_vector: .begin literal_prefix .nmi_vector .section .nmi_vector.text, "ax" .global _xtensa_nmi_vector + .global _xtensa_nmi_handler .type _xtensa_nmi_vector, @function .align 4 _xtensa_nmi_vector: + wsr a0, EXCSAVE + XCHAL_NMILEVEL /* Preserve a0 */ + call0 _xtensa_nmi_handler -#if 1 - /* For now, just panic */ - - wsr a0, EXCSAVE + XCHAL_NMILEVEL /* Preserve a0 */ - - exception_entry XCHAL_NMILEVEL - - movi a2, XTENSA_NMI_EXCEPTION /* Argument 1: Error code */ - call0 _xtensa_panic /* Does not return */ - -#else - /* Add high priority non-maskable interrupt (NMI) handler code here. */ - - rfi XCHAL_NMILEVEL - -#endif - - .size _xtensa_nmi_vector, . - _xtensa_nmi_vector - .end literal_prefix + .size _xtensa_nmi_vector, . - _xtensa_nmi_vector + .end literal_prefix #endif /* XCHAL_HAVE_NMI */ @@ -222,16 +208,15 @@ _xtensa_nmi_vector: .begin literal_prefix .debug_exception_vector .section .debug_exception_vector.text, "ax" .global _debug_exception_vector + .global _xtensa_debug_handler + .type _debug_exception_vector, @function .align 4 _debug_exception_vector: - wsr a0, EXCSAVE + XCHAL_DEBUGLEVEL /* Preserve a0 */ - - exception_entry XCHAL_DEBUGLEVEL - - movi a2, XTENSA_DEBUG_EXCEPTION /* Argument 1: Error code */ - call0 _xtensa_panic /* Does not return */ + wsr a0, EXCSAVE + XCHAL_DEBUGLEVEL /* Preserve a0 */ + call0 _xtensa_debug_handler + .size _debug_exception_vector, . - _debug_exception_vector .end literal_prefix #endif /* XCHAL_HAVE_DEBUG */ @@ -299,6 +284,8 @@ _double_exception_vector: .begin literal_prefix .kernel_exception_vector .section .kernel_exception_vector.text, "ax" .global _kernel_exception_vector + .global _xtensa_kernel_handler + .type _kernel_exception_vector, @function .align 4 _kernel_exception_vector: @@ -308,12 +295,9 @@ _kernel_exception_vector: #endif wsr a0, EXCSAVE_1 /* Preserve a0 */ + call0 _xtensa_kernel_handler - exception_entry 1 - - movi a2, XTENSA_KERNEL_EXCEPTION /* Argument 1: Error code */ - call0 _xtensa_panic /* Does not return */ - + .size _kernel_exception_vector, . - _kernel_exception_vector .end literal_prefix /**************************************************************************** diff --git a/arch/xtensa/src/common/xtensa_window_vector.S b/arch/xtensa/src/common/xtensa_window_vector.S index 5be6c079e3c..997c203bea1 100644 --- a/arch/xtensa/src/common/xtensa_window_vector.S +++ b/arch/xtensa/src/common/xtensa_window_vector.S @@ -31,12 +31,14 @@ * ****************************************************************************/ - .file "xtensa_vectors.S" + .file "xtensa_window_vector.S" /**************************************************************************** * Included Files ****************************************************************************/ +#include + #include #include #include @@ -96,7 +98,11 @@ _window_overflow4: s32e a1, a5, -12 /* Save a1 to call[j+1]'s stack frame */ s32e a2, a5, -8 /* Save a2 to call[j+1]'s stack frame */ s32e a3, a5, -4 /* Save a3 to call[j+1]'s stack frame */ +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + j _overflow4_exit_hook +#else rfwo /* Rotates back to call[i] position */ +#endif /* Window Underflow Exception for Call4 * @@ -119,7 +125,11 @@ _window_underflow4: l32e a1, a5, -12 /* Restore a1 from call[i+1]'s stack frame */ l32e a2, a5, -8 /* Restore a2 from call[i+1]'s stack frame */ l32e a3, a5, -4 /* Restore a3 from call[i+1]'s stack frame */ +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + j _underflow4_exit_hook +#else rfwu +#endif /* Handle alloca exception generated by interruptee executing 'movsp'. * This uses space between the window vectors, so is essentially "free". @@ -178,7 +188,11 @@ _window_overflow8: s32e a5, a0, -28 /* Save a5 to call[j]'s stack frame */ s32e a6, a0, -24 /* Save a6 to call[j]'s stack frame */ s32e a7, a0, -20 /* Save a7 to call[j]'s stack frame */ +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + j _overflow8_exit_hook +#else rfwo /* Rotates back to call[i] position */ +#endif /* Window Underflow Exception for Call8 * @@ -207,7 +221,11 @@ _window_underflow8: l32e a5, a7, -28 /* Restore a5 from call[i]'s stack frame */ l32e a6, a7, -24 /* Restore a6 from call[i]'s stack frame */ l32e a7, a7, -20 /* Restore a7 from call[i]'s stack frame */ +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + j _underflow8_exit_hook +#else rfwu +#endif /* Window Overflow Exception for Call12 * diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index 98db1623bc4..4883ccf11b4 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -541,6 +541,13 @@ config ESP32_AES_ACCELERATOR bool "AES Accelerator" default n +config ESP32_PID + bool "PID Controller" + default n + select ARCH_USE_MPU + select XTENSA_HAVE_EXCEPTION_HOOKS if BUILD_PROTECTED + depends on EXPERIMENTAL + endmenu # ESP32 Peripheral Selection config ESP32_WIFI_BT_COEXIST diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs index 7b8a1313dc8..9de37891042 100644 --- a/arch/xtensa/src/esp32/Make.defs +++ b/arch/xtensa/src/esp32/Make.defs @@ -23,7 +23,11 @@ include common/Make.defs # The start-up, "head", file. May be either a .S or a .c file. -HEAD_CSRC = esp32_start.c esp32_wdt.c +HEAD_CSRC = esp32_start.c esp32_wdt.c + +ifeq ($(CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS),y) +HEAD_ASRC += esp32_window_hooks.S +endif # Required ESP32 files (arch/xtensa/src/esp32) diff --git a/arch/xtensa/src/esp32/chip_macros.h b/arch/xtensa/src/esp32/chip_macros.h index 8613b33674b..e5fe6a7c89e 100644 --- a/arch/xtensa/src/esp32/chip_macros.h +++ b/arch/xtensa/src/esp32/chip_macros.h @@ -39,6 +39,10 @@ #include +#if defined(CONFIG_ESP32_PID) && defined(CONFIG_BUILD_PROTECTED) +#include "hardware/esp32_pid.h" +#endif + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -49,6 +53,23 @@ #define HANDLER_SECTION .iram1 +#if defined(CONFIG_ESP32_PID) && defined(CONFIG_BUILD_PROTECTED) + +/* Definitions for the PIDs reserved for Kernel and Userspace */ + +#define PIDCTRL_PID_KERNEL 0 /* Privileged */ +#define PIDCTRL_PID_USER 5 /* Non-privileged */ + +/* Macros for privilege handling with the PID Controller peripheral */ + +#define xtensa_saveprivilege(regs,var) ((var) = (regs)[REG_INT_CTX]) +#define xtensa_restoreprivilege(regs,var) ((regs)[REG_INT_CTX] = (var)) + +#define xtensa_lowerprivilege(regs) ((regs)[REG_INT_CTX] = PIDCTRL_PID_USER) +#define xtensa_raiseprivilege(regs) ((regs)[REG_INT_CTX] = PIDCTRL_PID_KERNEL) + +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -95,6 +116,116 @@ l32i a1, \tmp2, 0 /* a1 = *tmp2 */ .endm #endif + +/**************************************************************************** + * Name: get_prev_pid + * + * Description: + * Retrieve PID information from interruptee. + * + * Entry Conditions: + * level - Interrupt level + * out - Temporary and output register + * + * Exit Conditions: + * PID value to be returned will be written to "out" register. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32_PID + .macro get_prev_pid level out + movi \out, PIDCTRL_FROM_1_REG + (\level - 1) * 0x4 + l32i \out, \out, 0 + extui \out, \out, 0, 3 + .endm +#endif + +/**************************************************************************** + * Name: set_next_pid + * + * Description: + * Configure the PID Controller for the new execution context. + * + * Entry Conditions: + * in - PID to be set + * tmp - Temporary register + * + * Exit Conditions: + * Register "in" has been trashed. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32_PID + .macro set_next_pid in tmp + movi \tmp, PIDCTRL_PID_NEW_REG + s32i \in, \tmp, 0 /* Set new PID */ + + movi \tmp, PIDCTRL_PID_DELAY_REG + movi \in, 0x0 + s32i \in, \tmp, 0 /* Set delay (cycles) for PID change */ + + movi \tmp, PIDCTRL_PID_CONFIRM_REG + movi \in, 0x1 + s32i \in, \tmp, 0 /* Confirm change to the new PID */ + .endm +#endif + +/**************************************************************************** + * Name: exception_entry_hook + * + * Description: + * Perform chip-specific exception entry operations. + * + * Entry Conditions: + * level - Interrupt level + * reg_sp - Stack pointer + * tmp - Temporary register + * + ****************************************************************************/ + +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + .macro exception_entry_hook level reg_sp tmp + + /* Save PID information from interruptee when handling User (Level 1) and + * Software-triggered interrupts (Level 3). + */ + + .ifeq (\level - 1) & (\level - 3) + get_prev_pid \level \tmp + s32i \tmp, \reg_sp, (4 * REG_INT_CTX) /* Save PID into context area */ + .endif + .endm +#endif + +/**************************************************************************** + * Name: exception_exit_hook + * + * Description: + * Perform chip-specific exception exit operations. + * + * Entry Conditions: + * level - Interrupt level + * reg_sp - Stack pointer + * tmp1 - Temporary register 1 + * tmp2 - Temporary register 2 + * + ****************************************************************************/ + +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + .macro exception_exit_hook level reg_sp tmp1 tmp2 + + /* Configure the PID Controller for the new execution context before + * returning from User (Level 1) and Software-triggered interrupts + * (Level 3). + */ + + .ifeq (\level - 1) & (\level - 3) + l32i \tmp1, \reg_sp, (4 * REG_INT_CTX) + set_next_pid \tmp1 \tmp2 + .endif + .endm +#endif + #endif /* __ASSEMBLY */ /**************************************************************************** diff --git a/arch/xtensa/src/esp32/esp32_start.c b/arch/xtensa/src/esp32/esp32_start.c index 420ac161c38..cbcb858ebe2 100644 --- a/arch/xtensa/src/esp32/esp32_start.c +++ b/arch/xtensa/src/esp32/esp32_start.c @@ -141,6 +141,7 @@ uint32_t g_idlestack[IDLETHREAD_STACKWORDS] static noreturn_function void __esp32_start(void) { uint32_t sp; + uint32_t regval unused_data; /* Make sure that normal interrupts are disabled. This is really only an * issue when we are started in un-usual ways (such as from IRAM). In this @@ -163,17 +164,31 @@ static noreturn_function void __esp32_start(void) esp32_region_protection(); +#if defined(CONFIG_ESP32_PID) && defined(CONFIG_BUILD_PROTECTED) + /* We have 2 VECBASE Addresses: one in CPU and one in DPORT peripheral. + * CPU has no knowledge of PID hence any PID can change the CPU VECBASE + * address thus jumping to malicious interrupt vectors with higher + * privilege. + * So we configure CPU to use the VECBASE address in DPORT peripheral. + */ + + regval = ((uint32_t)&_init_start) >> 10; + putreg32(regval, DPORT_PRO_VECBASE_SET_REG); + + regval = getreg32(DPORT_PRO_VECBASE_CTRL_REG); + regval |= BIT(0) | BIT(1); + putreg32(regval, DPORT_PRO_VECBASE_CTRL_REG); +#else /* Move CPU0 exception vectors to IRAM */ - __asm__ __volatile__ ("wsr %0, vecbase\n"::"r" (&_init_start)); + __asm__ __volatile__ ("wsr %0, vecbase\n"::"r"(&_init_start)); +#endif /* Set .bss to zero */ memset(&_sbss, 0, (&_ebss - &_sbss) * sizeof(_sbss)); #ifndef CONFIG_SMP - uint32_t regval; - /* Make sure that the APP_CPU is disabled for now */ regval = getreg32(DPORT_APPCPU_CTRL_B_REG); diff --git a/arch/xtensa/src/esp32/esp32_userspace.c b/arch/xtensa/src/esp32/esp32_userspace.c index 812bbc84ca5..fdf9e30d198 100755 --- a/arch/xtensa/src/esp32/esp32_userspace.c +++ b/arch/xtensa/src/esp32/esp32_userspace.c @@ -33,9 +33,12 @@ #include +#include "chip.h" +#include "xtensa.h" #include "xtensa_attr.h" #include "esp32_userspace.h" #include "hardware/esp32_dport.h" +#include "hardware/esp32_pid.h" #ifdef CONFIG_BUILD_PROTECTED @@ -153,18 +156,34 @@ static noinline_function IRAM_ATTR void configure_flash_mmu(void) drom_lma_aligned = app_drom_lma & MMU_FLASH_MASK; drom_vma_aligned = app_drom_vma & MMU_FLASH_MASK; drom_page_count = calc_mmu_pages(app_drom_size, app_drom_vma); - DEBUGVERIFY(cache_flash_mmu_set(0, 0, drom_vma_aligned, drom_lma_aligned, - 64, (int)drom_page_count)); - DEBUGVERIFY(cache_flash_mmu_set(1, 0, drom_vma_aligned, drom_lma_aligned, - 64, (int)drom_page_count)); + ASSERT(cache_flash_mmu_set(0, PIDCTRL_PID_KERNEL, drom_vma_aligned, + drom_lma_aligned, 64, + (int)drom_page_count) == 0); + ASSERT(cache_flash_mmu_set(1, PIDCTRL_PID_KERNEL, drom_vma_aligned, + drom_lma_aligned, 64, + (int)drom_page_count) == 0); + ASSERT(cache_flash_mmu_set(0, PIDCTRL_PID_USER, drom_vma_aligned, + drom_lma_aligned, 64, + (int)drom_page_count) == 0); + ASSERT(cache_flash_mmu_set(1, PIDCTRL_PID_USER, drom_vma_aligned, + drom_lma_aligned, 64, + (int)drom_page_count) == 0); irom_lma_aligned = app_irom_lma & MMU_FLASH_MASK; irom_vma_aligned = app_irom_vma & MMU_FLASH_MASK; irom_page_count = calc_mmu_pages(app_irom_size, app_irom_vma); - DEBUGVERIFY(cache_flash_mmu_set(0, 0, irom_vma_aligned, irom_lma_aligned, - 64, (int)irom_page_count)); - DEBUGVERIFY(cache_flash_mmu_set(1, 0, irom_vma_aligned, irom_lma_aligned, - 64, (int)irom_page_count)); + ASSERT(cache_flash_mmu_set(0, PIDCTRL_PID_KERNEL, irom_vma_aligned, + irom_lma_aligned, 64, + (int)irom_page_count) == 0); + ASSERT(cache_flash_mmu_set(1, PIDCTRL_PID_KERNEL, irom_vma_aligned, + irom_lma_aligned, 64, + (int)irom_page_count) == 0); + ASSERT(cache_flash_mmu_set(0, PIDCTRL_PID_USER, irom_vma_aligned, + irom_lma_aligned, 64, + (int)irom_page_count) == 0); + ASSERT(cache_flash_mmu_set(1, PIDCTRL_PID_USER, irom_vma_aligned, + irom_lma_aligned, 64, + (int)irom_page_count) == 0); cache_read_enable(0); } @@ -195,8 +214,8 @@ static noinline_function IRAM_ATTR const void *map_flash(uint32_t src_addr, src_addr_aligned = src_addr & MMU_FLASH_MASK; page_count = calc_mmu_pages(size, src_addr); - DEBUGVERIFY(cache_flash_mmu_set(0, 0, MMU_BLOCK50_VADDR, src_addr_aligned, - 64, (int)page_count)); + ASSERT(cache_flash_mmu_set(0, PIDCTRL_PID_KERNEL, MMU_BLOCK50_VADDR, + src_addr_aligned, 64, (int)page_count) == 0); cache_read_enable(0); @@ -279,6 +298,71 @@ static void initialize_data(void) static void configure_mpu(void) { + /* 8K page size for mappings both IRAM and DRAM */ + + REG_SET_FIELD(DPORT_IMMU_PAGE_MODE_REG, DPORT_IMMU_PAGE_MODE, 0); + REG_SET_FIELD(DPORT_DMMU_PAGE_MODE_REG, DPORT_DMMU_PAGE_MODE, 0); + + /* 1:1 mapping for IRAM */ + + REG_SET_FIELD(DPORT_IMMU_TABLE0_REG, DPORT_IMMU_TABLE0, 0x00); + REG_SET_FIELD(DPORT_IMMU_TABLE1_REG, DPORT_IMMU_TABLE1, 0x51); + REG_SET_FIELD(DPORT_IMMU_TABLE2_REG, DPORT_IMMU_TABLE2, 0x52); + REG_SET_FIELD(DPORT_IMMU_TABLE3_REG, DPORT_IMMU_TABLE3, 0x53); + REG_SET_FIELD(DPORT_IMMU_TABLE4_REG, DPORT_IMMU_TABLE4, 0x54); + REG_SET_FIELD(DPORT_IMMU_TABLE5_REG, DPORT_IMMU_TABLE5, 0x55); + REG_SET_FIELD(DPORT_IMMU_TABLE6_REG, DPORT_IMMU_TABLE6, 0x56); + REG_SET_FIELD(DPORT_IMMU_TABLE7_REG, DPORT_IMMU_TABLE7, 0x57); + REG_SET_FIELD(DPORT_IMMU_TABLE8_REG, DPORT_IMMU_TABLE8, 0x08); + REG_SET_FIELD(DPORT_IMMU_TABLE9_REG, DPORT_IMMU_TABLE9, 0x09); + REG_SET_FIELD(DPORT_IMMU_TABLE10_REG, DPORT_IMMU_TABLE10, 0x0a); + REG_SET_FIELD(DPORT_IMMU_TABLE11_REG, DPORT_IMMU_TABLE11, 0x0b); + REG_SET_FIELD(DPORT_IMMU_TABLE12_REG, DPORT_IMMU_TABLE12, 0x0c); + REG_SET_FIELD(DPORT_IMMU_TABLE13_REG, DPORT_IMMU_TABLE13, 0x0d); + REG_SET_FIELD(DPORT_IMMU_TABLE14_REG, DPORT_IMMU_TABLE14, 0x0e); + REG_SET_FIELD(DPORT_IMMU_TABLE15_REG, DPORT_IMMU_TABLE15, 0x0f); + + REG_SET_FIELD(DPORT_DMMU_TABLE0_REG, DPORT_DMMU_TABLE0, 0x00); + REG_SET_FIELD(DPORT_DMMU_TABLE1_REG, DPORT_DMMU_TABLE1, 0x01); + REG_SET_FIELD(DPORT_DMMU_TABLE2_REG, DPORT_DMMU_TABLE2, 0x02); + REG_SET_FIELD(DPORT_DMMU_TABLE3_REG, DPORT_DMMU_TABLE3, 0x03); + REG_SET_FIELD(DPORT_DMMU_TABLE4_REG, DPORT_DMMU_TABLE4, 0x54); + REG_SET_FIELD(DPORT_DMMU_TABLE5_REG, DPORT_DMMU_TABLE5, 0x55); + REG_SET_FIELD(DPORT_DMMU_TABLE6_REG, DPORT_DMMU_TABLE6, 0x56); + REG_SET_FIELD(DPORT_DMMU_TABLE7_REG, DPORT_DMMU_TABLE7, 0x57); + REG_SET_FIELD(DPORT_DMMU_TABLE8_REG, DPORT_DMMU_TABLE8, 0x58); + REG_SET_FIELD(DPORT_DMMU_TABLE9_REG, DPORT_DMMU_TABLE9, 0x59); + REG_SET_FIELD(DPORT_DMMU_TABLE10_REG, DPORT_DMMU_TABLE10, 0x5a); + REG_SET_FIELD(DPORT_DMMU_TABLE11_REG, DPORT_DMMU_TABLE11, 0x5b); + REG_SET_FIELD(DPORT_DMMU_TABLE12_REG, DPORT_DMMU_TABLE12, 0x5c); + REG_SET_FIELD(DPORT_DMMU_TABLE13_REG, DPORT_DMMU_TABLE13, 0x5d); + REG_SET_FIELD(DPORT_DMMU_TABLE14_REG, DPORT_DMMU_TABLE14, 0x5e); + REG_SET_FIELD(DPORT_DMMU_TABLE15_REG, DPORT_DMMU_TABLE15, 0x5f); + + /* Configure interrupt vector addresses in PID Controller */ + + putreg32(PIDCTRL_INTERRUPT_ENABLE_M, PIDCTRL_INTERRUPT_ENABLE_REG); + + /* Configure the PID Controller to switch to privileged mode (PID 0) when + * the CPU fetches instruction from the following interrupt vectors: + * 1) Level 1 + * 2) Window Overflow 4 + * 3) Level 3 (SWINT) + * 4) Window Underflow 4 + * 5) Window Overflow 8 + * 6) Window Underflow 8 + * 7) NMI + */ + + putreg32(VECTORS_START + 0x340, PIDCTRL_INTERRUPT_ADDR_1_REG); + putreg32(VECTORS_START + 0x000, PIDCTRL_INTERRUPT_ADDR_2_REG); + putreg32(VECTORS_START + 0x1c0, PIDCTRL_INTERRUPT_ADDR_3_REG); + putreg32(VECTORS_START + 0x040, PIDCTRL_INTERRUPT_ADDR_4_REG); + putreg32(VECTORS_START + 0x080, PIDCTRL_INTERRUPT_ADDR_5_REG); + putreg32(VECTORS_START + 0x0c0, PIDCTRL_INTERRUPT_ADDR_6_REG); + putreg32(VECTORS_START + 0x2c0, PIDCTRL_INTERRUPT_ADDR_7_REG); + + putreg32(0, PIDCTRL_LEVEL_REG); } /**************************************************************************** diff --git a/arch/xtensa/src/esp32/esp32_window_hooks.S b/arch/xtensa/src/esp32/esp32_window_hooks.S new file mode 100644 index 00000000000..bebb85cfe1b --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_window_hooks.S @@ -0,0 +1,134 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_window_hooks.S + * + * 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. + * + ****************************************************************************/ + + .file "esp32_window_hooks.S" + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip_macros.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS + /* PID Controller is configured to switch to PID 0 when the CPU fetches + * instruction from the following window exception vectors: + * - Window Overflow 4: mapped as Level 2 vector entry address + * - Window Underflow 4: mapped as Level 4 vector entry address + * - Window Overflow 8: mapped as Level 5 vector entry address + * - Window Underflow 8: mapped as Level 6 vector entry address + * + * See arch/xtensa/src/esp32/esp32_userspace.c + */ + +/**************************************************************************** + * Name: _overflow4_exit_hook + ****************************************************************************/ + + .section HANDLER_SECTION, "ax" + .global _overflow4_exit_hook + .type _overflow4_exit_hook, @function + .align 4 + +_overflow4_exit_hook: + wsr a0, misc0 + wsr a1, misc1 + + /* Restore PID to the same value prior to the exception */ + + get_prev_pid 2 a0 + set_next_pid a0 a1 + + rsr a0, misc0 + rsr a1, misc1 + rfwo /* rotates back to call[i] position */ + +/**************************************************************************** + * Name: _underflow4_exit_hook + ****************************************************************************/ + + .section HANDLER_SECTION, "ax" + .global _underflow4_exit_hook + .type _underflow4_exit_hook, @function + .align 4 + +_underflow4_exit_hook: + wsr a0, misc0 + wsr a1, misc1 + + /* Restore PID to the same value prior to the exception */ + + get_prev_pid 4 a0 + set_next_pid a0 a1 + + rsr a0, misc0 + rsr a1, misc1 + rfwu + +/**************************************************************************** + * Name: _overflow8_exit_hook + ****************************************************************************/ + + .section HANDLER_SECTION, "ax" + .global _overflow8_exit_hook + .type _overflow8_exit_hook, @function + .align 4 + +_overflow8_exit_hook: + wsr a0, misc0 + wsr a1, misc1 + + /* Restore PID to the same value prior to the exception */ + + get_prev_pid 5 a0 + set_next_pid a0 a1 + + rsr a0, misc0 + rsr a1, misc1 + rfwo /* rotates back to call[i] position */ + +/**************************************************************************** + * Name: _underflow8_exit_hook + ****************************************************************************/ + + .section HANDLER_SECTION, "ax" + .global _underflow8_exit_hook + .type _underflow8_exit_hook, @function + .align 4 + +_underflow8_exit_hook: + wsr a0, misc0 + wsr a1, misc1 + + /* Restore PID to the same value prior to the exception */ + + get_prev_pid 6 a0 + set_next_pid a0 a1 + + rsr a0, misc0 + rsr a1, misc1 + rfwu + +#endif /* CONFIG_XTENSA_HAVE_EXCEPTION_HOOKS */ diff --git a/arch/xtensa/src/esp32/hardware/esp32_pid.h b/arch/xtensa/src/esp32/hardware/esp32_pid.h new file mode 100644 index 00000000000..193070ad2a7 --- /dev/null +++ b/arch/xtensa/src/esp32/hardware/esp32_pid.h @@ -0,0 +1,127 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/hardware/esp32_pid.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_PID_H_ +#define __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_PID_H_ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define REG_PIDCTRL_BASE 0x3ff1f000 + +/* Bits 1..7: 1 if interrupt will be triggering PID change */ + +#define PIDCTRL_INTERRUPT_ENABLE_REG ((REG_PIDCTRL_BASE) + 0x000) + +/* PIDCTRL_INTERRUPT_ENABLE : R/W; bitpos: [7:1]; default: 0; + * These bits are used to enable interrupt identification and processing. + */ + +#define PIDCTRL_INTERRUPT_ENABLE 0x0000007f +#define PIDCTRL_INTERRUPT_ENABLE_M (PIDCTRL_INTERRUPT_ENABLE_V << PIDCTRL_INTERRUPT_ENABLE_S) +#define PIDCTRL_INTERRUPT_ENABLE_V 0x0000007f +#define PIDCTRL_INTERRUPT_ENABLE_S 1 + +/* Vectors for the various interrupt handlers */ + +#define PIDCTRL_INTERRUPT_ADDR_1_REG ((REG_PIDCTRL_BASE) + 0x004) +#define PIDCTRL_INTERRUPT_ADDR_2_REG ((REG_PIDCTRL_BASE) + 0x008) +#define PIDCTRL_INTERRUPT_ADDR_3_REG ((REG_PIDCTRL_BASE) + 0x00c) +#define PIDCTRL_INTERRUPT_ADDR_4_REG ((REG_PIDCTRL_BASE) + 0x010) +#define PIDCTRL_INTERRUPT_ADDR_5_REG ((REG_PIDCTRL_BASE) + 0x014) +#define PIDCTRL_INTERRUPT_ADDR_6_REG ((REG_PIDCTRL_BASE) + 0x018) +#define PIDCTRL_INTERRUPT_ADDR_7_REG ((REG_PIDCTRL_BASE) + 0x01c) + +/* Delay, in CPU cycles, before switching to new PID */ + +#define PIDCTRL_PID_DELAY_REG ((REG_PIDCTRL_BASE) + 0x020) + +/* PIDCTRL_PID_DELAY : R/W; bitpos: [11:0]; default: 20; + * Delay until newly assigned PID is valid. + */ + +#define PIDCTRL_PID_DELAY 0x00001fff +#define PIDCTRL_PID_DELAY_M (PIDCTRL_PID_DELAY_V << PIDCTRL_PID_DELAY_S) +#define PIDCTRL_PID_DELAY_V 0x00001fff +#define PIDCTRL_PID_DELAY_S 0 + +#define PIDCTRL_NMI_DELAY_REG ((REG_PIDCTRL_BASE) + 0x024) + +/* PIDCTRL_NMI_DELAY : R/W; bitpos: [11:0]; default: 16; + * Delay for disabling CPU NMI interrupt mask signal. + */ + +#define PIDCTRL_NMI_DELAY 0x00001fff +#define PIDCTRL_NMI_DELAY_M (PIDCTRL_NMI_DELAY_V << PIDCTRL_NMI_DELAY_S) +#define PIDCTRL_NMI_DELAY_V 0x00001fff +#define PIDCTRL_NMI_DELAY_S 0 + +/* Last detected interrupt. Set by hw on int. */ + +#define PIDCTRL_LEVEL_REG ((REG_PIDCTRL_BASE) + 0x028) + +/* PID/prev int data for each int */ + +#define PIDCTRL_FROM_REG(i) ((REG_PIDCTRL_BASE) + 0x028 + (0x4 * i)) + +#define PIDCTRL_FROM_1_REG ((REG_PIDCTRL_BASE) + 0x02c) +#define PIDCTRL_FROM_2_REG ((REG_PIDCTRL_BASE) + 0x030) +#define PIDCTRL_FROM_3_REG ((REG_PIDCTRL_BASE) + 0x034) +#define PIDCTRL_FROM_4_REG ((REG_PIDCTRL_BASE) + 0x038) +#define PIDCTRL_FROM_5_REG ((REG_PIDCTRL_BASE) + 0x03c) +#define PIDCTRL_FROM_6_REG ((REG_PIDCTRL_BASE) + 0x040) +#define PIDCTRL_FROM_7_REG ((REG_PIDCTRL_BASE) + 0x044) + +/* PIDCTRL_FROM_INT : R/W; bitpos: [6:3]; default: 0; + * Interrupt status of the system before the interrupt occurs. + */ + +#define PIDCTRL_FROM_INT 0x0000000f +#define PIDCTRL_FROM_INT_M (PIDCTRL_FROM_INT_V << PIDCTRL_FROM_INT_S) +#define PIDCTRL_FROM_INT_V 0x0000000f +#define PIDCTRL_FROM_INT_S 3 + +/* PIDCTRL_FROM_PID : R/W; bitpos: [2:0]; default: 0; + * Process running on the CPU before the interrupt occurs. + */ + +#define PIDCTRL_FROM_PID 0x00000007 +#define PIDCTRL_FROM_PID_M (PIDCTRL_FROM_PID_V << PIDCTRL_FROM_PID_S) +#define PIDCTRL_FROM_PID_V 0x00000007 +#define PIDCTRL_FROM_PID_S 0 + +/* PID to be set after confirm routine */ + +#define PIDCTRL_PID_NEW_REG ((REG_PIDCTRL_BASE) + 0x048) + +/* Write to kick off PID change */ + +#define PIDCTRL_PID_CONFIRM_REG ((REG_PIDCTRL_BASE) + 0x04c) + +/* Write to mask NMI */ + +#define PIDCTRL_NMI_MASK_ENABLE_REG ((REG_PIDCTRL_BASE) + 0x054) + +/* Write to unmask NMI */ + +#define PIDCTRL_NMI_MASK_DISABLE_REG ((REG_PIDCTRL_BASE) + 0x058) + +#endif /* __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_PID_H_ */ diff --git a/boards/xtensa/esp32/esp32-devkitc/configs/knsh/defconfig b/boards/xtensa/esp32/esp32-devkitc/configs/knsh/defconfig index e85a601fb0a..6058b287bba 100644 --- a/boards/xtensa/esp32/esp32-devkitc/configs/knsh/defconfig +++ b/boards/xtensa/esp32/esp32-devkitc/configs/knsh/defconfig @@ -18,7 +18,6 @@ CONFIG_ARCH_CHIP_ESP32=y CONFIG_ARCH_CHIP_ESP32WROVER=y CONFIG_ARCH_INTERRUPTSTACK=2048 CONFIG_ARCH_STACKDUMP=y -CONFIG_ARCH_USE_MPU=y CONFIG_ARCH_XTENSA=y CONFIG_BOARD_LOOPSPERMSEC=16717 CONFIG_BUILD_PROTECTED=y @@ -30,7 +29,9 @@ CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEBUG_WARN=y +CONFIG_ESP32_PID=y CONFIG_ESP32_UART0=y +CONFIG_EXPERIMENTAL=y CONFIG_FS_PROCFS=y CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y