summary refs log tree commit diff
path: root/pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch
diff options
context:
space:
mode:
authorLluís Batlle i Rossell <viric@vicerveza.homeunix.net>2012-06-16 10:49:03 +0000
committerLluís Batlle i Rossell <viric@vicerveza.homeunix.net>2012-06-16 10:49:03 +0000
commit3874e5812d6cf07b6ee778c3f58df73b913bae93 (patch)
tree2d445bca9d35f58b5d02365fe166c9b2fb94d2d0 /pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch
parent404c21de2fa7ec36e92504f36a3dce95f8114704 (diff)
downloadnixpkgs-3874e5812d6cf07b6ee778c3f58df73b913bae93.tar
nixpkgs-3874e5812d6cf07b6ee778c3f58df73b913bae93.tar.gz
nixpkgs-3874e5812d6cf07b6ee778c3f58df73b913bae93.tar.bz2
nixpkgs-3874e5812d6cf07b6ee778c3f58df73b913bae93.tar.lz
nixpkgs-3874e5812d6cf07b6ee778c3f58df73b913bae93.tar.xz
nixpkgs-3874e5812d6cf07b6ee778c3f58df73b913bae93.tar.zst
nixpkgs-3874e5812d6cf07b6ee778c3f58df73b913bae93.zip
Adding two kernel patches for mips, that make the life easier on loongson2f
(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.


svn path=/nixpkgs/trunk/; revision=34522
Diffstat (limited to 'pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch')
-rw-r--r--pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch144
1 files changed, 144 insertions, 0 deletions
diff --git a/pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch b/pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch
new file mode 100644
index 00000000000..452c4f26f6f
--- /dev/null
+++ b/pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch
@@ -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
+