aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/kernel/traps.c')
-rw-r--r--arch/tile/kernel/traps.c130
1 files changed, 105 insertions, 25 deletions
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 12cb10f38527..3870abbeeaa2 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -20,6 +20,9 @@
20#include <linux/uaccess.h> 20#include <linux/uaccess.h>
21#include <linux/ptrace.h> 21#include <linux/ptrace.h>
22#include <asm/opcode-tile.h> 22#include <asm/opcode-tile.h>
23#include <asm/opcode_constants.h>
24#include <asm/stack.h>
25#include <asm/traps.h>
23 26
24#include <arch/interrupts.h> 27#include <arch/interrupts.h>
25#include <arch/spr_def.h> 28#include <arch/spr_def.h>
@@ -42,7 +45,7 @@ static int __init setup_unaligned_fixup(char *str)
42 if (strict_strtol(str, 0, &val) != 0) 45 if (strict_strtol(str, 0, &val) != 0)
43 return 0; 46 return 0;
44 unaligned_fixup = val; 47 unaligned_fixup = val;
45 printk("Fixups for unaligned data accesses are %s\n", 48 pr_info("Fixups for unaligned data accesses are %s\n",
46 unaligned_fixup >= 0 ? 49 unaligned_fixup >= 0 ?
47 (unaligned_fixup ? "enabled" : "disabled") : 50 (unaligned_fixup ? "enabled" : "disabled") :
48 "completely disabled"); 51 "completely disabled");
@@ -56,7 +59,7 @@ static int dma_disabled;
56 59
57static int __init nodma(char *str) 60static int __init nodma(char *str)
58{ 61{
59 printk("User-space DMA is disabled\n"); 62 pr_info("User-space DMA is disabled\n");
60 dma_disabled = 1; 63 dma_disabled = 1;
61 return 1; 64 return 1;
62} 65}
@@ -97,20 +100,106 @@ static int retry_gpv(unsigned int gpv_reason)
97 100
98#endif /* CHIP_HAS_TILE_DMA() */ 101#endif /* CHIP_HAS_TILE_DMA() */
99 102
100/* Defined inside do_trap(), below. */
101#ifdef __tilegx__ 103#ifdef __tilegx__
102extern tilegx_bundle_bits bpt_code; 104#define bundle_bits tilegx_bundle_bits
103#else 105#else
104extern tile_bundle_bits bpt_code; 106#define bundle_bits tile_bundle_bits
105#endif 107#endif
106 108
109extern bundle_bits bpt_code;
110
111asm(".pushsection .rodata.bpt_code,\"a\";"
112 ".align 8;"
113 "bpt_code: bpt;"
114 ".size bpt_code,.-bpt_code;"
115 ".popsection");
116
117static int special_ill(bundle_bits bundle, int *sigp, int *codep)
118{
119 int sig, code, maxcode;
120
121 if (bundle == bpt_code) {
122 *sigp = SIGTRAP;
123 *codep = TRAP_BRKPT;
124 return 1;
125 }
126
127 /* If it's a "raise" bundle, then "ill" must be in pipe X1. */
128#ifdef __tilegx__
129 if ((bundle & TILEGX_BUNDLE_MODE_MASK) != 0)
130 return 0;
131 if (get_Opcode_X1(bundle) != UNARY_OPCODE_X1)
132 return 0;
133 if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1)
134 return 0;
135#else
136 if (bundle & TILE_BUNDLE_Y_ENCODING_MASK)
137 return 0;
138 if (get_Opcode_X1(bundle) != SHUN_0_OPCODE_X1)
139 return 0;
140 if (get_UnShOpcodeExtension_X1(bundle) != UN_0_SHUN_0_OPCODE_X1)
141 return 0;
142 if (get_UnOpcodeExtension_X1(bundle) != ILL_UN_0_SHUN_0_OPCODE_X1)
143 return 0;
144#endif
145
146 /* Check that the magic distinguishers are set to mean "raise". */
147 if (get_Dest_X1(bundle) != 29 || get_SrcA_X1(bundle) != 37)
148 return 0;
149
150 /* There must be an "addli zero, zero, VAL" in X0. */
151 if (get_Opcode_X0(bundle) != ADDLI_OPCODE_X0)
152 return 0;
153 if (get_Dest_X0(bundle) != TREG_ZERO)
154 return 0;
155 if (get_SrcA_X0(bundle) != TREG_ZERO)
156 return 0;
157
158 /*
159 * Validate the proposed signal number and si_code value.
160 * Note that we embed these in the static instruction itself
161 * so that we perturb the register state as little as possible
162 * at the time of the actual fault; it's unlikely you'd ever
163 * need to dynamically choose which kind of fault to raise
164 * from user space.
165 */
166 sig = get_Imm16_X0(bundle) & 0x3f;
167 switch (sig) {
168 case SIGILL:
169 maxcode = NSIGILL;
170 break;
171 case SIGFPE:
172 maxcode = NSIGFPE;
173 break;
174 case SIGSEGV:
175 maxcode = NSIGSEGV;
176 break;
177 case SIGBUS:
178 maxcode = NSIGBUS;
179 break;
180 case SIGTRAP:
181 maxcode = NSIGTRAP;
182 break;
183 default:
184 return 0;
185 }
186 code = (get_Imm16_X0(bundle) >> 6) & 0xf;
187 if (code <= 0 || code > maxcode)
188 return 0;
189
190 /* Make it the requested signal. */
191 *sigp = sig;
192 *codep = code | __SI_FAULT;
193 return 1;
194}
195
107void __kprobes do_trap(struct pt_regs *regs, int fault_num, 196void __kprobes do_trap(struct pt_regs *regs, int fault_num,
108 unsigned long reason) 197 unsigned long reason)
109{ 198{
110 siginfo_t info = { 0 }; 199 siginfo_t info = { 0 };
111 int signo, code; 200 int signo, code;
112 unsigned long address; 201 unsigned long address;
113 __typeof__(bpt_code) instr; 202 bundle_bits instr;
114 203
115 /* Re-enable interrupts. */ 204 /* Re-enable interrupts. */
116 local_irq_enable(); 205 local_irq_enable();
@@ -122,10 +211,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
122 if (!user_mode(regs)) { 211 if (!user_mode(regs)) {
123 if (fixup_exception(regs)) /* only UNALIGN_DATA in practice */ 212 if (fixup_exception(regs)) /* only UNALIGN_DATA in practice */
124 return; 213 return;
125 printk(KERN_ALERT "Kernel took bad trap %d at PC %#lx\n", 214 pr_alert("Kernel took bad trap %d at PC %#lx\n",
126 fault_num, regs->pc); 215 fault_num, regs->pc);
127 if (fault_num == INT_GPV) 216 if (fault_num == INT_GPV)
128 printk(KERN_ALERT "GPV_REASON is %#lx\n", reason); 217 pr_alert("GPV_REASON is %#lx\n", reason);
129 show_regs(regs); 218 show_regs(regs);
130 do_exit(SIGKILL); /* FIXME: implement i386 die() */ 219 do_exit(SIGKILL); /* FIXME: implement i386 die() */
131 return; 220 return;
@@ -133,22 +222,14 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
133 222
134 switch (fault_num) { 223 switch (fault_num) {
135 case INT_ILL: 224 case INT_ILL:
136 asm(".pushsection .rodata.bpt_code,\"a\";" 225 if (copy_from_user(&instr, (void __user *)regs->pc,
137 ".align 8;" 226 sizeof(instr))) {
138 "bpt_code: bpt;" 227 pr_err("Unreadable instruction for INT_ILL:"
139 ".size bpt_code,.-bpt_code;"
140 ".popsection");
141
142 if (copy_from_user(&instr, (void *)regs->pc, sizeof(instr))) {
143 printk(KERN_ERR "Unreadable instruction for INT_ILL:"
144 " %#lx\n", regs->pc); 228 " %#lx\n", regs->pc);
145 do_exit(SIGKILL); 229 do_exit(SIGKILL);
146 return; 230 return;
147 } 231 }
148 if (instr == bpt_code) { 232 if (!special_ill(instr, &signo, &code)) {
149 signo = SIGTRAP;
150 code = TRAP_BRKPT;
151 } else {
152 signo = SIGILL; 233 signo = SIGILL;
153 code = ILL_ILLOPC; 234 code = ILL_ILLOPC;
154 } 235 }
@@ -181,7 +262,8 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
181 if (unaligned_fixup >= 0) { 262 if (unaligned_fixup >= 0) {
182 struct single_step_state *state = 263 struct single_step_state *state =
183 current_thread_info()->step_state; 264 current_thread_info()->step_state;
184 if (!state || (void *)(regs->pc) != state->buffer) { 265 if (!state ||
266 (void __user *)(regs->pc) != state->buffer) {
185 single_step_once(regs); 267 single_step_once(regs);
186 return; 268 return;
187 } 269 }
@@ -221,17 +303,15 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
221 303
222 info.si_signo = signo; 304 info.si_signo = signo;
223 info.si_code = code; 305 info.si_code = code;
224 info.si_addr = (void *)address; 306 info.si_addr = (void __user *)address;
225 if (signo == SIGILL) 307 if (signo == SIGILL)
226 info.si_trapno = fault_num; 308 info.si_trapno = fault_num;
227 force_sig_info(signo, &info, current); 309 force_sig_info(signo, &info, current);
228} 310}
229 311
230extern void _dump_stack(int dummy, ulong pc, ulong lr, ulong sp, ulong r52);
231
232void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52) 312void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
233{ 313{
234 _dump_stack(dummy, pc, lr, sp, r52); 314 _dump_stack(dummy, pc, lr, sp, r52);
235 printk("Double fault: exiting\n"); 315 pr_emerg("Double fault: exiting\n");
236 machine_halt(); 316 machine_halt();
237} 317}