Skip to content

Commit

Permalink
arch: arc: fix the bug where firq comes out in user mode
Browse files Browse the repository at this point in the history
firq's case is similar to regular irq, it also needs to consider
the case of reg bank switch.

Signed-off-by: Wayne Ren <[email protected]>
  • Loading branch information
Wayne Ren authored and andrewboie committed Feb 5, 2020
1 parent 05a669c commit 8450d26
Showing 1 changed file with 46 additions and 1 deletion.
47 changes: 46 additions & 1 deletion arch/arc/core/fast_irq.S
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,36 @@ _firq_reschedule:
* point, so when switching back to register bank 0, it will contain the
* registers from the interrupted thread.
*/

#if defined(CONFIG_USERSPACE)
/* when USERSPACE is configured, here need to consider the case where firq comes
* out in user mode, according to ARCv2 ISA and nsim, the following micro ops
* will be executed:
* sp<-reg bank1'sp
* switch between sp and _ARC_V2_USER_SP
* then:
* sp is the sp of kernel stack of interrupted thread
* _ARC_V2_USER_SP is reg bank1'sp
* the sp of user stack of interrupted thread is reg bank0'sp
* if firq comes out in kernel mode, the following micro ops will be executed:
* sp<-reg bank'sp
* so, sw needs to do necessary handling to set up the correct sp
*/
lr r0, [_ARC_V2_AUX_IRQ_ACT]
bbit0 r0, 31, _firq_from_kernel
aex sp, [_ARC_V2_USER_SP]
lr r0, [_ARC_V2_STATUS32]
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
kflag r0
aex sp, [_ARC_V2_USER_SP]
b _firq_create_irq_stack_frame
_firq_from_kernel:
#endif
/* chose register bank #0 */
lr r0, [_ARC_V2_STATUS32]
and r0, r0, ~_ARC_V2_STATUS32_RB(7)
kflag r0

_firq_create_irq_stack_frame:
/* we're back on the outgoing thread's stack */
_create_irq_stack_frame

Expand All @@ -225,6 +249,7 @@ _firq_reschedule:
st_s r0, [sp, ___isf_t_status32_OFFSET]

st ilink, [sp, ___isf_t_pc_OFFSET] /* ilink into pc */

#ifdef CONFIG_SMP
/*
* load r0, r1 from irq stack
Expand All @@ -235,6 +260,16 @@ _firq_reschedule:
#endif
#endif

#if defined(CONFIG_USERSPACE)
/*
* need to remember the user/kernel status of interrupted thread, will be
* restored when thread switched back
*/
lr r3, [_ARC_V2_AUX_IRQ_ACT]
and r3, r3, 0x80000000
push_s r3
#endif

#ifdef CONFIG_SMP
mov_s r2, r1
#else
Expand Down Expand Up @@ -300,6 +335,16 @@ _firq_return_from_coop:
_firq_return_from_rirq:
_firq_return_from_firq:

#if defined(CONFIG_USERSPACE)
/*
* need to recover the user/kernel status of interrupted thread
*/
pop_s r3
lr r2, [_ARC_V2_AUX_IRQ_ACT]
or r2, r2, r3
sr r2, [_ARC_V2_AUX_IRQ_ACT]
#endif

_pop_irq_stack_frame

ld ilink, [sp, -4] /* status32 into ilink */
Expand Down

0 comments on commit 8450d26

Please sign in to comment.