diff --git a/arch/arm/include/armv6-m/irq.h b/arch/arm/include/armv6-m/irq.h index b7ea799fc4..e900b6b1c5 100644 --- a/arch/arm/include/armv6-m/irq.h +++ b/arch/arm/include/armv6-m/irq.h @@ -69,8 +69,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_XCPT_REGS (11) +#define REG_CONTROL (10) /* CONTROL */ +#define REG_EXC_RETURN (11) /* EXC_RETURN */ +#define SW_XCPT_REGS (12) /* The total number of registers saved by software */ diff --git a/arch/arm/src/armv6-m/arm_exception.S b/arch/arm/src/armv6-m/arm_exception.S index 595198b698..a2c6ce854b 100644 --- a/arch/arm/src/armv6-m/arm_exception.S +++ b/arch/arm/src/armv6-m/arm_exception.S @@ -141,14 +141,15 @@ exception_common: mov r0, r1 /* Copy the context array pointer */ stmia r0!, {r2-r7} /* Save the SP, PRIMASK, and R4-R7 in the context array */ - /* Save R8-R11 and the EXEC_RETURN value in the context array */ + /* Save R8-R11 control and the EXEC_RETURN value in the context array */ mov r2, r8 /* Copy high registers to low */ mov r3, r9 mov r4, r10 mov r5, r11 - mov r6, r14 - stmia r0!, {r2-r6} /* Save the high registers r8-r11 and r14 */ + mrs r6, control /* R6=control */ + mov r7, r14 + stmia r0!, {r2-r7} /* Save the high registers r8-r11 control and r14 */ /* Get the exception number in R0=IRQ, R1=register save area on stack */ @@ -188,12 +189,13 @@ exception_common: movs r2, #(4*REG_R8) /* R2=Offset to R8 storage */ adds r1, r0, r2 /* R1=Address of R8 storage */ - ldmia r1!, {r2-r6} /* Recover R8-R11 and R14 (5 registers)*/ + ldmia r1!, {r2-r7} /* Recover R8-R11 control and R14 (6 registers)*/ mov r8, r2 /* Move to position in high registers */ mov r9, r3 mov r10, r4 mov r11, r5 - mov r14, r6 /* EXEC_RETURN */ + msr control, r6 + mov r14, r7 /* EXEC_RETURN */ /* Recover SP (R2), PRIMASK (R3), and R4-R7. Determine the value of * the stack pointer as it was on entry to the exception handler. diff --git a/arch/arm/src/armv6-m/arm_initialstate.c b/arch/arm/src/armv6-m/arm_initialstate.c index c7639d26ed..fa730969c7 100644 --- a/arch/arm/src/armv6-m/arm_initialstate.c +++ b/arch/arm/src/armv6-m/arm_initialstate.c @@ -137,6 +137,8 @@ void up_initial_state(struct tcb_s *tcb) xcp->regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + xcp->regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; + /* Enable or disable interrupts, based on user configuration */ #ifdef CONFIG_SUPPRESS_INTERRUPTS diff --git a/arch/arm/src/armv6-m/arm_schedulesigaction.c b/arch/arm/src/armv6-m/arm_schedulesigaction.c index a9c25d883d..f03b9e535b 100644 --- a/arch/arm/src/armv6-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv6-m/arm_schedulesigaction.c @@ -157,6 +157,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 } } @@ -200,6 +201,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } } @@ -306,6 +308,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } else @@ -348,6 +351,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_XPSR] = ARMV6M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; + CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; #endif } @@ -406,6 +410,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_XPSR] = ARMV6M_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/armv6-m/arm_svcall.c b/arch/arm/src/armv6-m/arm_svcall.c index b9f96459fb..231c796301 100644 --- a/arch/arm/src/armv6-m/arm_svcall.c +++ b/arch/arm/src/armv6-m/arm_svcall.c @@ -264,6 +264,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)USERSPACE->task_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 struct * userpace_s task_startup: */ @@ -297,6 +301,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)regs[REG_R1]; /* 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: */ @@ -338,6 +346,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)USERSPACE->signal_handler; 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. */ @@ -370,6 +382,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = rtcb->xcp.sigreturn; regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; + + /* Return privileged mode */ + + regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; rtcb->xcp.sigreturn = 0; } break; @@ -405,6 +421,10 @@ int arm_svcall(int irq, void *context, void *arg) regs[REG_PC] = (uint32_t)dispatch_syscall; 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;