mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 17:18:59 +00:00
7d7aa2fd92
This change makes the names of Broadcom targets consistent by using the common notation based on SoC/CPU ID (which is used internally anyway), bcmXXXX instead of brcmXXXX. This is even used for target TITLE in make menuconfig already, only the short target name used brcm so far. Despite, since subtargets range from bcm2708 to bcm2711, it seems appropriate to use bcm27xx instead of bcm2708 (again, as already done for BOARDNAME). This also renames the packages brcm2708-userland and brcm2708-gpu-fw. Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de> Acked-by: Álvaro Fernández Rojas <noltari@gmail.com>
138 lines
5.7 KiB
Diff
138 lines
5.7 KiB
Diff
From 0eb679e4b41dab1e421415917feae44d00e1687f Mon Sep 17 00:00:00 2001
|
|
From: Claggy3 <stephen.maclagan@hotmail.com>
|
|
Date: Sat, 11 Feb 2017 14:00:30 +0000
|
|
Subject: [PATCH] Update vfpmodule.c
|
|
|
|
Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m.
|
|
This patch fixes a problem with VFP state save and restore related
|
|
to exception handling (panic with message "BUG: unsupported FP
|
|
instruction in kernel mode") present on VFP11 floating point units
|
|
(as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry
|
|
Pi boards). This patch was developed and discussed on
|
|
|
|
https://github.com/raspberrypi/linux/issues/859
|
|
|
|
A precondition to see the crashes is that floating point exception
|
|
traps are enabled. In this case, the VFP11 might determine that a FPU
|
|
operation needs to trap at a point in time when it is not possible to
|
|
signal this to the ARM11 core any more. The VFP11 will then set the
|
|
FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases,
|
|
a second opcode might have been accepted by the VFP11 before the
|
|
exception was detected and could be reported to the ARM11 - in this
|
|
case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in
|
|
FPINST2.)
|
|
|
|
If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued
|
|
by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode
|
|
trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits
|
|
to decide what actions to take, i.e., whether to emulate the opcodes
|
|
found in FPINST and FPINST2, and whether to retry the bounced instruction.
|
|
|
|
If a user space application has left the VFP11 in this "pending trap"
|
|
state, the next FPU opcode issued to the VFP11 might actually be the
|
|
VSTMIA operation vfp_save_state() uses to store the FPU registers
|
|
to memory (in our test cases, when building the signal stack frame).
|
|
In this case, the kernel crashes as described above.
|
|
|
|
This patch fixes the problem by making sure that vfp_save_state() is
|
|
always entered with FPEXC.EX cleared. (The current value of FPEXC has
|
|
already been saved, so this does not corrupt the context. Clearing
|
|
FPEXC.EX has no effects on FPINST or FPINST2. Also note that many
|
|
callers already modify FPEXC by setting FPEXC.EN before invoking
|
|
vfp_save_state().)
|
|
|
|
This patch also addresses a second problem related to FPEXC.EX: After
|
|
returning from signal handling, the kernel reloads the VFP context
|
|
from the user mode stack. However, the current code explicitly clears
|
|
both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these
|
|
bits to be preserved, this patch disables clearing them for VFP
|
|
implementations belonging to architecture 1. There should be no
|
|
negative side effects: the user can set both bits by executing FPU
|
|
opcodes anyway, and while user code may now place arbitrary values
|
|
into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support
|
|
code knows which instructions can be emulated, and rejects other
|
|
opcodes with "unhandled bounce" messages, so there should be no
|
|
security impact from allowing reloading FPEXC.EX and FPEXC.FP2V.
|
|
|
|
Signed-off-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net>
|
|
---
|
|
arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------
|
|
1 file changed, 19 insertions(+), 6 deletions(-)
|
|
|
|
--- a/arch/arm/vfp/vfpmodule.c
|
|
+++ b/arch/arm/vfp/vfpmodule.c
|
|
@@ -179,8 +179,11 @@ static int vfp_notifier(struct notifier_
|
|
* case the thread migrates to a different CPU. The
|
|
* restoring is done lazily.
|
|
*/
|
|
- if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu])
|
|
+ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
|
|
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
|
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
|
|
vfp_save_state(vfp_current_hw_state[cpu], fpexc);
|
|
+ }
|
|
#endif
|
|
|
|
/*
|
|
@@ -462,13 +465,16 @@ static int vfp_pm_suspend(void)
|
|
/* if vfp is on, then save state for resumption */
|
|
if (fpexc & FPEXC_EN) {
|
|
pr_debug("%s: saving vfp state\n", __func__);
|
|
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
|
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
|
|
vfp_save_state(&ti->vfpstate, fpexc);
|
|
|
|
/* disable, just in case */
|
|
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
|
|
} else if (vfp_current_hw_state[ti->cpu]) {
|
|
#ifndef CONFIG_SMP
|
|
- fmxr(FPEXC, fpexc | FPEXC_EN);
|
|
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
|
+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
|
|
vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
|
|
fmxr(FPEXC, fpexc);
|
|
#endif
|
|
@@ -531,7 +537,8 @@ void vfp_sync_hwstate(struct thread_info
|
|
/*
|
|
* Save the last VFP state on this CPU.
|
|
*/
|
|
- fmxr(FPEXC, fpexc | FPEXC_EN);
|
|
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
|
+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
|
|
vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
|
|
fmxr(FPEXC, fpexc);
|
|
}
|
|
@@ -597,6 +604,7 @@ int vfp_restore_user_hwstate(struct user
|
|
struct thread_info *thread = current_thread_info();
|
|
struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
|
|
unsigned long fpexc;
|
|
+ u32 fpsid = fmrx(FPSID);
|
|
|
|
/* Disable VFP to avoid corrupting the new thread state. */
|
|
vfp_flush_hwstate(thread);
|
|
@@ -619,8 +627,12 @@ int vfp_restore_user_hwstate(struct user
|
|
/* Ensure the VFP is enabled. */
|
|
fpexc |= FPEXC_EN;
|
|
|
|
- /* Ensure FPINST2 is invalid and the exception flag is cleared. */
|
|
- fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
|
|
+ /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */
|
|
+ if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) {
|
|
+ /* Ensure FPINST2 is invalid and the exception flag is cleared. */
|
|
+ fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
|
|
+ }
|
|
+
|
|
hwstate->fpexc = fpexc;
|
|
|
|
hwstate->fpinst = ufp_exc->fpinst;
|
|
@@ -690,7 +702,8 @@ void kernel_neon_begin(void)
|
|
cpu = get_cpu();
|
|
|
|
fpexc = fmrx(FPEXC) | FPEXC_EN;
|
|
- fmxr(FPEXC, fpexc);
|
|
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
|
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
|
|
|
|
/*
|
|
* Save the userland NEON/VFP state. Under UP,
|