From 3874e5812d6cf07b6ee778c3f58df73b913bae93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Batlle=20i=20Rossell?= Date: Sat, 16 Jun 2012 10:49:03 +0000 Subject: [PATCH] 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 --- .../linux/kernel/mips-fpu-sigill.patch | 108 +++++++++++++ .../linux/kernel/mips-fpureg-emulation.patch | 144 ++++++++++++++++++ pkgs/os-specific/linux/kernel/patches.nix | 10 ++ pkgs/top-level/all-packages.nix | 3 + 4 files changed, 265 insertions(+) create mode 100644 pkgs/os-specific/linux/kernel/mips-fpu-sigill.patch create mode 100644 pkgs/os-specific/linux/kernel/mips-fpureg-emulation.patch diff --git a/pkgs/os-specific/linux/kernel/mips-fpu-sigill.patch b/pkgs/os-specific/linux/kernel/mips-fpu-sigill.patch new file mode 100644 index 000000000000..5a54f77dcb85 --- /dev/null +++ b/pkgs/os-specific/linux/kernel/mips-fpu-sigill.patch @@ -0,0 +1,108 @@ +From bf55ef4e3c2f622ac013f196affbd11b67b59223 Mon Sep 17 00:00:00 2001 +From: Mark H Weaver +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 +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 + 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 000000000000..452c4f26f6fd --- /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 +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 +--- + 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 + #include + #include ++#include + + #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 + diff --git a/pkgs/os-specific/linux/kernel/patches.nix b/pkgs/os-specific/linux/kernel/patches.nix index 7aefc7c5c0f6..4ac33380398a 100644 --- a/pkgs/os-specific/linux/kernel/patches.nix +++ b/pkgs/os-specific/linux/kernel/patches.nix @@ -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 # . diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 843379dbd4d6..f3131898bd38 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -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 ]; };