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 <wei.ren@synopsys.com>
This commit is contained in:
Wayne Ren 2019-09-26 21:13:42 +08:00 committed by Anas Nashif
commit 56650aff7e
2 changed files with 45 additions and 34 deletions

View file

@ -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

View file

@ -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)
*/