aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/unaligned.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-09-28 23:41:45 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-09-28 23:41:45 -0400
commit5fd29752f09cabff582f65c0ce35518db4c64937 (patch)
treeb46e5c2c596d26125a7c2aac619fe1b52431f978 /arch/sparc64/kernel/unaligned.c
parent8cf14af0a740fb7e9f94a203b5a989beb875d58f (diff)
[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: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/unaligned.c')
-rw-r--r--arch/sparc64/kernel/unaligned.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 9d6be20f4125..70faf630603b 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -180,14 +180,14 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs)
180 die_if_kernel(str, regs); 180 die_if_kernel(str, regs);
181} 181}
182 182
183extern void do_int_load(unsigned long *dest_reg, int size, 183extern int do_int_load(unsigned long *dest_reg, int size,
184 unsigned long *saddr, int is_signed, int asi); 184 unsigned long *saddr, int is_signed, int asi);
185 185
186extern void __do_int_store(unsigned long *dst_addr, int size, 186extern int __do_int_store(unsigned long *dst_addr, int size,
187 unsigned long src_val, int asi); 187 unsigned long src_val, int asi);
188 188
189static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, 189static inline int do_int_store(int reg_num, int size, unsigned long *dst_addr,
190 struct pt_regs *regs, int asi, int orig_asi) 190 struct pt_regs *regs, int asi, int orig_asi)
191{ 191{
192 unsigned long zero = 0; 192 unsigned long zero = 0;
193 unsigned long *src_val_p = &zero; 193 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 break; 219 break;
220 }; 220 };
221 } 221 }
222 __do_int_store(dst_addr, size, src_val, asi); 222 return __do_int_store(dst_addr, size, src_val, asi);
223} 223}
224 224
225static inline void advance(struct pt_regs *regs) 225static inline void advance(struct pt_regs *regs)
@@ -242,7 +242,7 @@ static inline int ok_for_kernel(unsigned int insn)
242 return !floating_point_load_or_store_p(insn); 242 return !floating_point_load_or_store_p(insn);
243} 243}
244 244
245void kernel_mna_trap_fault(void) 245static void kernel_mna_trap_fault(void)
246{ 246{
247 struct pt_regs *regs = current_thread_info()->kern_una_regs; 247 struct pt_regs *regs = current_thread_info()->kern_una_regs;
248 unsigned int insn = current_thread_info()->kern_una_insn; 248 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 kernel_mna_trap_fault(); 294 kernel_mna_trap_fault();
295 } else { 295 } else {
296 unsigned long addr, *reg_addr; 296 unsigned long addr, *reg_addr;
297 int orig_asi, asi; 297 int orig_asi, asi, err;
298 298
299 addr = compute_effective_address(regs, insn, 299 addr = compute_effective_address(regs, insn,
300 ((insn >> 25) & 0x1f)); 300 ((insn >> 25) & 0x1f));
@@ -319,9 +319,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
319 switch (dir) { 319 switch (dir) {
320 case load: 320 case load:
321 reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs); 321 reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs);
322 do_int_load(reg_addr, size, (unsigned long *) addr, 322 err = do_int_load(reg_addr, size,
323 decode_signedness(insn), asi); 323 (unsigned long *) addr,
324 if (unlikely(asi != orig_asi)) { 324 decode_signedness(insn), asi);
325 if (likely(!err) && unlikely(asi != orig_asi)) {
325 unsigned long val_in = *reg_addr; 326 unsigned long val_in = *reg_addr;
326 switch (size) { 327 switch (size) {
327 case 2: 328 case 2:
@@ -343,16 +344,19 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
343 break; 344 break;
344 345
345 case store: 346 case store:
346 do_int_store(((insn>>25)&0x1f), size, 347 err = do_int_store(((insn>>25)&0x1f), size,
347 (unsigned long *) addr, regs, 348 (unsigned long *) addr, regs,
348 asi, orig_asi); 349 asi, orig_asi);
349 break; 350 break;
350 351
351 default: 352 default:
352 panic("Impossible kernel unaligned trap."); 353 panic("Impossible kernel unaligned trap.");
353 /* Not reached... */ 354 /* Not reached... */
354 } 355 }
355 advance(regs); 356 if (unlikely(err))
357 kernel_mna_trap_fault();
358 else
359 advance(regs);
356 } 360 }
357} 361}
358 362