aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/traps_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r--arch/sh/kernel/traps_32.c151
1 files changed, 17 insertions, 134 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index efcbdfe52f52..204def6ecb6a 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -24,11 +24,10 @@
24#include <linux/kdebug.h> 24#include <linux/kdebug.h>
25#include <linux/kexec.h> 25#include <linux/kexec.h>
26#include <linux/limits.h> 26#include <linux/limits.h>
27#include <linux/proc_fs.h>
28#include <linux/seq_file.h>
29#include <linux/sysfs.h> 27#include <linux/sysfs.h>
28#include <linux/uaccess.h>
30#include <asm/system.h> 29#include <asm/system.h>
31#include <asm/uaccess.h> 30#include <asm/alignment.h>
32#include <asm/fpu.h> 31#include <asm/fpu.h>
33#include <asm/kprobes.h> 32#include <asm/kprobes.h>
34#include <asm/sh_bios.h> 33#include <asm/sh_bios.h>
@@ -48,73 +47,6 @@
48#define TRAP_ILLEGAL_SLOT_INST 13 47#define TRAP_ILLEGAL_SLOT_INST 13
49#endif 48#endif
50 49
51static unsigned long se_user;
52static unsigned long se_sys;
53static unsigned long se_half;
54static unsigned long se_word;
55static unsigned long se_dword;
56static unsigned long se_multi;
57/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not
58 valid! */
59static int se_usermode = 3;
60/* 0: no warning 1: print a warning message, disabled by default */
61static int se_kernmode_warn;
62
63#ifdef CONFIG_PROC_FS
64static const char *se_usermode_action[] = {
65 "ignored",
66 "warn",
67 "fixup",
68 "fixup+warn",
69 "signal",
70 "signal+warn"
71};
72
73static int alignment_proc_show(struct seq_file *m, void *v)
74{
75 seq_printf(m, "User:\t\t%lu\n", se_user);
76 seq_printf(m, "System:\t\t%lu\n", se_sys);
77 seq_printf(m, "Half:\t\t%lu\n", se_half);
78 seq_printf(m, "Word:\t\t%lu\n", se_word);
79 seq_printf(m, "DWord:\t\t%lu\n", se_dword);
80 seq_printf(m, "Multi:\t\t%lu\n", se_multi);
81 seq_printf(m, "User faults:\t%i (%s)\n", se_usermode,
82 se_usermode_action[se_usermode]);
83 seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
84 se_kernmode_warn ? "+warn" : "");
85 return 0;
86}
87
88static int alignment_proc_open(struct inode *inode, struct file *file)
89{
90 return single_open(file, alignment_proc_show, NULL);
91}
92
93static ssize_t alignment_proc_write(struct file *file,
94 const char __user *buffer, size_t count, loff_t *pos)
95{
96 int *data = PDE(file->f_path.dentry->d_inode)->data;
97 char mode;
98
99 if (count > 0) {
100 if (get_user(mode, buffer))
101 return -EFAULT;
102 if (mode >= '0' && mode <= '5')
103 *data = mode - '0';
104 }
105 return count;
106}
107
108static const struct file_operations alignment_proc_fops = {
109 .owner = THIS_MODULE,
110 .open = alignment_proc_open,
111 .read = seq_read,
112 .llseek = seq_lseek,
113 .release = single_release,
114 .write = alignment_proc_write,
115};
116#endif
117
118static void dump_mem(const char *str, unsigned long bottom, unsigned long top) 50static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
119{ 51{
120 unsigned long p; 52 unsigned long p;
@@ -266,10 +198,10 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs,
266 count = 1<<(instruction&3); 198 count = 1<<(instruction&3);
267 199
268 switch (count) { 200 switch (count) {
269 case 1: se_half += 1; break; 201 case 1: inc_unaligned_byte_access(); break;
270 case 2: se_word += 1; break; 202 case 2: inc_unaligned_word_access(); break;
271 case 4: se_dword += 1; break; 203 case 4: inc_unaligned_dword_access(); break;
272 case 8: se_multi += 1; break; /* ??? */ 204 case 8: inc_unaligned_multi_access(); break;
273 } 205 }
274 206
275 ret = -EFAULT; 207 ret = -EFAULT;
@@ -453,18 +385,8 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
453 rm = regs->regs[index]; 385 rm = regs->regs[index];
454 386
455 /* shout about fixups */ 387 /* shout about fixups */
456 if (!expected) { 388 if (!expected)
457 if (user_mode(regs) && (se_usermode & 1) && printk_ratelimit()) 389 unaligned_fixups_notify(current, instruction, regs);
458 pr_notice("Fixing up unaligned userspace access "
459 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
460 current->comm, task_pid_nr(current),
461 (void *)regs->pc, instruction);
462 else if (se_kernmode_warn && printk_ratelimit())
463 pr_notice("Fixing up unaligned kernel access "
464 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
465 current->comm, task_pid_nr(current),
466 (void *)regs->pc, instruction);
467 }
468 390
469 ret = -EFAULT; 391 ret = -EFAULT;
470 switch (instruction&0xF000) { 392 switch (instruction&0xF000) {
@@ -617,10 +539,10 @@ asmlinkage void do_address_error(struct pt_regs *regs,
617 539
618 if (user_mode(regs)) { 540 if (user_mode(regs)) {
619 int si_code = BUS_ADRERR; 541 int si_code = BUS_ADRERR;
542 unsigned int user_action;
620 543
621 local_irq_enable(); 544 local_irq_enable();
622 545 inc_unaligned_user_access();
623 se_user += 1;
624 546
625 set_fs(USER_DS); 547 set_fs(USER_DS);
626 if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1), 548 if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1),
@@ -631,16 +553,12 @@ asmlinkage void do_address_error(struct pt_regs *regs,
631 set_fs(oldfs); 553 set_fs(oldfs);
632 554
633 /* shout about userspace fixups */ 555 /* shout about userspace fixups */
634 if (se_usermode & 1) 556 unaligned_fixups_notify(current, instruction, regs);
635 printk(KERN_NOTICE "Unaligned userspace access "
636 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
637 current->comm, current->pid, (void *)regs->pc,
638 instruction);
639 557
640 if (se_usermode & 2) 558 user_action = unaligned_user_action();
559 if (user_action & UM_FIXUP)
641 goto fixup; 560 goto fixup;
642 561 if (user_action & UM_SIGNAL)
643 if (se_usermode & 4)
644 goto uspace_segv; 562 goto uspace_segv;
645 else { 563 else {
646 /* ignore */ 564 /* ignore */
@@ -660,7 +578,7 @@ fixup:
660 &user_mem_access, 0); 578 &user_mem_access, 0);
661 set_fs(oldfs); 579 set_fs(oldfs);
662 580
663 if (tmp==0) 581 if (tmp == 0)
664 return; /* sorted */ 582 return; /* sorted */
665uspace_segv: 583uspace_segv:
666 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " 584 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
@@ -673,7 +591,7 @@ uspace_segv:
673 info.si_addr = (void __user *)address; 591 info.si_addr = (void __user *)address;
674 force_sig_info(SIGBUS, &info, current); 592 force_sig_info(SIGBUS, &info, current);
675 } else { 593 } else {
676 se_sys += 1; 594 inc_unaligned_kernel_access();
677 595
678 if (regs->pc & 1) 596 if (regs->pc & 1)
679 die("unaligned program counter", regs, error_code); 597 die("unaligned program counter", regs, error_code);
@@ -688,11 +606,7 @@ uspace_segv:
688 die("insn faulting in do_address_error", regs, 0); 606 die("insn faulting in do_address_error", regs, 0);
689 } 607 }
690 608
691 if (se_kernmode_warn) 609 unaligned_fixups_notify(current, instruction, regs);
692 printk(KERN_NOTICE "Unaligned kernel access "
693 "on behalf of \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
694 current->comm, current->pid, (void *)regs->pc,
695 instruction);
696 610
697 handle_unaligned_access(instruction, regs, 611 handle_unaligned_access(instruction, regs,
698 &user_mem_access, 0); 612 &user_mem_access, 0);
@@ -964,34 +878,3 @@ void dump_stack(void)
964 show_stack(NULL, NULL); 878 show_stack(NULL, NULL);
965} 879}
966EXPORT_SYMBOL(dump_stack); 880EXPORT_SYMBOL(dump_stack);
967
968#ifdef CONFIG_PROC_FS
969/*
970 * This needs to be done after sysctl_init, otherwise sys/ will be
971 * overwritten. Actually, this shouldn't be in sys/ at all since
972 * it isn't a sysctl, and it doesn't contain sysctl information.
973 * We now locate it in /proc/cpu/alignment instead.
974 */
975static int __init alignment_init(void)
976{
977 struct proc_dir_entry *dir, *res;
978
979 dir = proc_mkdir("cpu", NULL);
980 if (!dir)
981 return -ENOMEM;
982
983 res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir,
984 &alignment_proc_fops, &se_usermode);
985 if (!res)
986 return -ENOMEM;
987
988 res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir,
989 &alignment_proc_fops, &se_kernmode_warn);
990 if (!res)
991 return -ENOMEM;
992
993 return 0;
994}
995
996fs_initcall(alignment_init);
997#endif