diff options
Diffstat (limited to 'arch/tile/kernel/single_step.c')
-rw-r--r-- | arch/tile/kernel/single_step.c | 75 |
1 files changed, 41 insertions, 34 deletions
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 266aae123632..5ec4b9c651f2 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <linux/mman.h> | 24 | #include <linux/mman.h> |
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <linux/err.h> | ||
26 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
27 | #include <asm/opcode-tile.h> | 28 | #include <asm/opcode-tile.h> |
28 | #include <asm/opcode_constants.h> | 29 | #include <asm/opcode_constants.h> |
@@ -39,8 +40,8 @@ static int __init setup_unaligned_printk(char *str) | |||
39 | if (strict_strtol(str, 0, &val) != 0) | 40 | if (strict_strtol(str, 0, &val) != 0) |
40 | return 0; | 41 | return 0; |
41 | unaligned_printk = val; | 42 | unaligned_printk = val; |
42 | printk("Printk for each unaligned data accesses is %s\n", | 43 | pr_info("Printk for each unaligned data accesses is %s\n", |
43 | unaligned_printk ? "enabled" : "disabled"); | 44 | unaligned_printk ? "enabled" : "disabled"); |
44 | return 1; | 45 | return 1; |
45 | } | 46 | } |
46 | __setup("unaligned_printk=", setup_unaligned_printk); | 47 | __setup("unaligned_printk=", setup_unaligned_printk); |
@@ -113,7 +114,7 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
113 | enum mem_op mem_op, | 114 | enum mem_op mem_op, |
114 | int size, int sign_ext) | 115 | int size, int sign_ext) |
115 | { | 116 | { |
116 | unsigned char *addr; | 117 | unsigned char __user *addr; |
117 | int val_reg, addr_reg, err, val; | 118 | int val_reg, addr_reg, err, val; |
118 | 119 | ||
119 | /* Get address and value registers */ | 120 | /* Get address and value registers */ |
@@ -148,7 +149,7 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
148 | return bundle; | 149 | return bundle; |
149 | 150 | ||
150 | /* If it's aligned, don't handle it specially */ | 151 | /* If it's aligned, don't handle it specially */ |
151 | addr = (void *)regs->regs[addr_reg]; | 152 | addr = (void __user *)regs->regs[addr_reg]; |
152 | if (((unsigned long)addr % size) == 0) | 153 | if (((unsigned long)addr % size) == 0) |
153 | return bundle; | 154 | return bundle; |
154 | 155 | ||
@@ -183,7 +184,7 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
183 | siginfo_t info = { | 184 | siginfo_t info = { |
184 | .si_signo = SIGSEGV, | 185 | .si_signo = SIGSEGV, |
185 | .si_code = SEGV_MAPERR, | 186 | .si_code = SEGV_MAPERR, |
186 | .si_addr = (void __user *)addr | 187 | .si_addr = addr |
187 | }; | 188 | }; |
188 | force_sig_info(info.si_signo, &info, current); | 189 | force_sig_info(info.si_signo, &info, current); |
189 | return (tile_bundle_bits) 0; | 190 | return (tile_bundle_bits) 0; |
@@ -193,30 +194,33 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
193 | siginfo_t info = { | 194 | siginfo_t info = { |
194 | .si_signo = SIGBUS, | 195 | .si_signo = SIGBUS, |
195 | .si_code = BUS_ADRALN, | 196 | .si_code = BUS_ADRALN, |
196 | .si_addr = (void __user *)addr | 197 | .si_addr = addr |
197 | }; | 198 | }; |
198 | force_sig_info(info.si_signo, &info, current); | 199 | force_sig_info(info.si_signo, &info, current); |
199 | return (tile_bundle_bits) 0; | 200 | return (tile_bundle_bits) 0; |
200 | } | 201 | } |
201 | 202 | ||
202 | if (unaligned_printk || unaligned_fixup_count == 0) { | 203 | if (unaligned_printk || unaligned_fixup_count == 0) { |
203 | printk("Process %d/%s: PC %#lx: Fixup of" | 204 | pr_info("Process %d/%s: PC %#lx: Fixup of" |
204 | " unaligned %s at %#lx.\n", | 205 | " unaligned %s at %#lx.\n", |
205 | current->pid, current->comm, regs->pc, | 206 | current->pid, current->comm, regs->pc, |
206 | (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) ? | 207 | (mem_op == MEMOP_LOAD || |
207 | "load" : "store", | 208 | mem_op == MEMOP_LOAD_POSTINCR) ? |
208 | (unsigned long)addr); | 209 | "load" : "store", |
210 | (unsigned long)addr); | ||
209 | if (!unaligned_printk) { | 211 | if (!unaligned_printk) { |
210 | printk("\n" | 212 | #define P pr_info |
211 | "Unaligned fixups in the kernel will slow your application considerably.\n" | 213 | P("\n"); |
212 | "You can find them by writing \"1\" to /proc/sys/tile/unaligned_fixup/printk,\n" | 214 | P("Unaligned fixups in the kernel will slow your application considerably.\n"); |
213 | "which requests the kernel show all unaligned fixups, or writing a \"0\"\n" | 215 | P("To find them, write a \"1\" to /proc/sys/tile/unaligned_fixup/printk,\n"); |
214 | "to /proc/sys/tile/unaligned_fixup/enabled, in which case each unaligned\n" | 216 | P("which requests the kernel show all unaligned fixups, or write a \"0\"\n"); |
215 | "access will become a SIGBUS you can debug. No further warnings will be\n" | 217 | P("to /proc/sys/tile/unaligned_fixup/enabled, in which case each unaligned\n"); |
216 | "shown so as to avoid additional slowdown, but you can track the number\n" | 218 | P("access will become a SIGBUS you can debug. No further warnings will be\n"); |
217 | "of fixups performed via /proc/sys/tile/unaligned_fixup/count.\n" | 219 | P("shown so as to avoid additional slowdown, but you can track the number\n"); |
218 | "Use the tile-addr2line command (see \"info addr2line\") to decode PCs.\n" | 220 | P("of fixups performed via /proc/sys/tile/unaligned_fixup/count.\n"); |
219 | "\n"); | 221 | P("Use the tile-addr2line command (see \"info addr2line\") to decode PCs.\n"); |
222 | P("\n"); | ||
223 | #undef P | ||
220 | } | 224 | } |
221 | } | 225 | } |
222 | ++unaligned_fixup_count; | 226 | ++unaligned_fixup_count; |
@@ -276,7 +280,7 @@ void single_step_once(struct pt_regs *regs) | |||
276 | struct thread_info *info = (void *)current_thread_info(); | 280 | struct thread_info *info = (void *)current_thread_info(); |
277 | struct single_step_state *state = info->step_state; | 281 | struct single_step_state *state = info->step_state; |
278 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); | 282 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); |
279 | tile_bundle_bits *buffer, *pc; | 283 | tile_bundle_bits __user *buffer, *pc; |
280 | tile_bundle_bits bundle; | 284 | tile_bundle_bits bundle; |
281 | int temp_reg; | 285 | int temp_reg; |
282 | int target_reg = TREG_LR; | 286 | int target_reg = TREG_LR; |
@@ -306,21 +310,21 @@ void single_step_once(struct pt_regs *regs) | |||
306 | /* allocate a page of writable, executable memory */ | 310 | /* allocate a page of writable, executable memory */ |
307 | state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL); | 311 | state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL); |
308 | if (state == NULL) { | 312 | if (state == NULL) { |
309 | printk("Out of kernel memory trying to single-step\n"); | 313 | pr_err("Out of kernel memory trying to single-step\n"); |
310 | return; | 314 | return; |
311 | } | 315 | } |
312 | 316 | ||
313 | /* allocate a cache line of writable, executable memory */ | 317 | /* allocate a cache line of writable, executable memory */ |
314 | down_write(¤t->mm->mmap_sem); | 318 | down_write(¤t->mm->mmap_sem); |
315 | buffer = (void *) do_mmap(0, 0, 64, | 319 | buffer = (void __user *) do_mmap(NULL, 0, 64, |
316 | PROT_EXEC | PROT_READ | PROT_WRITE, | 320 | PROT_EXEC | PROT_READ | PROT_WRITE, |
317 | MAP_PRIVATE | MAP_ANONYMOUS, | 321 | MAP_PRIVATE | MAP_ANONYMOUS, |
318 | 0); | 322 | 0); |
319 | up_write(¤t->mm->mmap_sem); | 323 | up_write(¤t->mm->mmap_sem); |
320 | 324 | ||
321 | if ((int)buffer < 0 && (int)buffer > -PAGE_SIZE) { | 325 | if (IS_ERR((void __force *)buffer)) { |
322 | kfree(state); | 326 | kfree(state); |
323 | printk("Out of kernel pages trying to single-step\n"); | 327 | pr_err("Out of kernel pages trying to single-step\n"); |
324 | return; | 328 | return; |
325 | } | 329 | } |
326 | 330 | ||
@@ -349,11 +353,14 @@ void single_step_once(struct pt_regs *regs) | |||
349 | if (regs->faultnum == INT_SWINT_1) | 353 | if (regs->faultnum == INT_SWINT_1) |
350 | regs->pc -= 8; | 354 | regs->pc -= 8; |
351 | 355 | ||
352 | pc = (tile_bundle_bits *)(regs->pc); | 356 | pc = (tile_bundle_bits __user *)(regs->pc); |
353 | bundle = pc[0]; | 357 | if (get_user(bundle, pc) != 0) { |
358 | pr_err("Couldn't read instruction at %p trying to step\n", pc); | ||
359 | return; | ||
360 | } | ||
354 | 361 | ||
355 | /* We'll follow the instruction with 2 ill op bundles */ | 362 | /* We'll follow the instruction with 2 ill op bundles */ |
356 | state->orig_pc = (unsigned long) pc; | 363 | state->orig_pc = (unsigned long)pc; |
357 | state->next_pc = (unsigned long)(pc + 1); | 364 | state->next_pc = (unsigned long)(pc + 1); |
358 | state->branch_next_pc = 0; | 365 | state->branch_next_pc = 0; |
359 | state->update = 0; | 366 | state->update = 0; |
@@ -633,7 +640,7 @@ void single_step_once(struct pt_regs *regs) | |||
633 | } | 640 | } |
634 | 641 | ||
635 | if (err) { | 642 | if (err) { |
636 | printk("Fault when writing to single-step buffer\n"); | 643 | pr_err("Fault when writing to single-step buffer\n"); |
637 | return; | 644 | return; |
638 | } | 645 | } |
639 | 646 | ||
@@ -641,12 +648,12 @@ void single_step_once(struct pt_regs *regs) | |||
641 | * Flush the buffer. | 648 | * Flush the buffer. |
642 | * We do a local flush only, since this is a thread-specific buffer. | 649 | * We do a local flush only, since this is a thread-specific buffer. |
643 | */ | 650 | */ |
644 | __flush_icache_range((unsigned long) state->buffer, | 651 | __flush_icache_range((unsigned long)state->buffer, |
645 | (unsigned long) buffer); | 652 | (unsigned long)buffer); |
646 | 653 | ||
647 | /* Indicate enabled */ | 654 | /* Indicate enabled */ |
648 | state->is_enabled = is_single_step; | 655 | state->is_enabled = is_single_step; |
649 | regs->pc = (unsigned long) state->buffer; | 656 | regs->pc = (unsigned long)state->buffer; |
650 | 657 | ||
651 | /* Fault immediately if we are coming back from a syscall. */ | 658 | /* Fault immediately if we are coming back from a syscall. */ |
652 | if (regs->faultnum == INT_SWINT_1) | 659 | if (regs->faultnum == INT_SWINT_1) |