xtensa: improve call0 ABI probing
When call0 userspace ABI support by probing is enabled instructions that cause illegal instruction exception when PS.WOE is clear are retried with PS.WOE set before calling c-level exception handler. Record user pc at which PS.WOE was set in the fast exception handler and clear PS.WOE in the c-level exception handler if we get there from the same address. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
This commit is contained in:
parent
d74862007e
commit
5cc5f19f88
|
@ -56,6 +56,10 @@ struct thread_info {
|
||||||
/* result of the most recent exclusive store */
|
/* result of the most recent exclusive store */
|
||||||
unsigned long atomctl8;
|
unsigned long atomctl8;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_USER_ABI_CALL0_PROBE
|
||||||
|
/* Address where PS.WOE was enabled by the ABI probing code */
|
||||||
|
unsigned long ps_woe_fix_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If i-th bit is set then coprocessor state is loaded into the
|
* If i-th bit is set then coprocessor state is loaded into the
|
||||||
|
|
|
@ -88,6 +88,9 @@ int main(void)
|
||||||
OFFSET(TI_STSTUS, thread_info, status);
|
OFFSET(TI_STSTUS, thread_info, status);
|
||||||
OFFSET(TI_CPU, thread_info, cpu);
|
OFFSET(TI_CPU, thread_info, cpu);
|
||||||
OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
|
OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
|
||||||
|
#ifdef CONFIG_USER_ABI_CALL0_PROBE
|
||||||
|
OFFSET(TI_PS_WOE_FIX_ADDR, thread_info, ps_woe_fix_addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* struct thread_info (offset from start_struct) */
|
/* struct thread_info (offset from start_struct) */
|
||||||
DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
|
DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
|
||||||
|
|
|
@ -1056,6 +1056,11 @@ ENTRY(fast_illegal_instruction_user)
|
||||||
movi a3, PS_WOE_MASK
|
movi a3, PS_WOE_MASK
|
||||||
or a0, a0, a3
|
or a0, a0, a3
|
||||||
wsr a0, ps
|
wsr a0, ps
|
||||||
|
#ifdef CONFIG_USER_ABI_CALL0_PROBE
|
||||||
|
GET_THREAD_INFO(a3, a2)
|
||||||
|
rsr a0, epc1
|
||||||
|
s32i a0, a3, TI_PS_WOE_FIX_ADDR
|
||||||
|
#endif
|
||||||
l32i a3, a2, PT_AREG3
|
l32i a3, a2, PT_AREG3
|
||||||
l32i a0, a2, PT_AREG0
|
l32i a0, a2, PT_AREG0
|
||||||
rsr a2, depc
|
rsr a2, depc
|
||||||
|
|
|
@ -317,6 +317,18 @@ static bool check_div0(struct pt_regs *regs)
|
||||||
|
|
||||||
static void do_illegal_instruction(struct pt_regs *regs)
|
static void do_illegal_instruction(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_USER_ABI_CALL0_PROBE
|
||||||
|
/*
|
||||||
|
* When call0 application encounters an illegal instruction fast
|
||||||
|
* exception handler will attempt to set PS.WOE and retry failing
|
||||||
|
* instruction.
|
||||||
|
* If we get here we know that that instruction is also illegal
|
||||||
|
* with PS.WOE set, so it's not related to the windowed option
|
||||||
|
* hence PS.WOE may be cleared.
|
||||||
|
*/
|
||||||
|
if (regs->pc == current_thread_info()->ps_woe_fix_addr)
|
||||||
|
regs->ps &= ~PS_WOE_MASK;
|
||||||
|
#endif
|
||||||
if (check_div0(regs)) {
|
if (check_div0(regs)) {
|
||||||
do_div0(regs);
|
do_div0(regs);
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue