]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/sparc64/kernel/unaligned.c
[SPARC64]: Fix fault handling in unaligned trap handler.
[linux-2.6-omap-h63xx.git] / arch / sparc64 / kernel / unaligned.c
index 9d6be20f4125938d1931e909535f09cb0867e36a..70faf630603bc49a34a2cba0bfe4733092aedd36 100644 (file)
@@ -180,14 +180,14 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs)
        die_if_kernel(str, regs);
 }
 
-extern void do_int_load(unsigned long *dest_reg, int size,
-                       unsigned long *saddr, int is_signed, int asi);
+extern int do_int_load(unsigned long *dest_reg, int size,
+                      unsigned long *saddr, int is_signed, int asi);
        
-extern void __do_int_store(unsigned long *dst_addr, int size,
-                          unsigned long src_val, int asi);
+extern int __do_int_store(unsigned long *dst_addr, int size,
+                         unsigned long src_val, int asi);
 
-static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr,
-                               struct pt_regs *regs, int asi, int orig_asi)
+static inline int do_int_store(int reg_num, int size, unsigned long *dst_addr,
+                              struct pt_regs *regs, int asi, int orig_asi)
 {
        unsigned long zero = 0;
        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,
                        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)
@@ -242,7 +242,7 @@ static inline int ok_for_kernel(unsigned int 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;
        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
                kernel_mna_trap_fault();
        } else {
                unsigned long addr, *reg_addr;
-               int orig_asi, asi;
+               int orig_asi, asi, err;
 
                addr = compute_effective_address(regs, insn,
                                                 ((insn >> 25) & 0x1f));
@@ -319,9 +319,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
                switch (dir) {
                case load:
                        reg_addr = fetch_reg_addr(((insn>>25)&0x1f), regs);
-                       do_int_load(reg_addr, size, (unsigned long *) addr,
-                                   decode_signedness(insn), asi);
-                       if (unlikely(asi != orig_asi)) {
+                       err = do_int_load(reg_addr, size,
+                                         (unsigned long *) addr,
+                                         decode_signedness(insn), asi);
+                       if (likely(!err) && unlikely(asi != orig_asi)) {
                                unsigned long val_in = *reg_addr;
                                switch (size) {
                                case 2:
@@ -343,16 +344,19 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
                        break;
 
                case store:
-                       do_int_store(((insn>>25)&0x1f), size,
-                                    (unsigned long *) addr, regs,
-                                    asi, orig_asi);
+                       err = do_int_store(((insn>>25)&0x1f), size,
+                                          (unsigned long *) addr, regs,
+                                          asi, orig_asi);
                        break;
 
                default:
                        panic("Impossible kernel unaligned trap.");
                        /* Not reached... */
                }
-               advance(regs);
+               if (unlikely(err))
+                       kernel_mna_trap_fault();
+               else
+                       advance(regs);
        }
 }