diff options
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r-- | arch/sh/kernel/traps_32.c | 151 |
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 | ||
51 | static unsigned long se_user; | ||
52 | static unsigned long se_sys; | ||
53 | static unsigned long se_half; | ||
54 | static unsigned long se_word; | ||
55 | static unsigned long se_dword; | ||
56 | static unsigned long se_multi; | ||
57 | /* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not | ||
58 | valid! */ | ||
59 | static int se_usermode = 3; | ||
60 | /* 0: no warning 1: print a warning message, disabled by default */ | ||
61 | static int se_kernmode_warn; | ||
62 | |||
63 | #ifdef CONFIG_PROC_FS | ||
64 | static const char *se_usermode_action[] = { | ||
65 | "ignored", | ||
66 | "warn", | ||
67 | "fixup", | ||
68 | "fixup+warn", | ||
69 | "signal", | ||
70 | "signal+warn" | ||
71 | }; | ||
72 | |||
73 | static 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 | |||
88 | static int alignment_proc_open(struct inode *inode, struct file *file) | ||
89 | { | ||
90 | return single_open(file, alignment_proc_show, NULL); | ||
91 | } | ||
92 | |||
93 | static 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 | |||
108 | static 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 | |||
118 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) | 50 | static 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 */ |
665 | uspace_segv: | 583 | uspace_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 | } |
966 | EXPORT_SYMBOL(dump_stack); | 880 | EXPORT_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 | */ | ||
975 | static 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 | |||
996 | fs_initcall(alignment_init); | ||
997 | #endif | ||