summaryrefslogtreecommitdiff
path: root/arch/powerpc/lib
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@ozlabs.org>2017-08-30 07:12:36 +0300
committerMichael Ellerman <mpe@ellerman.id.au>2017-09-01 09:39:54 +0300
commitb2543f7b20bb2a551ed340447d7303f0ce4644f1 (patch)
tree782ce4a44ad68bd1d372f0c77dd8542298b1deeb /arch/powerpc/lib
parent1f41fb790460acf432f826f4aeeff6f7da891ff7 (diff)
downloadlinux-b2543f7b20bb2a551ed340447d7303f0ce4644f1.tar.xz
powerpc: Emulate the dcbz instruction
This adds code to analyse_instr() and emulate_step() to understand the dcbz (data cache block zero) instruction. The emulate_dcbz() function is made public so it can be used by the alignment handler in future. (The apparently unnecessary cropping of the address to 32 bits is there because it will be needed in that situation.) Signed-off-by: Paul Mackerras <paulus@ozlabs.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/lib')
-rw-r--r--arch/powerpc/lib/sstep.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 44a8ce062747..2d7e498b622b 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -780,6 +780,30 @@ static nokprobe_inline int do_vsx_store(struct instruction_op *op,
}
#endif /* CONFIG_VSX */
+int emulate_dcbz(unsigned long ea, struct pt_regs *regs)
+{
+ int err;
+ unsigned long i, size;
+
+#ifdef __powerpc64__
+ size = ppc64_caches.l1d.block_size;
+ if (!(regs->msr & MSR_64BIT))
+ ea &= 0xffffffffUL;
+#else
+ size = L1_CACHE_BYTES;
+#endif
+ ea &= ~(size - 1);
+ if (!address_ok(regs, ea, size))
+ return -EFAULT;
+ for (i = 0; i < size; i += sizeof(long)) {
+ err = __put_user(0, (unsigned long __user *) (ea + i));
+ if (err)
+ return err;
+ }
+ return 0;
+}
+NOKPROBE_SYMBOL(emulate_dcbz);
+
#define __put_user_asmx(x, addr, err, op, cr) \
__asm__ __volatile__( \
"1: " op " %2,0,%3\n" \
@@ -1748,6 +1772,11 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
op->type = MKOP(CACHEOP, ICBI, 0);
op->ea = xform_ea(instr, regs);
return 0;
+
+ case 1014: /* dcbz */
+ op->type = MKOP(CACHEOP, DCBZ, 0);
+ op->ea = xform_ea(instr, regs);
+ return 0;
}
break;
}
@@ -2607,6 +2636,9 @@ int emulate_step(struct pt_regs *regs, unsigned int instr)
case ICBI:
__cacheop_user_asmx(ea, err, "icbi");
break;
+ case DCBZ:
+ err = emulate_dcbz(ea, regs);
+ break;
}
if (err)
return 0;