diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-01-12 02:12:25 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-01-12 02:12:25 -0500 |
commit | a99eae5417a09e0be66bf574a9a79a2a7388c967 (patch) | |
tree | 5024736c9afd76124e2f5f5424ecc153f6218c8e /arch/sh/kernel/traps_32.c | |
parent | 776258df925acd0563f471ee4b3f19bbffb3c04f (diff) |
sh: Split out the unaligned counters and user bits.
This splits out the unaligned access counters and userspace bits in to
their own generic interface, which will allow them to be wired up on sh64
too.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
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 | ||