OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | From aa00ca3b0296c40a6b5a1ad32258d5b655a28c70 Mon Sep 17 00:00:00 2001 |
2 | From: Claggy3 <stephen.maclagan@hotmail.com> |
||
3 | Date: Sat, 11 Feb 2017 14:00:30 +0000 |
||
4 | Subject: [PATCH] Update vfpmodule.c |
||
5 | |||
6 | Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m. |
||
7 | This patch fixes a problem with VFP state save and restore related |
||
8 | to exception handling (panic with message "BUG: unsupported FP |
||
9 | instruction in kernel mode") present on VFP11 floating point units |
||
10 | (as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry |
||
11 | Pi boards). This patch was developed and discussed on |
||
12 | |||
13 | https://github.com/raspberrypi/linux/issues/859 |
||
14 | |||
15 | A precondition to see the crashes is that floating point exception |
||
16 | traps are enabled. In this case, the VFP11 might determine that a FPU |
||
17 | operation needs to trap at a point in time when it is not possible to |
||
18 | signal this to the ARM11 core any more. The VFP11 will then set the |
||
19 | FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases, |
||
20 | a second opcode might have been accepted by the VFP11 before the |
||
21 | exception was detected and could be reported to the ARM11 - in this |
||
22 | case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in |
||
23 | FPINST2.) |
||
24 | |||
25 | If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued |
||
26 | by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode |
||
27 | trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits |
||
28 | to decide what actions to take, i.e., whether to emulate the opcodes |
||
29 | found in FPINST and FPINST2, and whether to retry the bounced instruction. |
||
30 | |||
31 | If a user space application has left the VFP11 in this "pending trap" |
||
32 | state, the next FPU opcode issued to the VFP11 might actually be the |
||
33 | VSTMIA operation vfp_save_state() uses to store the FPU registers |
||
34 | to memory (in our test cases, when building the signal stack frame). |
||
35 | In this case, the kernel crashes as described above. |
||
36 | |||
37 | This patch fixes the problem by making sure that vfp_save_state() is |
||
38 | always entered with FPEXC.EX cleared. (The current value of FPEXC has |
||
39 | already been saved, so this does not corrupt the context. Clearing |
||
40 | FPEXC.EX has no effects on FPINST or FPINST2. Also note that many |
||
41 | callers already modify FPEXC by setting FPEXC.EN before invoking |
||
42 | vfp_save_state().) |
||
43 | |||
44 | This patch also addresses a second problem related to FPEXC.EX: After |
||
45 | returning from signal handling, the kernel reloads the VFP context |
||
46 | from the user mode stack. However, the current code explicitly clears |
||
47 | both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these |
||
48 | bits to be preserved, this patch disables clearing them for VFP |
||
49 | implementations belonging to architecture 1. There should be no |
||
50 | negative side effects: the user can set both bits by executing FPU |
||
51 | opcodes anyway, and while user code may now place arbitrary values |
||
52 | into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support |
||
53 | code knows which instructions can be emulated, and rejects other |
||
54 | opcodes with "unhandled bounce" messages, so there should be no |
||
55 | security impact from allowing reloading FPEXC.EX and FPEXC.FP2V. |
||
56 | |||
57 | Signed-off-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net> |
||
58 | --- |
||
59 | arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------ |
||
60 | 1 file changed, 19 insertions(+), 6 deletions(-) |
||
61 | |||
62 | --- a/arch/arm/vfp/vfpmodule.c |
||
63 | +++ b/arch/arm/vfp/vfpmodule.c |
||
64 | @@ -179,8 +179,11 @@ static int vfp_notifier(struct notifier_ |
||
65 | * case the thread migrates to a different CPU. The |
||
66 | * restoring is done lazily. |
||
67 | */ |
||
68 | - if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) |
||
69 | + if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) { |
||
70 | + /* vfp_save_state oopses on VFP11 if EX bit set */ |
||
71 | + fmxr(FPEXC, fpexc & ~FPEXC_EX); |
||
72 | vfp_save_state(vfp_current_hw_state[cpu], fpexc); |
||
73 | + } |
||
74 | #endif |
||
75 | |||
76 | /* |
||
77 | @@ -463,13 +466,16 @@ static int vfp_pm_suspend(void) |
||
78 | /* if vfp is on, then save state for resumption */ |
||
79 | if (fpexc & FPEXC_EN) { |
||
80 | pr_debug("%s: saving vfp state\n", __func__); |
||
81 | + /* vfp_save_state oopses on VFP11 if EX bit set */ |
||
82 | + fmxr(FPEXC, fpexc & ~FPEXC_EX); |
||
83 | vfp_save_state(&ti->vfpstate, fpexc); |
||
84 | |||
85 | /* disable, just in case */ |
||
86 | fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); |
||
87 | } else if (vfp_current_hw_state[ti->cpu]) { |
||
88 | #ifndef CONFIG_SMP |
||
89 | - fmxr(FPEXC, fpexc | FPEXC_EN); |
||
90 | + /* vfp_save_state oopses on VFP11 if EX bit set */ |
||
91 | + fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); |
||
92 | vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc); |
||
93 | fmxr(FPEXC, fpexc); |
||
94 | #endif |
||
95 | @@ -532,7 +538,8 @@ void vfp_sync_hwstate(struct thread_info |
||
96 | /* |
||
97 | * Save the last VFP state on this CPU. |
||
98 | */ |
||
99 | - fmxr(FPEXC, fpexc | FPEXC_EN); |
||
100 | + /* vfp_save_state oopses on VFP11 if EX bit set */ |
||
101 | + fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); |
||
102 | vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); |
||
103 | fmxr(FPEXC, fpexc); |
||
104 | } |
||
105 | @@ -604,6 +611,7 @@ int vfp_restore_user_hwstate(struct user |
||
106 | struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; |
||
107 | unsigned long fpexc; |
||
108 | int err = 0; |
||
109 | + u32 fpsid = fmrx(FPSID); |
||
110 | |||
111 | /* Disable VFP to avoid corrupting the new thread state. */ |
||
112 | vfp_flush_hwstate(thread); |
||
113 | @@ -627,8 +635,12 @@ int vfp_restore_user_hwstate(struct user |
||
114 | /* Ensure the VFP is enabled. */ |
||
115 | fpexc |= FPEXC_EN; |
||
116 | |||
117 | - /* Ensure FPINST2 is invalid and the exception flag is cleared. */ |
||
118 | - fpexc &= ~(FPEXC_EX | FPEXC_FP2V); |
||
119 | + /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */ |
||
120 | + if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) { |
||
121 | + /* Ensure FPINST2 is invalid and the exception flag is cleared. */ |
||
122 | + fpexc &= ~(FPEXC_EX | FPEXC_FP2V); |
||
123 | + } |
||
124 | + |
||
125 | hwstate->fpexc = fpexc; |
||
126 | |||
127 | __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); |
||
128 | @@ -698,7 +710,8 @@ void kernel_neon_begin(void) |
||
129 | cpu = get_cpu(); |
||
130 | |||
131 | fpexc = fmrx(FPEXC) | FPEXC_EN; |
||
132 | - fmxr(FPEXC, fpexc); |
||
133 | + /* vfp_save_state oopses on VFP11 if EX bit set */ |
||
134 | + fmxr(FPEXC, fpexc & ~FPEXC_EX); |
||
135 | |||
136 | /* |
||
137 | * Save the userland NEON/VFP state. Under UP, |