diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-02-22 22:56:30 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-02-22 22:56:30 -0500 |
commit | 94ea5e449ae834af058ef005d16a8ad44fcf13d6 (patch) | |
tree | 4152e5cc7cd5535452b2cd074b6ba041abc7c301 /arch/sh | |
parent | 7c1b2c6890a1a033dde4f6991c0a1fcd69cf58ce (diff) |
sh: wire up SET/GET_UNALIGN_CTL.
This hooks up the SET/GET_UNALIGN_CTL knobs cribbing the bulk of it from
the PPC and ia64 implementations. The thread flags happen to be the
logical inverse of what the global fault mode is set to, so this works
out pretty cleanly. By default the global fault mode is used, with tasks
now being able to override their own settings via prctl().
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/include/asm/processor.h | 12 | ||||
-rw-r--r-- | arch/sh/include/asm/processor_32.h | 6 | ||||
-rw-r--r-- | arch/sh/include/asm/processor_64.h | 5 | ||||
-rw-r--r-- | arch/sh/mm/alignment.c | 30 |
4 files changed, 51 insertions, 2 deletions
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h index 87a8d1ef64e4..9605e062840f 100644 --- a/arch/sh/include/asm/processor.h +++ b/arch/sh/include/asm/processor.h | |||
@@ -107,6 +107,13 @@ extern unsigned int xstate_size; | |||
107 | extern void free_thread_xstate(struct task_struct *); | 107 | extern void free_thread_xstate(struct task_struct *); |
108 | extern struct kmem_cache *task_xstate_cachep; | 108 | extern struct kmem_cache *task_xstate_cachep; |
109 | 109 | ||
110 | /* arch/sh/mm/alignment.c */ | ||
111 | extern int get_unalign_ctl(struct task_struct *, unsigned long addr); | ||
112 | extern int set_unalign_ctl(struct task_struct *, unsigned int val); | ||
113 | |||
114 | #define GET_UNALIGN_CTL(tsk, addr) get_unalign_ctl((tsk), (addr)) | ||
115 | #define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val)) | ||
116 | |||
110 | /* arch/sh/mm/init.c */ | 117 | /* arch/sh/mm/init.c */ |
111 | extern unsigned int mem_init_done; | 118 | extern unsigned int mem_init_done; |
112 | 119 | ||
@@ -114,6 +121,11 @@ extern unsigned int mem_init_done; | |||
114 | const char *get_cpu_subtype(struct sh_cpuinfo *c); | 121 | const char *get_cpu_subtype(struct sh_cpuinfo *c); |
115 | extern const struct seq_operations cpuinfo_op; | 122 | extern const struct seq_operations cpuinfo_op; |
116 | 123 | ||
124 | /* thread_struct flags */ | ||
125 | #define SH_THREAD_UAC_NOPRINT (1 << 0) | ||
126 | #define SH_THREAD_UAC_SIGBUS (1 << 1) | ||
127 | #define SH_THREAD_UAC_MASK (SH_THREAD_UAC_NOPRINT | SH_THREAD_UAC_SIGBUS) | ||
128 | |||
117 | /* processor boot mode configuration */ | 129 | /* processor boot mode configuration */ |
118 | #define MODE_PIN0 (1 << 0) | 130 | #define MODE_PIN0 (1 << 0) |
119 | #define MODE_PIN1 (1 << 1) | 131 | #define MODE_PIN1 (1 << 1) |
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 488f0a906a41..572b4eb09493 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h | |||
@@ -101,8 +101,11 @@ struct thread_struct { | |||
101 | unsigned long sp; | 101 | unsigned long sp; |
102 | unsigned long pc; | 102 | unsigned long pc; |
103 | 103 | ||
104 | /* Various thread flags, see SH_THREAD_xxx */ | ||
105 | unsigned long flags; | ||
106 | |||
104 | /* Save middle states of ptrace breakpoints */ | 107 | /* Save middle states of ptrace breakpoints */ |
105 | struct perf_event *ptrace_bps[HBP_NUM]; | 108 | struct perf_event *ptrace_bps[HBP_NUM]; |
106 | 109 | ||
107 | #ifdef CONFIG_SH_DSP | 110 | #ifdef CONFIG_SH_DSP |
108 | /* Dsp status information */ | 111 | /* Dsp status information */ |
@@ -115,6 +118,7 @@ struct thread_struct { | |||
115 | 118 | ||
116 | #define INIT_THREAD { \ | 119 | #define INIT_THREAD { \ |
117 | .sp = sizeof(init_stack) + (long) &init_stack, \ | 120 | .sp = sizeof(init_stack) + (long) &init_stack, \ |
121 | .flags = 0, \ | ||
118 | } | 122 | } |
119 | 123 | ||
120 | /* Forward declaration, a strange C thing */ | 124 | /* Forward declaration, a strange C thing */ |
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index 7b1560f03d14..621bc4618c6b 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h | |||
@@ -108,6 +108,10 @@ union thread_xstate { | |||
108 | struct thread_struct { | 108 | struct thread_struct { |
109 | unsigned long sp; | 109 | unsigned long sp; |
110 | unsigned long pc; | 110 | unsigned long pc; |
111 | |||
112 | /* Various thread flags, see SH_THREAD_xxx */ | ||
113 | unsigned long flags; | ||
114 | |||
111 | /* This stores the address of the pt_regs built during a context | 115 | /* This stores the address of the pt_regs built during a context |
112 | switch, or of the register save area built for a kernel mode | 116 | switch, or of the register save area built for a kernel mode |
113 | exception. It is used for backtracing the stack of a sleeping task | 117 | exception. It is used for backtracing the stack of a sleeping task |
@@ -138,6 +142,7 @@ struct thread_struct { | |||
138 | .trap_no = 0, \ | 142 | .trap_no = 0, \ |
139 | .error_code = 0, \ | 143 | .error_code = 0, \ |
140 | .address = 0, \ | 144 | .address = 0, \ |
145 | .flags = 0, \ | ||
141 | } | 146 | } |
142 | 147 | ||
143 | /* | 148 | /* |
diff --git a/arch/sh/mm/alignment.c b/arch/sh/mm/alignment.c index 00fb9e3f057c..b2595b8548ee 100644 --- a/arch/sh/mm/alignment.c +++ b/arch/sh/mm/alignment.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/proc_fs.h> | 14 | #include <linux/proc_fs.h> |
15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
16 | #include <asm/alignment.h> | 16 | #include <asm/alignment.h> |
17 | #include <asm/processor.h> | ||
17 | 18 | ||
18 | static unsigned long se_user; | 19 | static unsigned long se_user; |
19 | static unsigned long se_sys; | 20 | static unsigned long se_sys; |
@@ -59,9 +60,36 @@ void inc_unaligned_kernel_access(void) | |||
59 | se_sys++; | 60 | se_sys++; |
60 | } | 61 | } |
61 | 62 | ||
63 | /* | ||
64 | * This defaults to the global policy which can be set from the command | ||
65 | * line, while processes can overload their preferences via prctl(). | ||
66 | */ | ||
62 | unsigned int unaligned_user_action(void) | 67 | unsigned int unaligned_user_action(void) |
63 | { | 68 | { |
64 | return se_usermode; | 69 | unsigned int action = se_usermode; |
70 | |||
71 | if (current->thread.flags & SH_THREAD_UAC_SIGBUS) { | ||
72 | action &= ~UM_FIXUP; | ||
73 | action |= UM_SIGNAL; | ||
74 | } | ||
75 | |||
76 | if (current->thread.flags & SH_THREAD_UAC_NOPRINT) | ||
77 | action &= ~UM_WARN; | ||
78 | |||
79 | return action; | ||
80 | } | ||
81 | |||
82 | int get_unalign_ctl(struct task_struct *tsk, unsigned long addr) | ||
83 | { | ||
84 | return put_user(tsk->thread.flags & SH_THREAD_UAC_MASK, | ||
85 | (unsigned int __user *)addr); | ||
86 | } | ||
87 | |||
88 | int set_unalign_ctl(struct task_struct *tsk, unsigned int val) | ||
89 | { | ||
90 | tsk->thread.flags = (tsk->thread.flags & ~SH_THREAD_UAC_MASK) | | ||
91 | (val & SH_THREAD_UAC_MASK); | ||
92 | return 0; | ||
65 | } | 93 | } |
66 | 94 | ||
67 | void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn, | 95 | void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn, |