From 56650aff7e3cc2884b63ee56acd644ef79a69cff Mon Sep 17 00:00:00 2001 From: Wayne Ren Date: Thu, 26 Sep 2019 21:13:42 +0800 Subject: [PATCH] arch: arc: fix the bug in prologue of sys call handling * the old codes may not save the caller saved regs correctly, e.g. r7- r12. Because the sys call entry is called in the form of static inline function. The compiler optimizations may not save all the caller saved regs. * new codes use the irq stack frame as the sys call frame and gurantee all the called saved regs are pushed and popped correctly. * the side effect of new codes are more stack operations and a little overhead. Signed-off-by: Wayne Ren --- arch/arc/core/fault_s.S | 30 ++++++++++++++---------- arch/arc/core/userspace.S | 49 +++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/arch/arc/core/fault_s.S b/arch/arc/core/fault_s.S index ac02061282c..1f537129f3e 100644 --- a/arch/arc/core/fault_s.S +++ b/arch/arc/core/fault_s.S @@ -196,7 +196,7 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap) #ifdef CONFIG_USERSPACE cmp ilink, _TRAP_S_CALL_SYSTEM_CALL bne _do_non_syscall_trap -/* do sys_call */ + /* do sys_call */ mov_s ilink, K_SYSCALL_LIMIT cmp r6, ilink blt valid_syscall_id @@ -205,21 +205,27 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap) mov_s r6, K_SYSCALL_BAD valid_syscall_id: + /* create a sys call frame + * caller regs (r0 - 12) are saved in _create_irq_stack_frame + * ok to use them later + */ + _create_irq_stack_frame + #ifdef CONFIG_ARC_SECURE_FIRMWARE - lr ilink, [_ARC_V2_ERSEC_STAT] - push ilink + /* ERSEC_STAT is IOW/RAZ in normal mode */ + lr r0, [_ARC_V2_ERSEC_STAT] + st_s r0, [sp, ___isf_t_sec_stat_OFFSET] #endif - lr ilink, [_ARC_V2_ERET] - push ilink - lr ilink, [_ARC_V2_ERSTATUS] - push ilink + lr r0,[_ARC_V2_ERET] + st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ + lr r0,[_ARC_V2_ERSTATUS] + st_s r0, [sp, ___isf_t_status32_OFFSET] + bclr r0, r0, _ARC_V2_STATUS32_U_BIT + sr r0, [_ARC_V2_ERSTATUS] - bclr ilink, ilink, _ARC_V2_STATUS32_U_BIT - sr ilink, [_ARC_V2_ERSTATUS] - - mov_s ilink, _arc_do_syscall - sr ilink, [_ARC_V2_ERET] + mov_s r0, _arc_do_syscall + sr r0, [_ARC_V2_ERET] rtie diff --git a/arch/arc/core/userspace.S b/arch/arc/core/userspace.S index 3d1be7d2421..41e5bb4a718 100644 --- a/arch/arc/core/userspace.S +++ b/arch/arc/core/userspace.S @@ -202,46 +202,51 @@ return_loc_userspace_enter: * */ SECTION_FUNC(TEXT, _arc_do_syscall) - /* r0-r5: arg1-arg6, r6 is call id */ - /* the call id is already checked in trap_s handler */ - push_s blink + /* + * r0-r5: arg1-arg6, r6 is call id which is already checked in + * trap_s handler, r7 is the system call stack frame pointer + * need to recover r0, r1, r2 because they will be modified in + * _create_irq_stack_frame. If a specific syscall frame (different + * with irq stack frame) is defined, the cover of r0, r1, r2 can be + * optimized. + */ + ld_s r0, [sp, ___isf_t_r0_OFFSET] + ld_s r1, [sp, ___isf_t_r1_OFFSET] + ld_s r2, [sp, ___isf_t_r2_OFFSET] + + mov r7, sp mov_s blink, _k_syscall_table ld.as r6, [blink, r6] jl [r6] - /* - * no need to clear callee regs, as they will be saved and restored - * automatically - */ - clear_scratch_regs + /* save return value */ + st_s r0, [sp, ___isf_t_r0_OFFSET] mov_s r29, 0 mov_s r30, 0 - pop_s blink - /* through fake exception return, go back to the caller */ - lr r6, [_ARC_V2_STATUS32] - bclr r6, r6, _ARC_V2_STATUS32_AE_BIT - kflag r6 + lr r0, [_ARC_V2_STATUS32] + bset r0, r0, _ARC_V2_STATUS32_AE_BIT + kflag r0 + - /* the status and return address are saved in trap_s handler */ - pop r6 - sr r6, [_ARC_V2_ERSTATUS] - pop r6 - sr r6, [_ARC_V2_ERET] #ifdef CONFIG_ARC_SECURE_FIRMWARE - pop r6 - sr r6, [_ARC_V2_ERSEC_STAT] + ld_s r0, [sp, ___isf_t_sec_stat_OFFSET] + sr r0,[_ARC_V2_ERSEC_STAT] #endif + ld_s r0, [sp, ___isf_t_status32_OFFSET] + sr r0,[_ARC_V2_ERSTATUS] - mov_s r6, 0 + ld_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ + sr r0,[_ARC_V2_ERET] + + _pop_irq_stack_frame rtie - /* * size_t z_arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg) */