Commit 5fd29752 authored by David S. Miller's avatar David S. Miller

[SPARC64]: Fix fault handling in unaligned trap handler.

We were not calling kernel_mna_trap_fault() correctly.
Instead of being fancy, just return 0 vs. -EFAULT from
the assembler stubs, and handle that return value as
appropriate.

Create an "__retl_efault" stub for assembler exception
table entries and use it where possible.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8cf14af0
...@@ -540,8 +540,11 @@ bootup_user_stack_end: ...@@ -540,8 +540,11 @@ bootup_user_stack_end:
prom_tba: .xword 0 prom_tba: .xword 0
tlb_type: .word 0 /* Must NOT end up in BSS */ tlb_type: .word 0 /* Must NOT end up in BSS */
.section ".fixup",#alloc,#execinstr .section ".fixup",#alloc,#execinstr
.globl __ret_efault
.globl __ret_efault, __retl_efault
__ret_efault: __ret_efault:
ret ret
restore %g0, -EFAULT, %o0 restore %g0, -EFAULT, %o0
__retl_efault:
retl
mov -EFAULT, %o0
...@@ -157,6 +157,9 @@ sys32_socketcall: /* %o0=call, %o1=args */ ...@@ -157,6 +157,9 @@ sys32_socketcall: /* %o0=call, %o1=args */
or %g2, %lo(__socketcall_table_begin), %g2 or %g2, %lo(__socketcall_table_begin), %g2
jmpl %g2 + %o0, %g0 jmpl %g2 + %o0, %g0
nop nop
do_einval:
retl
mov -EINVAL, %o0
.align 32 .align 32
__socketcall_table_begin: __socketcall_table_begin:
...@@ -316,29 +319,37 @@ do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) ...@@ -316,29 +319,37 @@ do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int)
nop nop
nop nop
do_einval:
retl
mov -EINVAL, %o0
do_efault:
retl
mov -EFAULT, %o0
.section __ex_table .section __ex_table
.align 4 .align 4
.word 1b, do_efault, 2b, do_efault, 3b, do_efault, 4b, do_efault .word 1b, __retl_efault, 2b, __retl_efault
.word 5b, do_efault, 6b, do_efault, 7b, do_efault, 8b, do_efault .word 3b, __retl_efault, 4b, __retl_efault
.word 9b, do_efault, 10b, do_efault, 11b, do_efault, 12b, do_efault .word 5b, __retl_efault, 6b, __retl_efault
.word 13b, do_efault, 14b, do_efault, 15b, do_efault, 16b, do_efault .word 7b, __retl_efault, 8b, __retl_efault
.word 17b, do_efault, 18b, do_efault, 19b, do_efault, 20b, do_efault .word 9b, __retl_efault, 10b, __retl_efault
.word 21b, do_efault, 22b, do_efault, 23b, do_efault, 24b, do_efault .word 11b, __retl_efault, 12b, __retl_efault
.word 25b, do_efault, 26b, do_efault, 27b, do_efault, 28b, do_efault .word 13b, __retl_efault, 14b, __retl_efault
.word 29b, do_efault, 30b, do_efault, 31b, do_efault, 32b, do_efault .word 15b, __retl_efault, 16b, __retl_efault
.word 33b, do_efault, 34b, do_efault, 35b, do_efault, 36b, do_efault .word 17b, __retl_efault, 18b, __retl_efault
.word 37b, do_efault, 38b, do_efault, 39b, do_efault, 40b, do_efault .word 19b, __retl_efault, 20b, __retl_efault
.word 41b, do_efault, 42b, do_efault, 43b, do_efault, 44b, do_efault .word 21b, __retl_efault, 22b, __retl_efault
.word 45b, do_efault, 46b, do_efault, 47b, do_efault, 48b, do_efault .word 23b, __retl_efault, 24b, __retl_efault
.word 49b, do_efault, 50b, do_efault, 51b, do_efault, 52b, do_efault .word 25b, __retl_efault, 26b, __retl_efault
.word 53b, do_efault, 54b, do_efault, 55b, do_efault, 56b, do_efault .word 27b, __retl_efault, 28b, __retl_efault
.word 57b, do_efault, 58b, do_efault, 59b, do_efault, 60b, do_efault .word 29b, __retl_efault, 30b, __retl_efault
.word 61b, do_efault, 62b, do_efault .word 31b, __retl_efault, 32b, __retl_efault
.word 33b, __retl_efault, 34b, __retl_efault
.word 35b, __retl_efault, 36b, __retl_efault
.word 37b, __retl_efault, 38b, __retl_efault
.word 39b, __retl_efault, 40b, __retl_efault
.word 41b, __retl_efault, 42b, __retl_efault
.word 43b, __retl_efault, 44b, __retl_efault
.word 45b, __retl_efault, 46b, __retl_efault
.word 47b, __retl_efault, 48b, __retl_efault
.word 49b, __retl_efault, 50b, __retl_efault
.word 51b, __retl_efault, 52b, __retl_efault
.word 53b, __retl_efault, 54b, __retl_efault
.word 55b, __retl_efault, 56b, __retl_efault
.word 57b, __retl_efault, 58b, __retl_efault
.word 59b, __retl_efault, 60b, __retl_efault
.word 61b, __retl_efault, 62b, __retl_efault
.previous .previous
...@@ -6,13 +6,6 @@ ...@@ -6,13 +6,6 @@
.text .text
kernel_unaligned_trap_fault:
call kernel_mna_trap_fault
nop
retl
nop
.size kern_unaligned_trap_fault, .-kern_unaligned_trap_fault
.globl __do_int_store .globl __do_int_store
__do_int_store: __do_int_store:
rd %asi, %o4 rd %asi, %o4
...@@ -51,24 +44,24 @@ __do_int_store: ...@@ -51,24 +44,24 @@ __do_int_store:
0: 0:
wr %o4, 0x0, %asi wr %o4, 0x0, %asi
retl retl
nop mov 0, %o0
.size __do_int_store, .-__do_int_store .size __do_int_store, .-__do_int_store
.section __ex_table .section __ex_table
.word 4b, kernel_unaligned_trap_fault .word 4b, __retl_efault
.word 5b, kernel_unaligned_trap_fault .word 5b, __retl_efault
.word 6b, kernel_unaligned_trap_fault .word 6b, __retl_efault
.word 7b, kernel_unaligned_trap_fault .word 7b, __retl_efault
.word 8b, kernel_unaligned_trap_fault .word 8b, __retl_efault
.word 9b, kernel_unaligned_trap_fault .word 9b, __retl_efault
.word 10b, kernel_unaligned_trap_fault .word 10b, __retl_efault
.word 11b, kernel_unaligned_trap_fault .word 11b, __retl_efault
.word 12b, kernel_unaligned_trap_fault .word 12b, __retl_efault
.word 13b, kernel_unaligned_trap_fault .word 13b, __retl_efault
.word 14b, kernel_unaligned_trap_fault .word 14b, __retl_efault
.word 15b, kernel_unaligned_trap_fault .word 15b, __retl_efault
.word 16b, kernel_unaligned_trap_fault .word 16b, __retl_efault
.word 17b, kernel_unaligned_trap_fault .word 17b, __retl_efault
.previous .previous
.globl do_int_load .globl do_int_load
...@@ -133,21 +126,21 @@ do_int_load: ...@@ -133,21 +126,21 @@ do_int_load:
0: 0:
wr %o5, 0x0, %asi wr %o5, 0x0, %asi
retl retl
nop mov 0, %o0
.size __do_int_load, .-__do_int_load .size __do_int_load, .-__do_int_load
.section __ex_table .section __ex_table
.word 4b, kernel_unaligned_trap_fault .word 4b, __retl_efault
.word 5b, kernel_unaligned_trap_fault .word 5b, __retl_efault
.word 6b, kernel_unaligned_trap_fault .word 6b, __retl_efault
.word 7b, kernel_unaligned_trap_fault .word 7b, __retl_efault
.word 8b, kernel_unaligned_trap_fault .word 8b, __retl_efault
.word 9b, kernel_unaligned_trap_fault .word 9b, __retl_efault
.word 10b, kernel_unaligned_trap_fault .word 10b, __retl_efault
.word 11b, kernel_unaligned_trap_fault .word 11b, __retl_efault
.word 12b, kernel_unaligned_trap_fault .word 12b, __retl_efault
.word 13b, kernel_unaligned_trap_fault .word 13b, __retl_efault
.word 14b, kernel_unaligned_trap_fault .word 14b, __retl_efault
.word 15b, kernel_unaligned_trap_fault .word 15b, __retl_efault
.word 16b, kernel_unaligned_trap_fault .word 16b, __retl_efault
.previous .previous
...@@ -180,14 +180,14 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs) ...@@ -180,14 +180,14 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs)
die_if_kernel(str, regs); die_if_kernel(str, regs);
} }
extern void do_int_load(unsigned long *dest_reg, int size, extern int do_int_load(unsigned long *dest_reg, int size,
unsigned long *saddr, int is_signed, int asi); unsigned long *saddr, int is_signed, int asi);
extern void __do_int_store(unsigned long *dst_addr, int size, extern int __do_int_store(unsigned long *dst_addr, int size,
unsigned long src_val, int asi); unsigned long src_val, int asi);
static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, static inline int do_int_store(int reg_num, int size, unsigned long *dst_addr,
struct pt_regs *regs, int asi, int orig_asi) struct pt_regs *regs, int asi, int orig_asi)
{ {
unsigned long zero = 0; unsigned long zero = 0;
unsigned long *src_val_p = &zero; unsigned long *src_val_p = &zero;
...@@ -219,7 +219,7 @@ static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, ...@@ -219,7 +219,7 @@ static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr,
break; break;
}; };
} }
__do_int_store(dst_addr, size, src_val, asi); return __do_int_store(dst_addr, size, src_val, asi);
} }
static inline void advance(struct pt_regs *regs) static inline void advance(struct pt_regs *regs)
...@@ -242,7 +242,7 @@ static inline int ok_for_kernel(unsigned int insn) ...@@ -242,7 +242,7 @@ static inline int ok_for_kernel(unsigned int insn)
return !floating_point_load_or_store_p(insn); return !floating_point_load_or_store_p(insn);
} }
void kernel_mna_trap_fault(void) static void kernel_mna_trap_fault(void)
{ {
struct pt_regs *regs = current_thread_info()->kern_una_regs; struct pt_regs *regs = current_thread_info()->kern_una_regs;
unsigned int insn = current_thread_info()->kern_una_insn; unsigned int insn = current_thread_info()->kern_una_insn;
...@@ -294,7 +294,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u ...@@ -294,7 +294,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
kernel_mna_trap_fault(); kernel_mna_trap_fault();
} else { } else {
unsigned long addr, *reg_addr; unsigned long addr, *reg_addr;
int orig_asi, asi; int orig_asi, asi, err;
addr = compute_effective_address(regs, insn, addr = compute_effective_address(regs, insn,
((insn >> 25) & 0x1f)); ((insn >> 25) & 0x1f));
...@@ -319,9 +319,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u ...@@ -319,9 +319,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
switch (dir) { switch (dir) {
case load: case load:
reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs); reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs);
do_int_load(reg_addr, size, (unsigned long *) addr, err = do_int_load(reg_addr, size,
decode_signedness(insn), asi); (unsigned long *) addr,
if (unlikely(asi != orig_asi)) { decode_signedness(insn), asi);
if (likely(!err) && unlikely(asi != orig_asi)) {
unsigned long val_in = *reg_addr; unsigned long val_in = *reg_addr;
switch (size) { switch (size) {
case 2: case 2:
...@@ -343,16 +344,19 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u ...@@ -343,16 +344,19 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
break; break;
case store: case store:
do_int_store(((insn>>25)&0x1f), size, err = do_int_store(((insn>>25)&0x1f), size,
(unsigned long *) addr, regs, (unsigned long *) addr, regs,
asi, orig_asi); asi, orig_asi);
break; break;
default: default:
panic("Impossible kernel unaligned trap."); panic("Impossible kernel unaligned trap.");
/* Not reached... */ /* Not reached... */
} }
advance(regs); if (unlikely(err))
kernel_mna_trap_fault();
else
advance(regs);
} }
} }
......
...@@ -125,15 +125,11 @@ __strncpy_from_user: ...@@ -125,15 +125,11 @@ __strncpy_from_user:
add %o2, %o3, %o0 add %o2, %o3, %o0
.size __strncpy_from_user, .-__strncpy_from_user .size __strncpy_from_user, .-__strncpy_from_user
.section .fixup,#alloc,#execinstr
.align 4
4: retl
mov -EFAULT, %o0
.section __ex_table,#alloc .section __ex_table,#alloc
.align 4 .align 4
.word 60b, 4b .word 60b, __retl_efault
.word 61b, 4b .word 61b, __retl_efault
.word 62b, 4b .word 62b, __retl_efault
.word 63b, 4b .word 63b, __retl_efault
.word 64b, 4b .word 64b, __retl_efault
.previous
...@@ -77,6 +77,7 @@ struct exception_table_entry { ...@@ -77,6 +77,7 @@ struct exception_table_entry {
}; };
extern void __ret_efault(void); extern void __ret_efault(void);
extern void __retl_efault(void);
/* Uh, these should become the main single-value transfer routines.. /* Uh, these should become the main single-value transfer routines..
* They automatically use the right size if we just have the right * They automatically use the right size if we just have the right
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment