Skip to content

Commit

Permalink
Adding two kernel patches for mips, that make the life easier on loon…
Browse files Browse the repository at this point in the history
…gson2f

(less sigill, less sigbus). Related to bad handling of FPU instructions.

I apply them only to linux 3.4, although I think they can apply to many older kernels too.



git-svn-id: https://nixos.org/repos/nix/nixpkgs/trunk@34522 70bd8c7a-acb8-0310-9f0d-9cc1c95dcdbb
  • Loading branch information
viric committed Jun 16, 2012
1 parent 972563f commit 6bddc77
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 0 deletions.
108 changes: 108 additions & 0 deletions pkgs/os-specific/linux/kernel/mips-fpu-sigill.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
From bf55ef4e3c2f622ac013f196affbd11b67b59223 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Fri, 28 Oct 2011 13:24:37 -0400
Subject: [PATCH 2/4] Fix handling of prefx instruction in mips/math-emu

* The instruction is named prefx, not pfetch, and its function
field is 0x17, not 0x07.

* Recognize the prefx instruction regardless of what bits happen to be
in bits 21-25, which is the format field of the floating-point ops,
but holds the base register of the prefx instruction.
---
arch/mips/include/asm/inst.h | 4 ++--
arch/mips/math-emu/cp1emu.c | 16 +++++++---------
2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
index ab84064..3048edc 100644
--- a/arch/mips/include/asm/inst.h
+++ b/arch/mips/include/asm/inst.h
@@ -161,8 +161,8 @@ enum cop1_sdw_func {
*/
enum cop1x_func {
lwxc1_op = 0x00, ldxc1_op = 0x01,
- pfetch_op = 0x07, swxc1_op = 0x08,
- sdxc1_op = 0x09, madd_s_op = 0x20,
+ swxc1_op = 0x08, sdxc1_op = 0x09,
+ prefx_op = 0x17, madd_s_op = 0x20,
madd_d_op = 0x21, madd_e_op = 0x22,
msub_s_op = 0x28, msub_d_op = 0x29,
msub_e_op = 0x2a, nmadd_s_op = 0x30,
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index dbf2f93..87ddba1 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -739,7 +739,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;

default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}
@@ -809,19 +809,17 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
goto copcsr;

default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}

- case 0x7: /* 7 */
- if (MIPSInst_FUNC(ir) != pfetch_op) {
- return SIGILL;
- }
- /* ignore prefx operation */
- break;
-
default:
+ SIGILL_unless_prefx_op:
+ if (MIPSInst_FUNC(ir) == prefx_op) {
+ /* ignore prefx operation */
+ break;
+ }
return SIGILL;
}

--
1.7.5.4

From 97a564e3eddbfb84844b8eccb3bd751c71dfb3eb Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Fri, 28 Oct 2011 13:35:27 -0400
Subject: [PATCH 3/4] Don't process empty cause flags after simple fp move on
mips

---
arch/mips/math-emu/cp1emu.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 87ddba1..fefcba2 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -912,7 +912,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
case fmov_op:
/* an easy one */
SPFROMREG(rv.s, MIPSInst_FS(ir));
- goto copcsr;
+ break;

/* binary op on handler */
scopbop:
@@ -1099,7 +1099,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
case fmov_op:
/* an easy one */
DPFROMREG(rv.d, MIPSInst_FS(ir));
- goto copcsr;
+ break;

/* binary op on handler */
dcopbop:{
--
1.7.5.4

144 changes: 144 additions & 0 deletions pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
From ab1ce0a6cd51ca83194a865837f3b90f366a733d Mon Sep 17 00:00:00 2001
From: Lluis Batlle i Rossell <viric@viric.name>
Date: Sat, 16 Jun 2012 00:22:53 +0200
Subject: [PATCH] MIPS: Add emulation for fpureg-mem unaligned access
To: linux-mips@linux-mips.org
Cc: loongson-dev@googlegroups.com

Reusing most of the code from lw,ld,sw,sd emulation,
I add the emulation for lwc1,ldc1,swc1,sdc1.

This avoids the direct SIGBUS sent to userspace processes that have
misaligned memory accesses.

I've tested the change in Loongson2F, with an own test program, and
WebKit 1.4.0, as both were killed by sigbus without this patch.

Signed-off: Lluis Batlle i Rossell <viric@viric.name>
---
arch/mips/kernel/unaligned.c | 43 +++++++++++++++++++++++++++++-------------
1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 9c58bdf..4531e6c 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -85,6 +85,7 @@
#include <asm/cop2.h>
#include <asm/inst.h>
#include <asm/uaccess.h>
+#include <asm/fpu.h>

#define STR(x) __STR(x)
#define __STR(x) #x
@@ -108,6 +109,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
union mips_instruction insn;
unsigned long value;
unsigned int res;
+ fpureg_t *fpuregs;

perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);

@@ -183,6 +185,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;

case lw_op:
+ case lwc1_op:
if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus;

@@ -209,7 +212,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (res)
goto fault;
compute_return_epc(regs);
- regs->regs[insn.i_format.rt] = value;
+ if (insn.i_format.opcode == lw_op) {
+ regs->regs[insn.i_format.rt] = value;
+ } else {
+ fpuregs = get_fpu_regs(current);
+ fpuregs[insn.i_format.rt] = value;
+ }
break;

case lhu_op:
@@ -291,6 +299,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
goto sigill;

case ld_op:
+ case ldc1_op:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
@@ -325,7 +334,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (res)
goto fault;
compute_return_epc(regs);
- regs->regs[insn.i_format.rt] = value;
+ if (insn.i_format.opcode == ld_op) {
+ regs->regs[insn.i_format.rt] = value;
+ } else {
+ fpuregs = get_fpu_regs(current);
+ fpuregs[insn.i_format.rt] = value;
+ }
break;
#endif /* CONFIG_64BIT */

@@ -370,10 +384,16 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;

case sw_op:
+ case swc1_op:
if (!access_ok(VERIFY_WRITE, addr, 4))
goto sigbus;

- value = regs->regs[insn.i_format.rt];
+ if (insn.i_format.opcode == sw_op) {
+ value = regs->regs[insn.i_format.rt];
+ } else {
+ fpuregs = get_fpu_regs(current);
+ value = fpuregs[insn.i_format.rt];
+ }
__asm__ __volatile__ (
#ifdef __BIG_ENDIAN
"1:\tswl\t%1,(%2)\n"
@@ -401,6 +421,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;

case sd_op:
+ case sdc1_op:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
@@ -412,7 +433,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, addr, 8))
goto sigbus;

- value = regs->regs[insn.i_format.rt];
+ if (insn.i_format.opcode == sd_op) {
+ value = regs->regs[insn.i_format.rt];
+ } else {
+ fpuregs = get_fpu_regs(current);
+ value = fpuregs[insn.i_format.rt];
+ }
__asm__ __volatile__ (
#ifdef __BIG_ENDIAN
"1:\tsdl\t%1,(%2)\n"
@@ -443,15 +469,6 @@ static void emulate_load_store_insn(struct pt_regs *regs,
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;

- case lwc1_op:
- case ldc1_op:
- case swc1_op:
- case sdc1_op:
- /*
- * I herewith declare: this does not happen. So send SIGBUS.
- */
- goto sigbus;
-
/*
* COP2 is available to implementor for application specific use.
* It's up to applications to register a notifier chain and do
--
1.7.9.5

10 changes: 10 additions & 0 deletions pkgs/os-specific/linux/kernel/patches.nix
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,16 @@ rec {
patch = ./mips_restart.patch;
};

mips_fpureg_emu =
{ name = "mips-fpureg-emulation";
patch = ./mips-fpureg-emulation.patch;
};

mips_fpu_sigill =
{ name = "mips-fpu-sigill";
patch = ./mips-fpu-sigill.patch;
};

guruplug_defconfig =
{ # Default configuration for the GuruPlug. From
# <http://www.openplug.org/plugwiki/images/c/c6/Guruplug-patchset-2.6.33.2.tar.bz2>.
Expand Down
3 changes: 3 additions & 0 deletions pkgs/top-level/all-packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5681,6 +5681,9 @@ let
[ #kernelPatches.fbcondecor_2_6_38
kernelPatches.sec_perm_2_6_24
kernelPatches.aufs3_4
] ++ lib.optionals (platform.kernelArch == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
];
};

Expand Down

0 comments on commit 6bddc77

Please sign in to comment.