diff options
author | SUGIOKA Toshinobu <sugioka@itonet.co.jp> | 2009-01-20 19:42:10 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-01-21 04:35:55 -0500 |
commit | 2afb447f33c29cb000a494396559f8005d3e33c1 (patch) | |
tree | 71365a7c84c6493f602cae0e6f249f26c26ae4ea /arch/sh/kernel/traps_32.c | |
parent | eb6434d9e79a72d35d68811efd68fe8bab8f5baf (diff) |
sh: fix unaligned and nonexistent address handling
unaligned and nonexistent address causes wrong exception
handling in traps_32.c(handle_unaligned_access).
'handle_unalinged_ins' should return -EFAULT if address error
is fixed up with kernel exception table, otherwise
'handle_unaligned_access' increases already fixed program counter
and then crash.
for example
ioctl(fd, TCGETA, (struct termio *)-1)
never return and stay in TASK_UNINTERRUPTIBLE state forever
in my kernel.
Signed-off-by: SUGIOKA Toshinobu <sugioka@itonet.co.jp>
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 | 9 |
1 files changed, 4 insertions, 5 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index c0aa3d83ec0e..60dcf87ed019 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -125,20 +125,18 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs, | |||
125 | * - userspace errors just cause EFAULT to be returned, resulting in SEGV | 125 | * - userspace errors just cause EFAULT to be returned, resulting in SEGV |
126 | * - kernel/userspace interfaces cause a jump to an appropriate handler | 126 | * - kernel/userspace interfaces cause a jump to an appropriate handler |
127 | * - other kernel errors are bad | 127 | * - other kernel errors are bad |
128 | * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault | ||
129 | */ | 128 | */ |
130 | static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) | 129 | static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) |
131 | { | 130 | { |
132 | if (!user_mode(regs)) { | 131 | if (!user_mode(regs)) { |
133 | const struct exception_table_entry *fixup; | 132 | const struct exception_table_entry *fixup; |
134 | fixup = search_exception_tables(regs->pc); | 133 | fixup = search_exception_tables(regs->pc); |
135 | if (fixup) { | 134 | if (fixup) { |
136 | regs->pc = fixup->fixup; | 135 | regs->pc = fixup->fixup; |
137 | return 0; | 136 | return; |
138 | } | 137 | } |
139 | die(str, regs, err); | 138 | die(str, regs, err); |
140 | } | 139 | } |
141 | return -EFAULT; | ||
142 | } | 140 | } |
143 | 141 | ||
144 | static inline void sign_extend(unsigned int count, unsigned char *dst) | 142 | static inline void sign_extend(unsigned int count, unsigned char *dst) |
@@ -314,7 +312,8 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, | |||
314 | /* Argh. Address not only misaligned but also non-existent. | 312 | /* Argh. Address not only misaligned but also non-existent. |
315 | * Raise an EFAULT and see if it's trapped | 313 | * Raise an EFAULT and see if it's trapped |
316 | */ | 314 | */ |
317 | return die_if_no_fixup("Fault in unaligned fixup", regs, 0); | 315 | die_if_no_fixup("Fault in unaligned fixup", regs, 0); |
316 | return -EFAULT; | ||
318 | } | 317 | } |
319 | 318 | ||
320 | /* | 319 | /* |