From eba78548da50f0a027d18feb53991db58dce4b84 Mon Sep 17 00:00:00 2001 From: Wayne Ren Date: Wed, 20 Mar 2019 17:36:20 +0800 Subject: [PATCH] arch: arc: add the handling of mpu stack guard exception * mpu stack guard exception is a kind of mpu violation exception * use SW way to distingusih it from other mpu vioation exception Signed-off-by: Wayne Ren --- arch/arc/core/fatal.c | 2 +- arch/arc/core/fault.c | 103 ++++++++++++++++++++++++++++++++++++++++ arch/arc/core/fault_s.S | 7 +-- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/arch/arc/core/fatal.c b/arch/arc/core/fatal.c index 71a5437ee74..15bf65dce8b 100644 --- a/arch/arc/core/fatal.c +++ b/arch/arc/core/fatal.c @@ -43,7 +43,7 @@ void z_NanoFatalErrorHandler(unsigned int reason, const NANO_ESF *pEsf) break; #if defined(CONFIG_STACK_CANARIES) || defined(CONFIG_ARC_STACK_CHECKING) \ - || defined(CONFIG_STACK_SENTINEL) + || defined(CONFIG_STACK_SENTINEL) || defined(CONFIG_MPU_STACK_GUARD) case _NANO_ERR_STACK_CHK_FAIL: printk("***** Stack Check Fail! *****\n"); break; diff --git a/arch/arc/core/fault.c b/arch/arc/core/fault.c index 9d0d5a648cc..38d6a83e972 100644 --- a/arch/arc/core/fault.c +++ b/arch/arc/core/fault.c @@ -21,6 +21,8 @@ #include #include +extern u32_t arc_exc_saved_sp; + #ifdef CONFIG_USERSPACE Z_EXC_DECLARE(z_arch_user_string_nlen); @@ -29,6 +31,98 @@ static const struct z_exc_handle exceptions[] = { }; #endif +#if defined(CONFIG_MPU_STACK_GUARD) + +#define IS_MPU_GUARD_VIOLATION(guard_start, fault_addr, stack_ptr) \ + ((fault_addr >= guard_start) && \ + (fault_addr < (guard_start + STACK_GUARD_SIZE)) && \ + (stack_ptr <= (guard_start + STACK_GUARD_SIZE))) + +/** + * @brief Assess occurrence of current thread's stack corruption + * + * This function performs an assessment whether a memory fault (on a + * given memory address) is the result of stack memory corruption of + * the current thread. + * + * Thread stack corruption for supervisor threads or user threads in + * privilege mode (when User Space is supported) is reported upon an + * attempt to access the stack guard area (if MPU Stack Guard feature + * is supported). Additionally the current thread stack pointer + * must be pointing inside or below the guard area. + * + * Thread stack corruption for user threads in user mode is reported, + * if the current stack pointer is pointing below the start of the current + * thread's stack. + * + * Notes: + * - we assume a fully descending stack, + * - we assume a stacking error has occurred, + * - the function shall be called when handling MPU privilege violation + * + * If stack corruption is detected, the function returns the lowest + * allowed address where the Stack Pointer can safely point to, to + * prevent from errors when un-stacking the corrupted stack frame + * upon exception return. + * + * @param fault_addr memory address on which memory access violation + * has been reported. + * @param sp stack pointer when exception comes out + * + * @return The lowest allowed stack frame pointer, if error is a + * thread stack corruption, otherwise return 0. + */ +static u32_t z_check_thread_stack_fail(const u32_t fault_addr, u32_t sp) +{ + const struct k_thread *thread = _current; + + if (!thread) { + return 0; + } +#if defined(CONFIG_USERSPACE) + if (thread->arch.priv_stack_start) { + /* User thread */ + if (z_arc_v2_aux_reg_read(_ARC_V2_ERSTATUS) + & _ARC_V2_STATUS32_U) { + /* Thread's user stack corruption */ +#ifdef CONFIG_ARC_HAS_SECURE + sp = z_arc_v2_aux_reg_read(_ARC_V2_SEC_U_SP); +#else + sp = z_arc_v2_aux_reg_read(_ARC_V2_USER_SP); +#endif + if (sp <= (u32_t)thread->stack_obj) { + return (u32_t)thread->stack_obj; + } + } else { + /* User thread in privilege mode */ + if (IS_MPU_GUARD_VIOLATION( + thread->arch.priv_stack_start - STACK_GUARD_SIZE, + fault_addr, sp)) { + /* Thread's privilege stack corruption */ + return thread->arch.priv_stack_start; + } + } + } else { + /* Supervisor thread */ + if (IS_MPU_GUARD_VIOLATION((u32_t)thread->stack_obj, + fault_addr, sp)) { + /* Supervisor thread stack corruption */ + return (u32_t)thread->stack_obj + STACK_GUARD_SIZE; + } + } +#else /* CONFIG_USERSPACE */ + if (IS_MPU_GUARD_VIOLATION(thread->stack_info.start, + fault_addr, sp)) { + /* Thread stack corruption */ + return thread->stack_info.start + STACK_GUARD_SIZE; + } +#endif /* CONFIG_USERSPACE */ + + return 0; +} + +#endif + /* * @brief Fault handler * @@ -82,5 +176,14 @@ void _Fault(NANO_ESF *esf) return; } #endif + +#ifdef CONFIG_MPU_STACK_GUARD + if (vector == 6 && ((parameter == 4) || (parameter == 24))) { + if (z_check_thread_stack_fail(exc_addr, arc_exc_saved_sp)) { + z_NanoFatalErrorHandler(_NANO_ERR_STACK_CHK_FAIL, esf); + return; + } + } +#endif z_NanoFatalErrorHandler(_NANO_ERR_HW_EXCEPTION, esf); } diff --git a/arch/arc/core/fault_s.S b/arch/arc/core/fault_s.S index 04f51fd0c03..0c6e25d9a24 100644 --- a/arch/arc/core/fault_s.S +++ b/arch/arc/core/fault_s.S @@ -39,8 +39,9 @@ GTEXT(_irq_do_offload); #endif GDATA(exc_nest_count) +GDATA(arc_exc_saved_sWWp) -SECTION_VAR(BSS, saved_value) +SECTION_VAR(BSS, arc_exc_saved_sp) .balign 4 .word 0 @@ -65,7 +66,7 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error) SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned) _exc_entry: - st sp, [saved_value] + st sp, [arc_exc_saved_sp] /* * re-use the top part of interrupt stack as exception * stack. If this top part is used by interrupt handling, @@ -145,7 +146,7 @@ _exc_return_from_exc: sr r0, [_ARC_V2_ERET] _pop_irq_stack_frame - ld sp, [saved_value] + ld sp, [arc_exc_saved_sp] rtie