This is an automated email from the ASF dual-hosted git repository. masayuki pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit db3a40ac25d0845e9118746bfdf996846a368728 Author: chao.an <anc...@xiaomi.com> AuthorDate: Wed Feb 16 13:01:47 2022 +0800 arch/armv7-r: unify switch context from software interrupt Signed-off-by: chao.an <anc...@xiaomi.com> --- arch/arm/src/armv7-r/arm_blocktask.c | 27 +++++----- arch/arm/src/armv7-r/arm_fullcontextrestore.S | 74 --------------------------- arch/arm/src/armv7-r/arm_releasepending.c | 28 +++++----- arch/arm/src/armv7-r/arm_reprioritizertr.c | 29 ++++++----- arch/arm/src/armv7-r/arm_syscall.c | 50 ++++++++++++------ arch/arm/src/armv7-r/arm_unblocktask.c | 29 +++++------ arch/arm/src/armv7-r/svcall.h | 68 +++++++++++++----------- 7 files changed, 129 insertions(+), 176 deletions(-) diff --git a/arch/arm/src/armv7-r/arm_blocktask.c b/arch/arm/src/armv7-r/arm_blocktask.c index 6dafcc1..7e5dacb 100644 --- a/arch/arm/src/armv7-r/arm_blocktask.c +++ b/arch/arm/src/armv7-r/arm_blocktask.c @@ -123,26 +123,27 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state) arm_restorestate(rtcb->xcp.regs); } - /* Copy the user C context into the TCB at the (old) head of the - * ready-to-run Task list. if arm_saveusercontext returns a non-zero - * value, then this is really the previously running task restarting! - */ + /* No, then we will need to perform the user context switch */ - else if (!arm_saveusercontext(rtcb->xcp.regs)) + else { - /* Restore the exception context of the rtcb at the (new) head - * of the ready-to-run task list. - */ - - rtcb = this_task(); + struct tcb_s *nexttcb = this_task(); /* Reset scheduler parameters */ - nxsched_resume_scheduler(rtcb); + nxsched_resume_scheduler(nexttcb); + + /* Switch context to the context of the task at the head of the + * ready to run list. + */ - /* Then switch contexts */ + arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); - arm_fullcontextrestore(rtcb->xcp.regs); + /* arm_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ } } } diff --git a/arch/arm/src/armv7-r/arm_fullcontextrestore.S b/arch/arm/src/armv7-r/arm_fullcontextrestore.S index 1d806be..9af7219 100644 --- a/arch/arm/src/armv7-r/arm_fullcontextrestore.S +++ b/arch/arm/src/armv7-r/arm_fullcontextrestore.S @@ -62,44 +62,6 @@ .type arm_fullcontextrestore, function arm_fullcontextrestore: - /* On entry, a1 (r0) holds address of the register save area. All other - * registers are available for use. - */ - -#ifdef CONFIG_ARCH_FPU - /* First, restore the floating point registers. Lets do this before we - * restore the ARM registers so that we have plenty of registers to - * work with. - */ - - add r1, r0, #(4*REG_S0) /* r1=Address of FP register storage */ - - /* Load all floating point registers. Registers are loaded in numeric order, - * s0, s1, ... in increasing address order. - */ - -#ifdef CONFIG_ARM_HAVE_FPU_D32 - vldmia.64 r1!, {d0-d15} /* Restore the full FP context */ - vldmia.64 r1!, {d16-d31} -#else - vldmia r1!, {s0-s31} /* Restore the full FP context */ -#endif - - /* Load the floating point control and status register. At the end of the - * vstmia, r1 will point to the FPSCR storage location. - */ - - ldr r2, [r1], #4 /* Fetch the floating point control and status register */ - vmsr fpscr, r2 /* Restore the FPSCR */ -#endif - -#ifdef CONFIG_BUILD_PROTECTED - /* For the protected build, we need to be able to transition gracefully - * between kernel- and user-mode tasks. Here we do that with a system - * call; the system call will execute in kernel mode and but can return - * to either user or kernel mode. - */ - /* Perform the System call with R0=1 and R1=regs */ mov r1, r0 /* R1: regs */ @@ -109,41 +71,5 @@ arm_fullcontextrestore: /* This call should not return */ bx lr /* Unnecessary ... will not return */ - -#else - /* For a flat build, we can do all of this here... Just think of this as - * a longjmp() all on steroids. - */ - - /* Recover all registers except for r0, r1, R15, and CPSR */ - - add r1, r0, #(4*REG_R2) /* Offset to REG_R2 storage */ - ldmia r1, {r2-r14} /* Recover registers */ - - /* Create a stack frame to hold the some registers */ - - sub sp, sp, #(3*4) /* Frame for three registers */ - ldr r1, [r0, #(4*REG_R0)] /* Fetch the stored r0 value */ - str r1, [sp] /* Save it at the top of the stack */ - ldr r1, [r0, #(4*REG_R1)] /* Fetch the stored r1 value */ - str r1, [sp, #4] /* Save it in the stack */ - ldr r1, [r0, #(4*REG_PC)] /* Fetch the stored pc value */ - str r1, [sp, #8] /* Save it at the bottom of the frame */ - - /* Now we can restore the CPSR. We wait until we are completely - * finished with the context save data to do this. Restore the CPSR - * may re-enable and interrupts and we could be in a context - * where the save structure is only protected by interrupts being - * disabled. - */ - - ldr r1, [r0, #(4*REG_CPSR)] /* Fetch the stored CPSR value */ - msr spsr_cxsf, r1 /* Set the SPSR */ - - /* Now recover r0-r1, pc and cpsr, destroying the stack frame */ - - ldmia sp!, {r0-r1, pc}^ -#endif - .size arm_fullcontextrestore, .-arm_fullcontextrestore .end diff --git a/arch/arm/src/armv7-r/arm_releasepending.c b/arch/arm/src/armv7-r/arm_releasepending.c index 689c355..43b78f2 100644 --- a/arch/arm/src/armv7-r/arm_releasepending.c +++ b/arch/arm/src/armv7-r/arm_releasepending.c @@ -93,27 +93,27 @@ void up_release_pending(void) arm_restorestate(rtcb->xcp.regs); } - /* Copy the exception context into the TCB of the task that - * was currently active. if arm_saveusercontext returns a non-zero - * value, then this is really the previously running task - * restarting! - */ + /* No, then we will need to perform the user context switch */ - else if (!arm_saveusercontext(rtcb->xcp.regs)) + else { - /* Restore the exception context of the rtcb at the (new) head - * of the ready-to-run task list. - */ - - rtcb = this_task(); + struct tcb_s *nexttcb = this_task(); /* Update scheduler parameters */ - nxsched_resume_scheduler(rtcb); + nxsched_resume_scheduler(nexttcb); - /* Then switch contexts */ + /* Switch context to the context of the task at the head of the + * ready to run list. + */ - arm_fullcontextrestore(rtcb->xcp.regs); + arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + + /* arm_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ } } } diff --git a/arch/arm/src/armv7-r/arm_reprioritizertr.c b/arch/arm/src/armv7-r/arm_reprioritizertr.c index 44c41b6..6852177 100644 --- a/arch/arm/src/armv7-r/arm_reprioritizertr.c +++ b/arch/arm/src/armv7-r/arm_reprioritizertr.c @@ -147,27 +147,28 @@ void up_reprioritize_rtr(struct tcb_s *tcb, uint8_t priority) arm_restorestate(rtcb->xcp.regs); } - /* Copy the exception context into the TCB at the (old) head of - * the ready-to-run Task list. if arm_saveusercontext returns a - * non-zero value, then this is really the previously running task - * restarting! - */ + /* No, then we will need to perform the user context switch */ - else if (!arm_saveusercontext(rtcb->xcp.regs)) + else { - /* Restore the exception context of the rtcb at the (new) head - * of the ready-to-run task list. - */ - - rtcb = this_task(); + struct tcb_s *nexttcb = this_task(); /* Update scheduler parameters */ - nxsched_resume_scheduler(rtcb); + nxsched_resume_scheduler(nexttcb); - /* Then switch contexts */ + /* Switch context to the context of the task at the head of the + * ready to run list. + */ - arm_fullcontextrestore(rtcb->xcp.regs); + arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + + /* arm_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the + * blocked task is again ready to run and has execution + * priority. + */ } } } diff --git a/arch/arm/src/armv7-r/arm_syscall.c b/arch/arm/src/armv7-r/arm_syscall.c index 06ddc27..719d270 100644 --- a/arch/arm/src/armv7-r/arm_syscall.c +++ b/arch/arm/src/armv7-r/arm_syscall.c @@ -120,7 +120,6 @@ static void dispatch_syscall(void) * ****************************************************************************/ -#ifdef CONFIG_LIB_SYSCALL uint32_t *arm_syscall(uint32_t *regs) { uint32_t cmd; @@ -165,6 +164,7 @@ uint32_t *arm_syscall(uint32_t *regs) * unprivileged thread mode. */ +#ifdef CONFIG_LIB_SYSCALL case SYS_syscall_return: { FAR struct tcb_s *rtcb = nxsched_self(); @@ -213,6 +213,7 @@ uint32_t *arm_syscall(uint32_t *regs) (void)nxsig_unmask_pendingsignal(); } break; +#endif /* R0=SYS_restore_context: Restore task context * @@ -225,7 +226,6 @@ uint32_t *arm_syscall(uint32_t *regs) * R1 = restoreregs */ -#ifdef CONFIG_BUILD_PROTECTED case SYS_restore_context: { /* Replace 'regs' with the pointer to the register set in @@ -233,11 +233,40 @@ uint32_t *arm_syscall(uint32_t *regs) * set will determine the restored context. */ + arm_restorefpu((uint32_t *)regs[REG_R1]); regs = (uint32_t *)regs[REG_R1]; DEBUGASSERT(regs); } break; + + /* R0=SYS_switch_context: This a switch context command: + * + * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_switch_context + * R1 = saveregs + * R2 = restoreregs + * + * In this case, we do both: We save the context registers to the save + * register area reference by the saved contents of R1 and then set + * regs to the save register area referenced by the saved + * contents of R2. + */ + + case SYS_switch_context: + { + DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); +#if defined(CONFIG_ARCH_FPU) + arm_copyarmstate((uint32_t *)regs[REG_R1], regs); + arm_restorefpu((uint32_t *)regs[REG_R2]); +#else + memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); #endif + regs = (uint32_t *)regs[REG_R2]; + } + break; /* R0=SYS_task_start: This a user task start * @@ -452,9 +481,6 @@ uint32_t *arm_syscall(uint32_t *regs) /* Indicate that we are in a syscall handler. */ rtcb->flags |= TCB_FLAG_SYSCALL; -#else - svcerr("ERROR: Bad SYS call: %d\n", regs[REG_R0]); -#endif #ifdef CONFIG_ARCH_KERNEL_STACK /* If this is the first SYSCALL and if there is an allocated @@ -472,6 +498,9 @@ uint32_t *arm_syscall(uint32_t *regs) /* Save the new SYSCALL nesting level */ rtcb->xcp.nsyscalls = index + 1; +#else + svcerr("ERROR: Bad SYS call: 0x%" PRIx32 "\n", regs[REG_R0]); +#endif } break; } @@ -494,14 +523,3 @@ uint32_t *arm_syscall(uint32_t *regs) return regs; } - -#else - -uint32_t *arm_syscall(uint32_t *regs) -{ - _alert("SYSCALL from 0x%x\n", regs[REG_PC]); - CURRENT_REGS = regs; - PANIC(); -} - -#endif diff --git a/arch/arm/src/armv7-r/arm_unblocktask.c b/arch/arm/src/armv7-r/arm_unblocktask.c index 0d4d489..d10d7a2 100644 --- a/arch/arm/src/armv7-r/arm_unblocktask.c +++ b/arch/arm/src/armv7-r/arm_unblocktask.c @@ -121,28 +121,27 @@ void up_unblock_task(struct tcb_s *tcb) arm_restorestate(rtcb->xcp.regs); } - /* We are not in an interrupt handler. Copy the user C context - * into the TCB of the task that was previously active. if - * arm_saveusercontext returns a non-zero value, then this is really - * the previously running task restarting! - */ + /* No, then we will need to perform the user context switch */ - else if (!arm_saveusercontext(rtcb->xcp.regs)) + else { - /* Restore the exception context of the new task that is ready to - * run (probably tcb). This is the new rtcb at the head of the - * ready-to-run task list. - */ - - rtcb = this_task(); + struct tcb_s *nexttcb = this_task(); /* Update scheduler parameters */ - nxsched_resume_scheduler(rtcb); + nxsched_resume_scheduler(nexttcb); + + /* Switch context to the context of the task at the head of the + * ready to run list. + */ - /* Then switch contexts */ + arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); - arm_fullcontextrestore(rtcb->xcp.regs); + /* arm_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ } } } diff --git a/arch/arm/src/armv7-r/svcall.h b/arch/arm/src/armv7-r/svcall.h index 2470da7..b0efecd 100644 --- a/arch/arm/src/armv7-r/svcall.h +++ b/arch/arm/src/armv7-r/svcall.h @@ -29,8 +29,6 @@ #include <syscall.h> -#ifdef CONFIG_LIB_SYSCALL - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -43,17 +41,19 @@ * more syscall values must be reserved. */ -#ifdef CONFIG_BUILD_PROTECTED -# ifndef CONFIG_SYS_RESERVED -# error "CONFIG_SYS_RESERVED must be defined to have the value 6" -# elif CONFIG_SYS_RESERVED != 6 -# error "CONFIG_SYS_RESERVED must have the value 6" -# endif -#else -# ifndef CONFIG_SYS_RESERVED -# error "CONFIG_SYS_RESERVED must be defined to have the value 1" -# elif CONFIG_SYS_RESERVED != 1 -# error "CONFIG_SYS_RESERVED must have the value 1" +#ifdef CONFIG_LIB_SYSCALL +# ifdef CONFIG_BUILD_KERNEL +# ifndef CONFIG_SYS_RESERVED +# error "CONFIG_SYS_RESERVED must be defined to have the value 7" +# elif CONFIG_SYS_RESERVED != 7 +# error "CONFIG_SYS_RESERVED must have the value 7" +# endif +# else +# ifndef CONFIG_SYS_RESERVED +# error "CONFIG_SYS_RESERVED must be defined to have the value 4" +# elif CONFIG_SYS_RESERVED != 4 +# error "CONFIG_SYS_RESERVED must have the value 4" +# endif # endif #endif @@ -61,60 +61,68 @@ /* SYS call 0: * - * void arm_syscall_return(void); + * void arm_fullcontextrestore(uint32_t *restoreregs) noreturn_function; */ -#define SYS_syscall_return (0) +#define SYS_restore_context (0) -#ifndef CONFIG_BUILD_FLAT -#ifdef CONFIG_BUILD_PROTECTED /* SYS call 1: * - * void arm_fullcontextrestore(uint32_t *restoreregs) noreturn_function; + * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); */ -#define SYS_restore_context (1) +#define SYS_switch_context (1) +#ifdef CONFIG_LIB_SYSCALL /* SYS call 2: * + * void arm_syscall_return(void); + */ + +#define SYS_syscall_return (2) + +#ifndef CONFIG_BUILD_FLAT +#ifdef CONFIG_BUILD_KERNEL +/* SYS call 3: + * * void up_task_start(main_t taskentry, int argc, FAR char *argv[]) * noreturn_function; */ -#define SYS_task_start (2) +#define SYS_task_start (3) -/* SYS call 4: +/* SYS call 5: * - * void signal_handler(_sa_sigaction_t sighand, int signo, - * FAR siginfo_t *info, + * void signal_handler(_sa_sigaction_t sighand, + * int signo, FAR siginfo_t *info, * FAR void *ucontext); */ -#define SYS_signal_handler (4) +#define SYS_signal_handler (5) -/* SYS call 5: +/* SYS call 6: * * void signal_handler_return(void); */ -#define SYS_signal_handler_return (5) +#define SYS_signal_handler_return (6) -#endif /* CONFIG_BUILD_PROTECTED */ +#endif /* !CONFIG_BUILD_FLAT */ -/* SYS call 3: +/* SYS call 4: * * void up_pthread_start(pthread_startroutine_t startup, * pthread_startroutine_t entrypt, pthread_addr_t arg) * noreturn_function */ -#define SYS_pthread_start (3) +#define SYS_pthread_start (4) #endif /* !CONFIG_BUILD_FLAT */ +#endif /* CONFIG_LIB_SYSCALL */ /**************************************************************************** * Inline Functions ****************************************************************************/ -#endif /* CONFIG_LIB_SYSCALL */ #endif /* __ARCH_ARM_SRC_ARMV7_R_SVCALL_H */