Skip to content

Commit 2958b66

Browse files
committed
xtensa: enable coprocessors that are being flushed
coprocessor_flush_all may be called from a context of a thread that is different from the thread being flushed. In that case contents of the cpenable special register may not match ti->cpenable of the target thread, resulting in unhandled coprocessor exception in the kernel context. Set cpenable special register to the ti->cpenable of the target register for the duration of the flush and restore it afterwards. This fixes the following crash caused by coprocessor register inspection in native gdb: (gdb) p/x $w0 Illegal instruction in kernel: sig: 9 [#1] PREEMPT Call Trace: ___might_sleep+0x184/0x1a4 __might_sleep+0x41/0xac exit_signals+0x14/0x218 do_exit+0xc9/0x8b8 die+0x99/0xa0 do_illegal_instruction+0x18/0x6c common_exception+0x77/0x77 coprocessor_flush+0x16/0x3c arch_ptrace+0x46c/0x674 sys_ptrace+0x2ce/0x3b4 system_call+0x54/0x80 common_exception+0x77/0x77 note: gdb[100] exited with preempt_count 1 Killed Cc: [email protected] Signed-off-by: Max Filippov <[email protected]>
1 parent 2e6e902 commit 2958b66

File tree

1 file changed

+4
-1
lines changed

1 file changed

+4
-1
lines changed

arch/xtensa/kernel/process.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,21 @@ void coprocessor_release_all(struct thread_info *ti)
9494

9595
void coprocessor_flush_all(struct thread_info *ti)
9696
{
97-
unsigned long cpenable;
97+
unsigned long cpenable, old_cpenable;
9898
int i;
9999

100100
preempt_disable();
101101

102+
RSR_CPENABLE(old_cpenable);
102103
cpenable = ti->cpenable;
104+
WSR_CPENABLE(cpenable);
103105

104106
for (i = 0; i < XCHAL_CP_MAX; i++) {
105107
if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
106108
coprocessor_flush(ti, i);
107109
cpenable >>= 1;
108110
}
111+
WSR_CPENABLE(old_cpenable);
109112

110113
preempt_enable();
111114
}

0 commit comments

Comments
 (0)