return 1;
 }
 
-static nokprobe_inline long address_ok(struct pt_regs *regs, unsigned long ea, int nb)
+static nokprobe_inline long address_ok(struct pt_regs *regs,
+                                      unsigned long ea, int nb)
 {
        if (!user_mode(regs))
                return 1;
-       return __access_ok(ea, nb, USER_DS);
+       if (__access_ok(ea, nb, USER_DS))
+               return 1;
+       if (__access_ok(ea, 1, USER_DS))
+               /* Access overlaps the end of the user region */
+               regs->dar = USER_DS.seg;
+       else
+               regs->dar = ea;
+       return 0;
 }
 
 /*
 #endif
 
 static nokprobe_inline int read_mem_aligned(unsigned long *dest,
-                                       unsigned long ea, int nb)
+                                           unsigned long ea, int nb,
+                                           struct pt_regs *regs)
 {
        int err = 0;
        unsigned long x = 0;
        }
        if (!err)
                *dest = x;
+       else
+               regs->dar = ea;
        return err;
 }
 
  * Copy from userspace to a buffer, using the largest possible
  * aligned accesses, up to sizeof(long).
  */
-static int nokprobe_inline copy_mem_in(u8 *dest, unsigned long ea, int nb)
+static int nokprobe_inline copy_mem_in(u8 *dest, unsigned long ea, int nb,
+                                      struct pt_regs *regs)
 {
        int err = 0;
        int c;
                        break;
 #endif
                }
-               if (err)
+               if (err) {
+                       regs->dar = ea;
                        return err;
+               }
                dest += c;
                ea += c;
        }
 
        u.ul = 0;
        i = IS_BE ? sizeof(unsigned long) - nb : 0;
-       err = copy_mem_in(&u.b[i], ea, nb);
+       err = copy_mem_in(&u.b[i], ea, nb, regs);
        if (!err)
                *dest = u.ul;
        return err;
        if (!address_ok(regs, ea, nb))
                return -EFAULT;
        if ((ea & (nb - 1)) == 0)
-               return read_mem_aligned(dest, ea, nb);
+               return read_mem_aligned(dest, ea, nb, regs);
        return read_mem_unaligned(dest, ea, nb, regs);
 }
 NOKPROBE_SYMBOL(read_mem);
 
 static nokprobe_inline int write_mem_aligned(unsigned long val,
-                                       unsigned long ea, int nb)
+                                            unsigned long ea, int nb,
+                                            struct pt_regs *regs)
 {
        int err = 0;
 
                break;
 #endif
        }
+       if (err)
+               regs->dar = ea;
        return err;
 }
 
  * Copy from a buffer to userspace, using the largest possible
  * aligned accesses, up to sizeof(long).
  */
-static int nokprobe_inline copy_mem_out(u8 *dest, unsigned long ea, int nb)
+static int nokprobe_inline copy_mem_out(u8 *dest, unsigned long ea, int nb,
+                                       struct pt_regs *regs)
 {
        int err = 0;
        int c;
                        break;
 #endif
                }
-               if (err)
+               if (err) {
+                       regs->dar = ea;
                        return err;
+               }
                dest += c;
                ea += c;
        }
 
        u.ul = val;
        i = IS_BE ? sizeof(unsigned long) - nb : 0;
-       return copy_mem_out(&u.b[i], ea, nb);
+       return copy_mem_out(&u.b[i], ea, nb, regs);
 }
 
 /*
        if (!address_ok(regs, ea, nb))
                return -EFAULT;
        if ((ea & (nb - 1)) == 0)
-               return write_mem_aligned(val, ea, nb);
+               return write_mem_aligned(val, ea, nb, regs);
        return write_mem_unaligned(val, ea, nb, regs);
 }
 NOKPROBE_SYMBOL(write_mem);
 
        if (!address_ok(regs, ea, nb))
                return -EFAULT;
-       err = copy_mem_in(u.b, ea, nb);
+       err = copy_mem_in(u.b, ea, nb, regs);
        if (err)
                return err;
        preempt_disable();
                        u.l[1] = current->thread.TS_FPR(rn);
        }
        preempt_enable();
-       return copy_mem_out(u.b, ea, nb);
+       return copy_mem_out(u.b, ea, nb, regs);
 }
 NOKPROBE_SYMBOL(do_fp_store);
 #endif
                return -EFAULT;
        /* align to multiple of size */
        ea &= ~(size - 1);
-       err = copy_mem_in(&u.b[ea & 0xf], ea, size);
+       err = copy_mem_in(&u.b[ea & 0xf], ea, size, regs);
        if (err)
                return err;
 
        else
                u.v = current->thread.vr_state.vr[rn];
        preempt_enable();
-       return copy_mem_out(&u.b[ea & 0xf], ea, size);
+       return copy_mem_out(&u.b[ea & 0xf], ea, size, regs);
 }
 #endif /* CONFIG_ALTIVEC */
 
        union vsx_reg buf;
        int size = GETSIZE(op->type);
 
-       if (!address_ok(regs, ea, size) || copy_mem_in(mem, ea, size))
+       if (!address_ok(regs, ea, size) || copy_mem_in(mem, ea, size, regs))
                return -EFAULT;
 
        emulate_vsx_load(op, &buf, mem);
        }
        preempt_enable();
        emulate_vsx_store(op, &buf, mem);
-       return  copy_mem_out(mem, ea, size);
+       return  copy_mem_out(mem, ea, size, regs);
 }
 #endif /* CONFIG_VSX */
 
                return -EFAULT;
        for (i = 0; i < size; i += sizeof(long)) {
                err = __put_user(0, (unsigned long __user *) (ea + i));
-               if (err)
+               if (err) {
+                       regs->dar = ea;
                        return err;
+               }
        }
        return 0;
 }
                        err = emulate_dcbz(ea, regs);
                        break;
                }
-               if (err)
+               if (err) {
+                       regs->dar = ea;
                        return 0;
+               }
                goto instr_done;
 
        case LARX:
                        break;
                case 16:
                        err = do_lqarx(ea, ®s->gpr[op.reg]);
-                       goto ldst_done;
+                       break;
 #endif
                default:
                        return 0;
                }
-               if (!err)
+               if (err) {
+                       regs->dar = ea;
+                       return 0;
+               }
+               if (size < 16)
                        regs->gpr[op.reg] = val;
                goto ldst_done;
 
                        regs->ccr = (regs->ccr & 0x0fffffff) |
                                (cr & 0xe0000000) |
                                ((regs->xer >> 3) & 0x10000000);
+               else
+                       regs->dar = ea;
                goto ldst_done;
 
        case LOAD: