aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/traps_32.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-01-12 02:12:25 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-01-12 02:12:25 -0500
commita99eae5417a09e0be66bf574a9a79a2a7388c967 (patch)
tree5024736c9afd76124e2f5f5424ecc153f6218c8e /arch/sh/kernel/traps_32.c
parent776258df925acd0563f471ee4b3f19bbffb3c04f (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.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 efcbdfe52f5..204def6ecb6 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