diff options
| author | Vineet Gupta <vgupta@synopsys.com> | 2013-01-23 06:00:36 -0500 |
|---|---|---|
| committer | Vineet Gupta <vgupta@synopsys.com> | 2013-02-15 12:46:06 -0500 |
| commit | 2e651ea1596b0ee25af4fcdc4cd13cbb33ffc254 (patch) | |
| tree | 51210f1cd80327a00e2fd4b0d20849b6329925d6 /arch/arc | |
| parent | bf14e3b979a01cd7298d631736f965fe83c6e2bc (diff) | |
ARC: Unaligned access emulation
ARC700 doesn't natively support unaligned access, but can be emulated
-Unaligned Access Exception
-Disassembly at the Fault address to find the exact insn (long/short)
Also per Arnd's comment, we runtime control it using 2 sysctl knobs:
* SYSCTL_ARCH_UNALIGN_ALLOW: Runtime enable/disble
* SYSCTL_ARCH_UNALIGN_NO_WARN: Warn on each emulation attempt
Originally contributed by Tim Yao <tim.yao@amlogic.com>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Tim Yao <tim.yao@amlogic.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arc')
| -rw-r--r-- | arch/arc/Kconfig | 11 | ||||
| -rw-r--r-- | arch/arc/include/asm/Kbuild | 1 | ||||
| -rw-r--r-- | arch/arc/include/asm/ptrace.h | 3 | ||||
| -rw-r--r-- | arch/arc/include/asm/unaligned.h | 29 | ||||
| -rw-r--r-- | arch/arc/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/arc/kernel/disasm.c | 2 | ||||
| -rw-r--r-- | arch/arc/kernel/entry.S | 13 | ||||
| -rw-r--r-- | arch/arc/kernel/traps.c | 26 | ||||
| -rw-r--r-- | arch/arc/kernel/unaligned.c | 245 |
9 files changed, 329 insertions, 2 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index cde8d3fcec94..f8042835e746 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig | |||
| @@ -336,6 +336,17 @@ config ARC_CURR_IN_REG | |||
| 336 | This reserved Register R25 to point to Current Task in | 336 | This reserved Register R25 to point to Current Task in |
| 337 | kernel mode. This saves memory access for each such access | 337 | kernel mode. This saves memory access for each such access |
| 338 | 338 | ||
| 339 | |||
| 340 | config ARC_MISALIGN_ACCESS | ||
| 341 | bool "Emulate unaligned memory access (userspace only)" | ||
| 342 | default N | ||
| 343 | select SYSCTL_ARCH_UNALIGN_NO_WARN | ||
| 344 | select SYSCTL_ARCH_UNALIGN_ALLOW | ||
| 345 | help | ||
| 346 | This enables misaligned 16 & 32 bit memory access from user space. | ||
| 347 | Use ONLY-IF-ABS-NECESSARY as it will be very slow and also can hide | ||
| 348 | potential bugs in code | ||
| 349 | |||
| 339 | config ARC_STACK_NONEXEC | 350 | config ARC_STACK_NONEXEC |
| 340 | bool "Make stack non-executable" | 351 | bool "Make stack non-executable" |
| 341 | default n | 352 | default n |
diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild index 78e982dad537..b24089c974a9 100644 --- a/arch/arc/include/asm/Kbuild +++ b/arch/arc/include/asm/Kbuild | |||
| @@ -52,7 +52,6 @@ generic-y += topology.h | |||
| 52 | generic-y += trace_clock.h | 52 | generic-y += trace_clock.h |
| 53 | generic-y += types.h | 53 | generic-y += types.h |
| 54 | generic-y += ucontext.h | 54 | generic-y += ucontext.h |
| 55 | generic-y += unaligned.h | ||
| 56 | generic-y += user.h | 55 | generic-y += user.h |
| 57 | generic-y += vga.h | 56 | generic-y += vga.h |
| 58 | generic-y += xor.h | 57 | generic-y += xor.h |
diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 063ed0040ef7..df5b95213776 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h | |||
| @@ -97,6 +97,9 @@ struct callee_regs { | |||
| 97 | sp; \ | 97 | sp; \ |
| 98 | }) | 98 | }) |
| 99 | 99 | ||
| 100 | /* return 1 if PC in delay slot */ | ||
| 101 | #define delay_mode(regs) ((regs->status32 & STATUS_DE_MASK) == STATUS_DE_MASK) | ||
| 102 | |||
| 100 | #define in_syscall(regs) (regs->event & orig_r8_IS_SCALL) | 103 | #define in_syscall(regs) (regs->event & orig_r8_IS_SCALL) |
| 101 | #define in_brkpt_trap(regs) (regs->event & orig_r8_IS_BRKPT) | 104 | #define in_brkpt_trap(regs) (regs->event & orig_r8_IS_BRKPT) |
| 102 | 105 | ||
diff --git a/arch/arc/include/asm/unaligned.h b/arch/arc/include/asm/unaligned.h new file mode 100644 index 000000000000..5dbe63f17b66 --- /dev/null +++ b/arch/arc/include/asm/unaligned.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef _ASM_ARC_UNALIGNED_H | ||
| 10 | #define _ASM_ARC_UNALIGNED_H | ||
| 11 | |||
| 12 | /* ARC700 can't handle unaligned Data accesses. */ | ||
| 13 | |||
| 14 | #include <asm-generic/unaligned.h> | ||
| 15 | #include <asm/ptrace.h> | ||
| 16 | |||
| 17 | #ifdef CONFIG_ARC_MISALIGN_ACCESS | ||
| 18 | int misaligned_fixup(unsigned long address, struct pt_regs *regs, | ||
| 19 | unsigned long cause, struct callee_regs *cregs); | ||
| 20 | #else | ||
| 21 | static inline int | ||
| 22 | misaligned_fixup(unsigned long address, struct pt_regs *regs, | ||
| 23 | unsigned long cause, struct callee_regs *cregs) | ||
| 24 | { | ||
| 25 | return 0; | ||
| 26 | } | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #endif /* _ASM_ARC_UNALIGNED_H */ | ||
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index d331bd7047a1..507a33d4a255 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile | |||
| @@ -16,6 +16,7 @@ obj-$(CONFIG_MODULES) += arcksyms.o module.o | |||
| 16 | obj-$(CONFIG_SMP) += smp.o | 16 | obj-$(CONFIG_SMP) += smp.o |
| 17 | obj-$(CONFIG_ARC_DW2_UNWIND) += unwind.o | 17 | obj-$(CONFIG_ARC_DW2_UNWIND) += unwind.o |
| 18 | obj-$(CONFIG_KPROBES) += kprobes.o | 18 | obj-$(CONFIG_KPROBES) += kprobes.o |
| 19 | obj-$(CONFIG_ARC_MISALIGN_ACCESS) += unaligned.o | ||
| 19 | 20 | ||
| 20 | obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o | 21 | obj-$(CONFIG_ARC_FPU_SAVE_RESTORE) += fpu.o |
| 21 | CFLAGS_fpu.o += -mdpfp | 22 | CFLAGS_fpu.o += -mdpfp |
diff --git a/arch/arc/kernel/disasm.c b/arch/arc/kernel/disasm.c index 51bad8ff373b..2f390289a792 100644 --- a/arch/arc/kernel/disasm.c +++ b/arch/arc/kernel/disasm.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include <asm/disasm.h> | 15 | #include <asm/disasm.h> |
| 16 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
| 17 | 17 | ||
| 18 | #if defined(CONFIG_KGDB) || defined(CONFIG_MISALIGN_ACCESS) || \ | 18 | #if defined(CONFIG_KGDB) || defined(CONFIG_ARC_MISALIGN_ACCESS) || \ |
| 19 | defined(CONFIG_KPROBES) | 19 | defined(CONFIG_KPROBES) |
| 20 | 20 | ||
| 21 | /* disasm_instr: Analyses instruction at addr, stores | 21 | /* disasm_instr: Analyses instruction at addr, stores |
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S index 021cfa46a1dc..f8efade15368 100644 --- a/arch/arc/kernel/entry.S +++ b/arch/arc/kernel/entry.S | |||
| @@ -7,6 +7,9 @@ | |||
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * vineetg: May 2011 | ||
| 11 | * -Userspace unaligned access emulation | ||
| 12 | * | ||
| 10 | * vineetg: Feb 2011 (ptrace low level code fixes) | 13 | * vineetg: Feb 2011 (ptrace low level code fixes) |
| 11 | * -traced syscall return code (r0) was not saved into pt_regs for restoring | 14 | * -traced syscall return code (r0) was not saved into pt_regs for restoring |
| 12 | * into user reg-file when traded task rets to user space. | 15 | * into user reg-file when traded task rets to user space. |
| @@ -387,7 +390,17 @@ ARC_ENTRY EV_TLBProtV | |||
| 387 | mov r1, r4 ; faulting address | 390 | mov r1, r4 ; faulting address |
| 388 | mov r2, sp ; pt_regs | 391 | mov r2, sp ; pt_regs |
| 389 | 392 | ||
| 393 | #ifdef CONFIG_ARC_MISALIGN_ACCESS | ||
| 394 | SAVE_CALLEE_SAVED_USER | ||
| 395 | mov r3, sp ; callee_regs | ||
| 396 | #endif | ||
| 397 | |||
| 390 | bl do_misaligned_access | 398 | bl do_misaligned_access |
| 399 | |||
| 400 | #ifdef CONFIG_ARC_MISALIGN_ACCESS | ||
| 401 | DISCARD_CALLEE_SAVED_USER | ||
| 402 | #endif | ||
| 403 | |||
| 391 | b ret_from_exception | 404 | b ret_from_exception |
| 392 | 405 | ||
| 393 | ARC_EXIT EV_TLBProtV | 406 | ARC_EXIT EV_TLBProtV |
diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c index c6396b48fcd2..ec802c52a1ca 100644 --- a/arch/arc/kernel/traps.c +++ b/arch/arc/kernel/traps.c | |||
| @@ -7,6 +7,9 @@ | |||
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * vineetg: May 2011 | ||
| 11 | * -user-space unaligned access emulation | ||
| 12 | * | ||
| 10 | * Rahul Trivedi: Codito Technologies 2004 | 13 | * Rahul Trivedi: Codito Technologies 2004 |
| 11 | */ | 14 | */ |
| 12 | 15 | ||
| @@ -16,6 +19,7 @@ | |||
| 16 | #include <asm/ptrace.h> | 19 | #include <asm/ptrace.h> |
| 17 | #include <asm/setup.h> | 20 | #include <asm/setup.h> |
| 18 | #include <asm/kprobes.h> | 21 | #include <asm/kprobes.h> |
| 22 | #include <asm/unaligned.h> | ||
| 19 | 23 | ||
| 20 | void __init trap_init(void) | 24 | void __init trap_init(void) |
| 21 | { | 25 | { |
| @@ -79,7 +83,29 @@ DO_ERROR_INFO(SIGILL, "Illegal Insn (or Seq)", insterror_is_error, ILL_ILLOPC) | |||
| 79 | DO_ERROR_INFO(SIGBUS, "Invalid Mem Access", do_memory_error, BUS_ADRERR) | 83 | DO_ERROR_INFO(SIGBUS, "Invalid Mem Access", do_memory_error, BUS_ADRERR) |
| 80 | DO_ERROR_INFO(SIGTRAP, "Breakpoint Set", trap_is_brkpt, TRAP_BRKPT) | 84 | DO_ERROR_INFO(SIGTRAP, "Breakpoint Set", trap_is_brkpt, TRAP_BRKPT) |
| 81 | 85 | ||
| 86 | #ifdef CONFIG_ARC_MISALIGN_ACCESS | ||
| 87 | /* | ||
| 88 | * Entry Point for Misaligned Data access Exception, for emulating in software | ||
| 89 | */ | ||
| 90 | int do_misaligned_access(unsigned long cause, unsigned long address, | ||
| 91 | struct pt_regs *regs, struct callee_regs *cregs) | ||
| 92 | { | ||
| 93 | if (misaligned_fixup(address, regs, cause, cregs) != 0) { | ||
| 94 | siginfo_t info; | ||
| 95 | |||
| 96 | info.si_signo = SIGBUS; | ||
| 97 | info.si_errno = 0; | ||
| 98 | info.si_code = BUS_ADRALN; | ||
| 99 | info.si_addr = (void __user *)address; | ||
| 100 | return handle_exception(cause, "Misaligned Access", regs, | ||
| 101 | &info); | ||
| 102 | } | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | #else | ||
| 82 | DO_ERROR_INFO(SIGSEGV, "Misaligned Access", do_misaligned_access, SEGV_ACCERR) | 107 | DO_ERROR_INFO(SIGSEGV, "Misaligned Access", do_misaligned_access, SEGV_ACCERR) |
| 108 | #endif | ||
| 83 | 109 | ||
| 84 | /* | 110 | /* |
| 85 | * Entry point for miscll errors such as Nested Exceptions | 111 | * Entry point for miscll errors such as Nested Exceptions |
diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c new file mode 100644 index 000000000000..4cd81633febd --- /dev/null +++ b/arch/arc/kernel/unaligned.c | |||
| @@ -0,0 +1,245 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011-2012 Synopsys (www.synopsys.com) | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * vineetg : May 2011 | ||
| 9 | * -Adapted (from .26 to .35) | ||
| 10 | * -original contribution by Tim.yao@amlogic.com | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/ptrace.h> | ||
| 16 | #include <linux/uaccess.h> | ||
| 17 | #include <asm/disasm.h> | ||
| 18 | |||
| 19 | #define __get8_unaligned_check(val, addr, err) \ | ||
| 20 | __asm__( \ | ||
| 21 | "1: ldb.ab %1, [%2, 1]\n" \ | ||
| 22 | "2:\n" \ | ||
| 23 | " .section .fixup,\"ax\"\n" \ | ||
| 24 | " .align 4\n" \ | ||
| 25 | "3: mov %0, 1\n" \ | ||
| 26 | " b 2b\n" \ | ||
| 27 | " .previous\n" \ | ||
| 28 | " .section __ex_table,\"a\"\n" \ | ||
| 29 | " .align 4\n" \ | ||
| 30 | " .long 1b, 3b\n" \ | ||
| 31 | " .previous\n" \ | ||
| 32 | : "=r" (err), "=&r" (val), "=r" (addr) \ | ||
| 33 | : "0" (err), "2" (addr)) | ||
| 34 | |||
| 35 | #define get16_unaligned_check(val, addr) \ | ||
| 36 | do { \ | ||
| 37 | unsigned int err = 0, v, a = addr; \ | ||
| 38 | __get8_unaligned_check(v, a, err); \ | ||
| 39 | val = v ; \ | ||
| 40 | __get8_unaligned_check(v, a, err); \ | ||
| 41 | val |= v << 8; \ | ||
| 42 | if (err) \ | ||
| 43 | goto fault; \ | ||
| 44 | } while (0) | ||
| 45 | |||
| 46 | #define get32_unaligned_check(val, addr) \ | ||
| 47 | do { \ | ||
| 48 | unsigned int err = 0, v, a = addr; \ | ||
| 49 | __get8_unaligned_check(v, a, err); \ | ||
| 50 | val = v << 0; \ | ||
| 51 | __get8_unaligned_check(v, a, err); \ | ||
| 52 | val |= v << 8; \ | ||
| 53 | __get8_unaligned_check(v, a, err); \ | ||
| 54 | val |= v << 16; \ | ||
| 55 | __get8_unaligned_check(v, a, err); \ | ||
| 56 | val |= v << 24; \ | ||
| 57 | if (err) \ | ||
| 58 | goto fault; \ | ||
| 59 | } while (0) | ||
| 60 | |||
| 61 | #define put16_unaligned_check(val, addr) \ | ||
| 62 | do { \ | ||
| 63 | unsigned int err = 0, v = val, a = addr;\ | ||
| 64 | \ | ||
| 65 | __asm__( \ | ||
| 66 | "1: stb.ab %1, [%2, 1]\n" \ | ||
| 67 | " lsr %1, %1, 8\n" \ | ||
| 68 | "2: stb %1, [%2]\n" \ | ||
| 69 | "3:\n" \ | ||
| 70 | " .section .fixup,\"ax\"\n" \ | ||
| 71 | " .align 4\n" \ | ||
| 72 | "4: mov %0, 1\n" \ | ||
| 73 | " b 3b\n" \ | ||
| 74 | " .previous\n" \ | ||
| 75 | " .section __ex_table,\"a\"\n" \ | ||
| 76 | " .align 4\n" \ | ||
| 77 | " .long 1b, 4b\n" \ | ||
| 78 | " .long 2b, 4b\n" \ | ||
| 79 | " .previous\n" \ | ||
| 80 | : "=r" (err), "=&r" (v), "=&r" (a) \ | ||
| 81 | : "0" (err), "1" (v), "2" (a)); \ | ||
| 82 | \ | ||
| 83 | if (err) \ | ||
| 84 | goto fault; \ | ||
| 85 | } while (0) | ||
| 86 | |||
| 87 | #define put32_unaligned_check(val, addr) \ | ||
| 88 | do { \ | ||
| 89 | unsigned int err = 0, v = val, a = addr;\ | ||
| 90 | __asm__( \ | ||
| 91 | \ | ||
| 92 | "1: stb.ab %1, [%2, 1]\n" \ | ||
| 93 | " lsr %1, %1, 8\n" \ | ||
| 94 | "2: stb.ab %1, [%2, 1]\n" \ | ||
| 95 | " lsr %1, %1, 8\n" \ | ||
| 96 | "3: stb.ab %1, [%2, 1]\n" \ | ||
| 97 | " lsr %1, %1, 8\n" \ | ||
| 98 | "4: stb %1, [%2]\n" \ | ||
| 99 | "5:\n" \ | ||
| 100 | " .section .fixup,\"ax\"\n" \ | ||
| 101 | " .align 4\n" \ | ||
| 102 | "6: mov %0, 1\n" \ | ||
| 103 | " b 5b\n" \ | ||
| 104 | " .previous\n" \ | ||
| 105 | " .section __ex_table,\"a\"\n" \ | ||
| 106 | " .align 4\n" \ | ||
| 107 | " .long 1b, 6b\n" \ | ||
| 108 | " .long 2b, 6b\n" \ | ||
| 109 | " .long 3b, 6b\n" \ | ||
| 110 | " .long 4b, 6b\n" \ | ||
| 111 | " .previous\n" \ | ||
| 112 | : "=r" (err), "=&r" (v), "=&r" (a) \ | ||
| 113 | : "0" (err), "1" (v), "2" (a)); \ | ||
| 114 | \ | ||
| 115 | if (err) \ | ||
| 116 | goto fault; \ | ||
| 117 | } while (0) | ||
| 118 | |||
| 119 | /* sysctl hooks */ | ||
| 120 | int unaligned_enabled __read_mostly = 1; /* Enabled by default */ | ||
| 121 | int no_unaligned_warning __read_mostly = 1; /* Only 1 warning by default */ | ||
| 122 | |||
| 123 | static void fixup_load(struct disasm_state *state, struct pt_regs *regs, | ||
| 124 | struct callee_regs *cregs) | ||
| 125 | { | ||
| 126 | int val; | ||
| 127 | |||
| 128 | /* register write back */ | ||
| 129 | if ((state->aa == 1) || (state->aa == 2)) { | ||
| 130 | set_reg(state->wb_reg, state->src1 + state->src2, regs, cregs); | ||
| 131 | |||
| 132 | if (state->aa == 2) | ||
| 133 | state->src2 = 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | if (state->zz == 0) { | ||
| 137 | get32_unaligned_check(val, state->src1 + state->src2); | ||
| 138 | } else { | ||
| 139 | get16_unaligned_check(val, state->src1 + state->src2); | ||
| 140 | |||
| 141 | if (state->x) | ||
| 142 | val = (val << 16) >> 16; | ||
| 143 | } | ||
| 144 | |||
| 145 | if (state->pref == 0) | ||
| 146 | set_reg(state->dest, val, regs, cregs); | ||
| 147 | |||
| 148 | return; | ||
| 149 | |||
| 150 | fault: state->fault = 1; | ||
| 151 | } | ||
| 152 | |||
| 153 | static void fixup_store(struct disasm_state *state, struct pt_regs *regs, | ||
| 154 | struct callee_regs *cregs) | ||
| 155 | { | ||
| 156 | /* register write back */ | ||
| 157 | if ((state->aa == 1) || (state->aa == 2)) { | ||
| 158 | set_reg(state->wb_reg, state->src2 + state->src3, regs, cregs); | ||
| 159 | |||
| 160 | if (state->aa == 3) | ||
| 161 | state->src3 = 0; | ||
| 162 | } else if (state->aa == 3) { | ||
| 163 | if (state->zz == 2) { | ||
| 164 | set_reg(state->wb_reg, state->src2 + (state->src3 << 1), | ||
| 165 | regs, cregs); | ||
| 166 | } else if (!state->zz) { | ||
| 167 | set_reg(state->wb_reg, state->src2 + (state->src3 << 2), | ||
| 168 | regs, cregs); | ||
| 169 | } else { | ||
| 170 | goto fault; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | /* write fix-up */ | ||
| 175 | if (!state->zz) | ||
| 176 | put32_unaligned_check(state->src1, state->src2 + state->src3); | ||
| 177 | else | ||
| 178 | put16_unaligned_check(state->src1, state->src2 + state->src3); | ||
| 179 | |||
| 180 | return; | ||
| 181 | |||
| 182 | fault: state->fault = 1; | ||
| 183 | } | ||
| 184 | |||
| 185 | /* | ||
| 186 | * Handle an unaligned access | ||
| 187 | * Returns 0 if successfully handled, 1 if some error happened | ||
| 188 | */ | ||
| 189 | int misaligned_fixup(unsigned long address, struct pt_regs *regs, | ||
| 190 | unsigned long cause, struct callee_regs *cregs) | ||
| 191 | { | ||
| 192 | struct disasm_state state; | ||
| 193 | char buf[TASK_COMM_LEN]; | ||
| 194 | |||
| 195 | /* handle user mode only and only if enabled by sysadmin */ | ||
| 196 | if (!user_mode(regs) || !unaligned_enabled) | ||
| 197 | return 1; | ||
| 198 | |||
| 199 | if (no_unaligned_warning) { | ||
| 200 | pr_warn_once("%s(%d) made unaligned access which was emulated" | ||
| 201 | " by kernel assist\n. This can degrade application" | ||
| 202 | " performance significantly\n. To enable further" | ||
| 203 | " logging of such instances, please \n" | ||
| 204 | " echo 0 > /proc/sys/kernel/ignore-unaligned-usertrap\n", | ||
| 205 | get_task_comm(buf, current), task_pid_nr(current)); | ||
| 206 | } else { | ||
| 207 | /* Add rate limiting if it gets down to it */ | ||
| 208 | pr_warn("%s(%d): unaligned access to/from 0x%lx by PC: 0x%lx\n", | ||
| 209 | get_task_comm(buf, current), task_pid_nr(current), | ||
| 210 | address, regs->ret); | ||
| 211 | |||
| 212 | } | ||
| 213 | |||
| 214 | disasm_instr(regs->ret, &state, 1, regs, cregs); | ||
| 215 | |||
| 216 | if (state.fault) | ||
| 217 | goto fault; | ||
| 218 | |||
| 219 | /* ldb/stb should not have unaligned exception */ | ||
| 220 | if ((state.zz == 1) || (state.di)) | ||
| 221 | goto fault; | ||
| 222 | |||
| 223 | if (!state.write) | ||
| 224 | fixup_load(&state, regs, cregs); | ||
| 225 | else | ||
| 226 | fixup_store(&state, regs, cregs); | ||
| 227 | |||
| 228 | if (state.fault) | ||
| 229 | goto fault; | ||
| 230 | |||
| 231 | if (delay_mode(regs)) { | ||
| 232 | regs->ret = regs->bta; | ||
| 233 | regs->status32 &= ~STATUS_DE_MASK; | ||
| 234 | } else { | ||
| 235 | regs->ret += state.instr_len; | ||
| 236 | } | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | |||
| 240 | fault: | ||
| 241 | pr_err("Alignment trap: fault in fix-up %08lx at [<%08lx>]\n", | ||
| 242 | state.words[0], address); | ||
| 243 | |||
| 244 | return 1; | ||
| 245 | } | ||
