diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /arch/sh/kernel/traps_32.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r-- | arch/sh/kernel/traps_32.c | 195 |
1 files changed, 18 insertions, 177 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 7a2ee3a6b8e7..c3d86fa71ddf 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -24,10 +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/sysfs.h> | 27 | #include <linux/sysfs.h> |
28 | #include <linux/uaccess.h> | ||
29 | #include <asm/system.h> | 29 | #include <asm/system.h> |
30 | #include <asm/uaccess.h> | 30 | #include <asm/alignment.h> |
31 | #include <asm/fpu.h> | 31 | #include <asm/fpu.h> |
32 | #include <asm/kprobes.h> | 32 | #include <asm/kprobes.h> |
33 | 33 | ||
@@ -46,85 +46,6 @@ | |||
46 | #define TRAP_ILLEGAL_SLOT_INST 13 | 46 | #define TRAP_ILLEGAL_SLOT_INST 13 |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | static unsigned long se_user; | ||
50 | static unsigned long se_sys; | ||
51 | static unsigned long se_half; | ||
52 | static unsigned long se_word; | ||
53 | static unsigned long se_dword; | ||
54 | static unsigned long se_multi; | ||
55 | /* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not | ||
56 | valid! */ | ||
57 | static int se_usermode = 3; | ||
58 | /* 0: no warning 1: print a warning message, disabled by default */ | ||
59 | static int se_kernmode_warn; | ||
60 | |||
61 | #ifdef CONFIG_PROC_FS | ||
62 | static const char *se_usermode_action[] = { | ||
63 | "ignored", | ||
64 | "warn", | ||
65 | "fixup", | ||
66 | "fixup+warn", | ||
67 | "signal", | ||
68 | "signal+warn" | ||
69 | }; | ||
70 | |||
71 | static int | ||
72 | proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, | ||
73 | void *data) | ||
74 | { | ||
75 | char *p = page; | ||
76 | int len; | ||
77 | |||
78 | p += sprintf(p, "User:\t\t%lu\n", se_user); | ||
79 | p += sprintf(p, "System:\t\t%lu\n", se_sys); | ||
80 | p += sprintf(p, "Half:\t\t%lu\n", se_half); | ||
81 | p += sprintf(p, "Word:\t\t%lu\n", se_word); | ||
82 | p += sprintf(p, "DWord:\t\t%lu\n", se_dword); | ||
83 | p += sprintf(p, "Multi:\t\t%lu\n", se_multi); | ||
84 | p += sprintf(p, "User faults:\t%i (%s)\n", se_usermode, | ||
85 | se_usermode_action[se_usermode]); | ||
86 | p += sprintf(p, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, | ||
87 | se_kernmode_warn ? "+warn" : ""); | ||
88 | |||
89 | len = (p - page) - off; | ||
90 | if (len < 0) | ||
91 | len = 0; | ||
92 | |||
93 | *eof = (len <= count) ? 1 : 0; | ||
94 | *start = page + off; | ||
95 | |||
96 | return len; | ||
97 | } | ||
98 | |||
99 | static int proc_alignment_write(struct file *file, const char __user *buffer, | ||
100 | unsigned long count, void *data) | ||
101 | { | ||
102 | char mode; | ||
103 | |||
104 | if (count > 0) { | ||
105 | if (get_user(mode, buffer)) | ||
106 | return -EFAULT; | ||
107 | if (mode >= '0' && mode <= '5') | ||
108 | se_usermode = mode - '0'; | ||
109 | } | ||
110 | return count; | ||
111 | } | ||
112 | |||
113 | static int proc_alignment_kern_write(struct file *file, const char __user *buffer, | ||
114 | unsigned long count, void *data) | ||
115 | { | ||
116 | char mode; | ||
117 | |||
118 | if (count > 0) { | ||
119 | if (get_user(mode, buffer)) | ||
120 | return -EFAULT; | ||
121 | if (mode >= '0' && mode <= '1') | ||
122 | se_kernmode_warn = mode - '0'; | ||
123 | } | ||
124 | return count; | ||
125 | } | ||
126 | #endif | ||
127 | |||
128 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) | 49 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) |
129 | { | 50 | { |
130 | unsigned long p; | 51 | unsigned long p; |
@@ -276,10 +197,10 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs, | |||
276 | count = 1<<(instruction&3); | 197 | count = 1<<(instruction&3); |
277 | 198 | ||
278 | switch (count) { | 199 | switch (count) { |
279 | case 1: se_half += 1; break; | 200 | case 1: inc_unaligned_byte_access(); break; |
280 | case 2: se_word += 1; break; | 201 | case 2: inc_unaligned_word_access(); break; |
281 | case 4: se_dword += 1; break; | 202 | case 4: inc_unaligned_dword_access(); break; |
282 | case 8: se_multi += 1; break; /* ??? */ | 203 | case 8: inc_unaligned_multi_access(); break; |
283 | } | 204 | } |
284 | 205 | ||
285 | ret = -EFAULT; | 206 | ret = -EFAULT; |
@@ -463,12 +384,8 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, | |||
463 | rm = regs->regs[index]; | 384 | rm = regs->regs[index]; |
464 | 385 | ||
465 | /* shout about fixups */ | 386 | /* shout about fixups */ |
466 | if (!expected && printk_ratelimit()) | 387 | if (!expected) |
467 | printk(KERN_NOTICE "Fixing up unaligned %s access " | 388 | unaligned_fixups_notify(current, instruction, regs); |
468 | "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | ||
469 | user_mode(regs) ? "userspace" : "kernel", | ||
470 | current->comm, task_pid_nr(current), | ||
471 | (void *)regs->pc, instruction); | ||
472 | 389 | ||
473 | ret = -EFAULT; | 390 | ret = -EFAULT; |
474 | switch (instruction&0xF000) { | 391 | switch (instruction&0xF000) { |
@@ -621,10 +538,10 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
621 | 538 | ||
622 | if (user_mode(regs)) { | 539 | if (user_mode(regs)) { |
623 | int si_code = BUS_ADRERR; | 540 | int si_code = BUS_ADRERR; |
541 | unsigned int user_action; | ||
624 | 542 | ||
625 | local_irq_enable(); | 543 | local_irq_enable(); |
626 | 544 | inc_unaligned_user_access(); | |
627 | se_user += 1; | ||
628 | 545 | ||
629 | set_fs(USER_DS); | 546 | set_fs(USER_DS); |
630 | if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1), | 547 | if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1), |
@@ -635,16 +552,12 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
635 | set_fs(oldfs); | 552 | set_fs(oldfs); |
636 | 553 | ||
637 | /* shout about userspace fixups */ | 554 | /* shout about userspace fixups */ |
638 | if (se_usermode & 1) | 555 | unaligned_fixups_notify(current, instruction, regs); |
639 | printk(KERN_NOTICE "Unaligned userspace access " | ||
640 | "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | ||
641 | current->comm, current->pid, (void *)regs->pc, | ||
642 | instruction); | ||
643 | 556 | ||
644 | if (se_usermode & 2) | 557 | user_action = unaligned_user_action(); |
558 | if (user_action & UM_FIXUP) | ||
645 | goto fixup; | 559 | goto fixup; |
646 | 560 | if (user_action & UM_SIGNAL) | |
647 | if (se_usermode & 4) | ||
648 | goto uspace_segv; | 561 | goto uspace_segv; |
649 | else { | 562 | else { |
650 | /* ignore */ | 563 | /* ignore */ |
@@ -664,7 +577,7 @@ fixup: | |||
664 | &user_mem_access, 0); | 577 | &user_mem_access, 0); |
665 | set_fs(oldfs); | 578 | set_fs(oldfs); |
666 | 579 | ||
667 | if (tmp==0) | 580 | if (tmp == 0) |
668 | return; /* sorted */ | 581 | return; /* sorted */ |
669 | uspace_segv: | 582 | uspace_segv: |
670 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " | 583 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " |
@@ -677,7 +590,7 @@ uspace_segv: | |||
677 | info.si_addr = (void __user *)address; | 590 | info.si_addr = (void __user *)address; |
678 | force_sig_info(SIGBUS, &info, current); | 591 | force_sig_info(SIGBUS, &info, current); |
679 | } else { | 592 | } else { |
680 | se_sys += 1; | 593 | inc_unaligned_kernel_access(); |
681 | 594 | ||
682 | if (regs->pc & 1) | 595 | if (regs->pc & 1) |
683 | die("unaligned program counter", regs, error_code); | 596 | die("unaligned program counter", regs, error_code); |
@@ -692,11 +605,7 @@ uspace_segv: | |||
692 | die("insn faulting in do_address_error", regs, 0); | 605 | die("insn faulting in do_address_error", regs, 0); |
693 | } | 606 | } |
694 | 607 | ||
695 | if (se_kernmode_warn) | 608 | unaligned_fixups_notify(current, instruction, regs); |
696 | printk(KERN_NOTICE "Unaligned kernel access " | ||
697 | "on behalf of \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | ||
698 | current->comm, current->pid, (void *)regs->pc, | ||
699 | instruction); | ||
700 | 609 | ||
701 | handle_unaligned_access(instruction, regs, | 610 | handle_unaligned_access(instruction, regs, |
702 | &user_mem_access, 0); | 611 | &user_mem_access, 0); |
@@ -881,35 +790,10 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | |||
881 | die_if_kernel("exception", regs, ex); | 790 | die_if_kernel("exception", regs, ex); |
882 | } | 791 | } |
883 | 792 | ||
884 | #if defined(CONFIG_SH_STANDARD_BIOS) | ||
885 | void *gdb_vbr_vector; | ||
886 | |||
887 | static inline void __init gdb_vbr_init(void) | ||
888 | { | ||
889 | register unsigned long vbr; | ||
890 | |||
891 | /* | ||
892 | * Read the old value of the VBR register to initialise | ||
893 | * the vector through which debug and BIOS traps are | ||
894 | * delegated by the Linux trap handler. | ||
895 | */ | ||
896 | asm volatile("stc vbr, %0" : "=r" (vbr)); | ||
897 | |||
898 | gdb_vbr_vector = (void *)(vbr + 0x100); | ||
899 | printk("Setting GDB trap vector to 0x%08lx\n", | ||
900 | (unsigned long)gdb_vbr_vector); | ||
901 | } | ||
902 | #endif | ||
903 | |||
904 | void __cpuinit per_cpu_trap_init(void) | 793 | void __cpuinit per_cpu_trap_init(void) |
905 | { | 794 | { |
906 | extern void *vbr_base; | 795 | extern void *vbr_base; |
907 | 796 | ||
908 | #ifdef CONFIG_SH_STANDARD_BIOS | ||
909 | if (raw_smp_processor_id() == 0) | ||
910 | gdb_vbr_init(); | ||
911 | #endif | ||
912 | |||
913 | /* NOTE: The VBR value should be at P1 | 797 | /* NOTE: The VBR value should be at P1 |
914 | (or P2, virtural "fixed" address space). | 798 | (or P2, virtural "fixed" address space). |
915 | It's definitely should not in physical address. */ | 799 | It's definitely should not in physical address. */ |
@@ -945,14 +829,9 @@ void __init trap_init(void) | |||
945 | set_exception_table_evt(0x800, do_reserved_inst); | 829 | set_exception_table_evt(0x800, do_reserved_inst); |
946 | set_exception_table_evt(0x820, do_illegal_slot_inst); | 830 | set_exception_table_evt(0x820, do_illegal_slot_inst); |
947 | #elif defined(CONFIG_SH_FPU) | 831 | #elif defined(CONFIG_SH_FPU) |
948 | #ifdef CONFIG_CPU_SUBTYPE_SHX3 | ||
949 | set_exception_table_evt(0xd80, fpu_state_restore_trap_handler); | ||
950 | set_exception_table_evt(0xda0, fpu_state_restore_trap_handler); | ||
951 | #else | ||
952 | set_exception_table_evt(0x800, fpu_state_restore_trap_handler); | 832 | set_exception_table_evt(0x800, fpu_state_restore_trap_handler); |
953 | set_exception_table_evt(0x820, fpu_state_restore_trap_handler); | 833 | set_exception_table_evt(0x820, fpu_state_restore_trap_handler); |
954 | #endif | 834 | #endif |
955 | #endif | ||
956 | 835 | ||
957 | #ifdef CONFIG_CPU_SH2 | 836 | #ifdef CONFIG_CPU_SH2 |
958 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler); | 837 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler); |
@@ -966,11 +845,8 @@ void __init trap_init(void) | |||
966 | #endif | 845 | #endif |
967 | 846 | ||
968 | #ifdef TRAP_UBC | 847 | #ifdef TRAP_UBC |
969 | set_exception_table_vec(TRAP_UBC, break_point_trap); | 848 | set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler); |
970 | #endif | 849 | #endif |
971 | |||
972 | /* Setup VBR for boot cpu */ | ||
973 | per_cpu_trap_init(); | ||
974 | } | 850 | } |
975 | 851 | ||
976 | void show_stack(struct task_struct *tsk, unsigned long *sp) | 852 | void show_stack(struct task_struct *tsk, unsigned long *sp) |
@@ -995,38 +871,3 @@ void dump_stack(void) | |||
995 | show_stack(NULL, NULL); | 871 | show_stack(NULL, NULL); |
996 | } | 872 | } |
997 | EXPORT_SYMBOL(dump_stack); | 873 | EXPORT_SYMBOL(dump_stack); |
998 | |||
999 | #ifdef CONFIG_PROC_FS | ||
1000 | /* | ||
1001 | * This needs to be done after sysctl_init, otherwise sys/ will be | ||
1002 | * overwritten. Actually, this shouldn't be in sys/ at all since | ||
1003 | * it isn't a sysctl, and it doesn't contain sysctl information. | ||
1004 | * We now locate it in /proc/cpu/alignment instead. | ||
1005 | */ | ||
1006 | static int __init alignment_init(void) | ||
1007 | { | ||
1008 | struct proc_dir_entry *dir, *res; | ||
1009 | |||
1010 | dir = proc_mkdir("cpu", NULL); | ||
1011 | if (!dir) | ||
1012 | return -ENOMEM; | ||
1013 | |||
1014 | res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, dir); | ||
1015 | if (!res) | ||
1016 | return -ENOMEM; | ||
1017 | |||
1018 | res->read_proc = proc_alignment_read; | ||
1019 | res->write_proc = proc_alignment_write; | ||
1020 | |||
1021 | res = create_proc_entry("kernel_alignment", S_IWUSR | S_IRUGO, dir); | ||
1022 | if (!res) | ||
1023 | return -ENOMEM; | ||
1024 | |||
1025 | res->read_proc = proc_alignment_read; | ||
1026 | res->write_proc = proc_alignment_kern_write; | ||
1027 | |||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | fs_initcall(alignment_init); | ||
1032 | #endif | ||