diff --git a/arch/arm/include/armv8-m/irq.h b/arch/arm/include/armv8-m/irq.h index 0c1809f13f..ed4620a265 100644 --- a/arch/arm/include/armv8-m/irq.h +++ b/arch/arm/include/armv8-m/irq.h @@ -72,8 +72,9 @@ #define REG_R9 (7) /* R9 */ #define REG_R10 (8) /* R10 */ #define REG_R11 (9) /* R11 */ -#define REG_EXC_RETURN (10) /* EXC_RETURN */ -#define SW_INT_REGS (11) +#define REG_CONTROL (10) /* CONTROL */ +#define REG_EXC_RETURN (11) /* EXC_RETURN */ +#define SW_INT_REGS (12) #ifdef CONFIG_ARCH_FPU diff --git a/arch/arm/src/armv8-m/arm_exception.S b/arch/arm/src/armv8-m/arm_exception.S index bec4f68b31..4ff4ee7fc0 100644 --- a/arch/arm/src/armv8-m/arm_exception.S +++ b/arch/arm/src/armv8-m/arm_exception.S @@ -146,6 +146,7 @@ exception_common: mrs r0, ipsr /* R0=exception number */ + mrs r12, control /* R12=control */ /* Complete the context save */ @@ -198,7 +199,7 @@ exception_common: subne sp, #(4*SW_FPU_REGS) #endif - stmdb sp!, {r2-r11,r14} /* Save the remaining registers plus the SP/PRIMASK values */ + stmdb sp!, {r2-r12,r14} /* Save the remaining registers plus the SP/PRIMASK values */ /* There are two arguments to arm_doirq: * @@ -243,7 +244,7 @@ exception_common: * array to use for the interrupt return. */ - ldmia r0!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */ + ldmia r0!, {r2-r12,r14} /* Recover R4-R12, r14 + 2 temp values */ #ifdef CONFIG_ARCH_FPU /* Switched-in task including volatile FP registers ? */ @@ -260,31 +261,6 @@ exception_common: /* The EXC_RETURN value tells us whether we are returning on the MSP or PSP */ -#ifdef CONFIG_BUILD_PROTECTED - /* The EXC_RETURN value will be 0xfffffff9 (privileged thread) or 0xfffffff1 - * (handler mode) if the stack is on the MSP. It can only be on the PSP if - * EXC_RETURN is 0xfffffffd (unprivileged thread) - */ - - mrs r2, control /* R2=Contents of the control register */ - tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ - beq 2f /* Branch if privileged */ - - orr r2, r2, #1 /* Unprivileged mode */ -#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE - msr psplim, r1 -#endif - msr psp, r0 /* R0=The process stack pointer */ - b 3f -2: - bic r2, r2, #1 /* Privileged mode */ -#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE - msr msplim, r1 -#endif - msr msp, r0 /* R0=The main stack pointer */ -3: - msr control, r2 /* Save the updated control register */ -#else tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ #ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE itete eq @@ -295,7 +271,6 @@ exception_common: #endif msreq msp, r0 /* R0=The main stack pointer */ msrne psp, r0 /* R0=The process stack pointer */ -#endif /* Restore the interrupt state */ @@ -305,6 +280,8 @@ exception_common: msr primask, r3 /* Restore interrupts */ #endif + msr control, r12 + /* Always return with R14 containing the special value that will: (1) * return to thread mode, and (2) select the correct stack. */ diff --git a/arch/arm/src/armv8-m/arm_initialstate.c b/arch/arm/src/armv8-m/arm_initialstate.c index dbaf0d2052..5ad73e3727 100644 --- a/arch/arm/src/armv8-m/arm_initialstate.c +++ b/arch/arm/src/armv8-m/arm_initialstate.c @@ -150,6 +150,8 @@ void up_initial_state(struct tcb_s *tcb) xcp->regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + xcp->regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; + #ifdef CONFIG_ARCH_FPU xcp->regs[REG_FPSCR] |= ARMV8M_FPSCR_LTPSIZE_NONE; #endif /* CONFIG_ARCH_FPU */ diff --git a/arch/arm/src/armv8-m/arm_schedulesigaction.c b/arch/arm/src/armv8-m/arm_schedulesigaction.c index 7459c7b578..0caf5ccbb7 100644 --- a/arch/arm/src/armv8-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv8-m/arm_schedulesigaction.c @@ -162,6 +162,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_BUILD_PROTECTED CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } } @@ -209,6 +210,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } } @@ -319,6 +321,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } else @@ -365,6 +368,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_XPSR] = ARMV8M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; + CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } @@ -431,6 +435,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } } diff --git a/arch/arm/src/armv8-m/arm_svcall.c b/arch/arm/src/armv8-m/arm_svcall.c index 70fc9643bd..f24ba53a69 100644 --- a/arch/arm/src/armv8-m/arm_svcall.c +++ b/arch/arm/src/armv8-m/arm_svcall.c @@ -145,12 +145,8 @@ int arm_svcall(int irq, void *context, void *arg) svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n", regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11], regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]); -# ifdef REG_EXC_RETURN - svcinfo(" PSR: %08x EXC_RETURN: %08x\n", - regs[REG_XPSR], regs[REG_EXC_RETURN]); -# else - svcinfo(" PSR: %08x\n", regs[REG_XPSR]); -# endif + svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n", + regs[REG_XPSR], regs[REG_EXC_RETURN], regs[REG_CONTROL]); } #endif @@ -276,6 +272,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)USERSPACE->task_startup & ~1; regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; + /* Return unprivileged mode */ + + regs[REG_CONTROL] = getcontrol() | CONTROL_NPRIV; + /* Change the parameter ordering to match the expectation of struct * userpace_s task_startup: */ @@ -310,6 +310,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)regs[REG_R1] & ~1; /* startup */ regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; + /* Return unprivileged mode */ + + regs[REG_CONTROL] = getcontrol() | CONTROL_NPRIV; + /* Change the parameter ordering to match the expectation of the * user space pthread_startup: */ @@ -351,6 +355,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)USERSPACE->signal_handler & ~1; regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; + /* Return unprivileged mode */ + + regs[REG_CONTROL] = getcontrol() | CONTROL_NPRIV; + /* Change the parameter ordering to match the expectation of struct * userpace_s signal_handler. */ @@ -383,6 +391,11 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = rtcb->xcp.sigreturn & ~1; regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + + /* Return privileged mode */ + + regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; + rtcb->xcp.sigreturn = 0; } break; @@ -418,6 +431,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)dispatch_syscall & ~1; regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + /* Return privileged mode */ + + regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; + /* Offset R0 to account for the reserved values */ regs[REG_R0] -= CONFIG_SYS_RESERVED; @@ -454,12 +471,9 @@ int arm_svcall(int irq, void *context, void *arg) CURRENT_REGS[REG_R10], CURRENT_REGS[REG_R11], CURRENT_REGS[REG_R12], CURRENT_REGS[REG_R13], CURRENT_REGS[REG_R14], CURRENT_REGS[REG_R15]); -# ifdef REG_EXC_RETURN - svcinfo(" PSR: %08x EXC_RETURN: %08x\n", - CURRENT_REGS[REG_XPSR], CURRENT_REGS[REG_EXC_RETURN]); -# else - svcinfo(" PSR: %08x\n", CURRENT_REGS[REG_XPSR]); -# endif + svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n", + CURRENT_REGS[REG_XPSR], CURRENT_REGS[REG_EXC_RETURN], + CURRENT_REGS[REG_CONTROL]); } # ifdef CONFIG_DEBUG_SVCALL else