145 lines
4.0 KiB
Diff
145 lines
4.0 KiB
Diff
|
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
|
||
|
|