]>
Commit | Line | Data |
---|---|---|
f570a3f8 GKH |
1 | From 2958b66694e018c552be0b60521fec27e8d12988 Mon Sep 17 00:00:00 2001 |
2 | From: Max Filippov <jcmvbkbc@gmail.com> | |
3 | Date: Mon, 26 Nov 2018 13:29:41 -0800 | |
4 | Subject: xtensa: enable coprocessors that are being flushed | |
5 | ||
6 | From: Max Filippov <jcmvbkbc@gmail.com> | |
7 | ||
8 | commit 2958b66694e018c552be0b60521fec27e8d12988 upstream. | |
9 | ||
10 | coprocessor_flush_all may be called from a context of a thread that is | |
11 | different from the thread being flushed. In that case contents of the | |
12 | cpenable special register may not match ti->cpenable of the target | |
13 | thread, resulting in unhandled coprocessor exception in the kernel | |
14 | context. | |
15 | Set cpenable special register to the ti->cpenable of the target register | |
16 | for the duration of the flush and restore it afterwards. | |
17 | This fixes the following crash caused by coprocessor register inspection | |
18 | in native gdb: | |
19 | ||
20 | (gdb) p/x $w0 | |
21 | Illegal instruction in kernel: sig: 9 [#1] PREEMPT | |
22 | Call Trace: | |
23 | ___might_sleep+0x184/0x1a4 | |
24 | __might_sleep+0x41/0xac | |
25 | exit_signals+0x14/0x218 | |
26 | do_exit+0xc9/0x8b8 | |
27 | die+0x99/0xa0 | |
28 | do_illegal_instruction+0x18/0x6c | |
29 | common_exception+0x77/0x77 | |
30 | coprocessor_flush+0x16/0x3c | |
31 | arch_ptrace+0x46c/0x674 | |
32 | sys_ptrace+0x2ce/0x3b4 | |
33 | system_call+0x54/0x80 | |
34 | common_exception+0x77/0x77 | |
35 | note: gdb[100] exited with preempt_count 1 | |
36 | Killed | |
37 | ||
38 | Cc: stable@vger.kernel.org | |
39 | Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> | |
40 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
41 | ||
42 | --- | |
43 | arch/xtensa/kernel/process.c | 5 ++++- | |
44 | 1 file changed, 4 insertions(+), 1 deletion(-) | |
45 | ||
46 | --- a/arch/xtensa/kernel/process.c | |
47 | +++ b/arch/xtensa/kernel/process.c | |
48 | @@ -94,18 +94,21 @@ void coprocessor_release_all(struct thre | |
49 | ||
50 | void coprocessor_flush_all(struct thread_info *ti) | |
51 | { | |
52 | - unsigned long cpenable; | |
53 | + unsigned long cpenable, old_cpenable; | |
54 | int i; | |
55 | ||
56 | preempt_disable(); | |
57 | ||
58 | + RSR_CPENABLE(old_cpenable); | |
59 | cpenable = ti->cpenable; | |
60 | + WSR_CPENABLE(cpenable); | |
61 | ||
62 | for (i = 0; i < XCHAL_CP_MAX; i++) { | |
63 | if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti) | |
64 | coprocessor_flush(ti, i); | |
65 | cpenable >>= 1; | |
66 | } | |
67 | + WSR_CPENABLE(old_cpenable); | |
68 | ||
69 | preempt_enable(); | |
70 | } |