All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] Improve PPC instruction emulation
@ 2014-07-19 10:14 ` Paul Mackerras
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This series aims to increase the range of instructions that KVM on PPC
can emulate and reduce code duplication by using the existing
instruction emulation code from arch/powerpc/lib/sstep.c for KVM.

The ultimate goal is to make PR KVM run faster on the kind of
instruction sequences that we get in Linux's first-level interrupt
handlers, where we have privileged instructions such as move to/from
SPR, mtmsrd, rfid, etc., intermingled with ordinary unprivileged
loads, stores, arithmetic instructions, etc.  If KVM could emulate
those ordinary instructions as well as the privileged ones, we could
emulate these code sequences without incurring the cost to exit and
re-enter the guest for every single privileged instruction.  That
would be a speedup provided the guest entry/exit cost was greater than
the cost of emulating a few ordinary instructions.

This series doesn't get to that ultimate goal but does lay the
groundwork.  It splits the emulate_step() function into two parts,
analyse_instr() and emulate_step(), and uses analyse_instr() in
kvmppc_emulate_instruction().  This means that KVM needs to store its
vcpu integer register state in a struct pt_regs like the rest of the
kernel does.  We also need to make kvmppc_handle_load() and
kvmppc_handle_store() handle loads and stores to ordinary guest memory
as well as emulated MMIO.

I have tested this series by running a Fedora 20 PR guest inside a HV
guest on POWER7.  The series is against Alex Graf's kvm-ppc-queue
branch, plus the 3 bug-fix patches I just posted, and a bug-fix
entitled "powerpc: Fix bugs in emulate_step()" that I posted to the
linuxppc-dev list.

Paul.
--
 arch/powerpc/include/asm/kvm_book3s.h    |  24 +-
 arch/powerpc/include/asm/kvm_booke.h     |  24 +-
 arch/powerpc/include/asm/kvm_host.h      |  22 +-
 arch/powerpc/include/asm/kvm_ppc.h       |  21 +-
 arch/powerpc/include/asm/sstep.h         |  62 ++
 arch/powerpc/kernel/asm-offsets.c        |  32 +-
 arch/powerpc/kvm/Makefile                |   1 +
 arch/powerpc/kvm/book3s_32_mmu.c         |   2 +-
 arch/powerpc/kvm/book3s_64_mmu_hv.c      |  10 +-
 arch/powerpc/kvm/book3s_64_vio_hv.c      |   2 +-
 arch/powerpc/kvm/book3s_emulate.c        |  22 +-
 arch/powerpc/kvm/book3s_hv.c             |  42 +-
 arch/powerpc/kvm/book3s_hv_rm_mmu.c      |  10 +-
 arch/powerpc/kvm/book3s_hv_rm_xics.c     |   2 +-
 arch/powerpc/kvm/book3s_paired_singles.c | 121 +---
 arch/powerpc/kvm/book3s_pr.c             |  88 +--
 arch/powerpc/kvm/booke.c                 |  45 +-
 arch/powerpc/kvm/booke_emulate.c         |  12 +-
 arch/powerpc/kvm/e500_mmu.c              |   2 +-
 arch/powerpc/kvm/emulate.c               | 318 ++++------
 arch/powerpc/kvm/powerpc.c               | 148 +++--
 arch/powerpc/lib/sstep.c                 | 987 ++++++++++++++++++++-----------
 22 files changed, 1093 insertions(+), 904 deletions(-)

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [RFC PATCH 0/5] Improve PPC instruction emulation
@ 2014-07-19 10:14 ` Paul Mackerras
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This series aims to increase the range of instructions that KVM on PPC
can emulate and reduce code duplication by using the existing
instruction emulation code from arch/powerpc/lib/sstep.c for KVM.

The ultimate goal is to make PR KVM run faster on the kind of
instruction sequences that we get in Linux's first-level interrupt
handlers, where we have privileged instructions such as move to/from
SPR, mtmsrd, rfid, etc., intermingled with ordinary unprivileged
loads, stores, arithmetic instructions, etc.  If KVM could emulate
those ordinary instructions as well as the privileged ones, we could
emulate these code sequences without incurring the cost to exit and
re-enter the guest for every single privileged instruction.  That
would be a speedup provided the guest entry/exit cost was greater than
the cost of emulating a few ordinary instructions.

This series doesn't get to that ultimate goal but does lay the
groundwork.  It splits the emulate_step() function into two parts,
analyse_instr() and emulate_step(), and uses analyse_instr() in
kvmppc_emulate_instruction().  This means that KVM needs to store its
vcpu integer register state in a struct pt_regs like the rest of the
kernel does.  We also need to make kvmppc_handle_load() and
kvmppc_handle_store() handle loads and stores to ordinary guest memory
as well as emulated MMIO.

I have tested this series by running a Fedora 20 PR guest inside a HV
guest on POWER7.  The series is against Alex Graf's kvm-ppc-queue
branch, plus the 3 bug-fix patches I just posted, and a bug-fix
entitled "powerpc: Fix bugs in emulate_step()" that I posted to the
linuxppc-dev list.

Paul.
--
 arch/powerpc/include/asm/kvm_book3s.h    |  24 +-
 arch/powerpc/include/asm/kvm_booke.h     |  24 +-
 arch/powerpc/include/asm/kvm_host.h      |  22 +-
 arch/powerpc/include/asm/kvm_ppc.h       |  21 +-
 arch/powerpc/include/asm/sstep.h         |  62 ++
 arch/powerpc/kernel/asm-offsets.c        |  32 +-
 arch/powerpc/kvm/Makefile                |   1 +
 arch/powerpc/kvm/book3s_32_mmu.c         |   2 +-
 arch/powerpc/kvm/book3s_64_mmu_hv.c      |  10 +-
 arch/powerpc/kvm/book3s_64_vio_hv.c      |   2 +-
 arch/powerpc/kvm/book3s_emulate.c        |  22 +-
 arch/powerpc/kvm/book3s_hv.c             |  42 +-
 arch/powerpc/kvm/book3s_hv_rm_mmu.c      |  10 +-
 arch/powerpc/kvm/book3s_hv_rm_xics.c     |   2 +-
 arch/powerpc/kvm/book3s_paired_singles.c | 121 +---
 arch/powerpc/kvm/book3s_pr.c             |  88 +--
 arch/powerpc/kvm/booke.c                 |  45 +-
 arch/powerpc/kvm/booke_emulate.c         |  12 +-
 arch/powerpc/kvm/e500_mmu.c              |   2 +-
 arch/powerpc/kvm/emulate.c               | 318 ++++------
 arch/powerpc/kvm/powerpc.c               | 148 +++--
 arch/powerpc/lib/sstep.c                 | 987 ++++++++++++++++++++-----------
 22 files changed, 1093 insertions(+), 904 deletions(-)


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [RFC PATCH 1/5] powerpc: Split out instruction analysis part of emulate_step()
  2014-07-19 10:14 ` Paul Mackerras
@ 2014-07-19 10:14   ` Paul Mackerras
  -1 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This splits out the instruction analysis part of emulate_step() into
a separate analyse_instr() function, which decodes the instruction,
but doesn't execute any load or store instructions.  It does execute
integer instructions and branches which can be executed purely by
updating register values in the pt_regs struct.  For other instructions,
it returns the instruction type and other details in a new
instruction_op struct.  emulate_step() then uses that information
to execute loads, stores, cache operations, mfmsr, mtmsr[d], and
(on 64-bit) sc instructions.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/sstep.h |  62 +++
 arch/powerpc/lib/sstep.c         | 939 ++++++++++++++++++++++++---------------
 2 files changed, 642 insertions(+), 359 deletions(-)

diff --git a/arch/powerpc/include/asm/sstep.h b/arch/powerpc/include/asm/sstep.h
index f593b0f..d3a42cc 100644
--- a/arch/powerpc/include/asm/sstep.h
+++ b/arch/powerpc/include/asm/sstep.h
@@ -25,3 +25,65 @@ struct pt_regs;
 
 /* Emulate instructions that cause a transfer of control. */
 extern int emulate_step(struct pt_regs *regs, unsigned int instr);
+
+enum instruction_type {
+	COMPUTE,		/* arith/logical/CR op, etc. */
+	LOAD,
+	LOAD_MULTI,
+	LOAD_FP,
+	LOAD_VMX,
+	LOAD_VSX,
+	STORE,
+	STORE_MULTI,
+	STORE_FP,
+	STORE_VMX,
+	STORE_VSX,
+	LARX,
+	STCX,
+	BRANCH,
+	MFSPR,
+	MTSPR,
+	CACHEOP,
+	BARRIER,
+	SYSCALL,
+	MFMSR,
+	MTMSR,
+	RFI,
+	INTERRUPT,
+	UNKNOWN
+};
+
+#define INSTR_TYPE_MASK	0x1f
+
+/* Load/store flags, ORed in with type */
+#define SIGNEXT		0x20
+#define UPDATE		0x40	/* matches bit in opcode 31 instructions */
+#define BYTEREV		0x80
+
+/* Cacheop values, ORed in with type */
+#define CACHEOP_MASK	0x700
+#define DCBST		0
+#define DCBF		0x100
+#define DCBTST		0x200
+#define DCBT		0x300
+#define ICBI		0x400
+
+/* Size field in type word */
+#define SIZE(n)		((n) << 8)
+#define GETSIZE(w)	((w) >> 8)
+
+#define MKOP(t, f, s)	((t) | (f) | SIZE(s))
+
+struct instruction_op {
+	int type;
+	int reg;
+	unsigned long val;
+	/* For LOAD/STORE/LARX/STCX */
+	unsigned long ea;
+	int update_reg;
+	/* For MFSPR */
+	int spr;
+};
+
+extern int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
+			 unsigned int instr);
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 5c09f36..7a54df2 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -98,13 +98,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs
 
 	ra = (instr >> 16) & 0x1f;
 	ea = (signed short) instr;		/* sign-extend */
-	if (ra) {
+	if (ra)
 		ea += regs->gpr[ra];
-		if (instr & 0x04000000) {		/* update forms */
-			if ((instr>>26) != 47) 		/* stmw is not an update form */
-				regs->gpr[ra] = ea;
-		}
-	}
 
 	return truncate_if_32bit(regs->msr, ea);
 }
@@ -120,11 +115,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
 
 	ra = (instr >> 16) & 0x1f;
 	ea = (signed short) (instr & ~3);	/* sign-extend */
-	if (ra) {
+	if (ra)
 		ea += regs->gpr[ra];
-		if ((instr & 3) == 1)		/* update forms */
-			regs->gpr[ra] = ea;
-	}
 
 	return truncate_if_32bit(regs->msr, ea);
 }
@@ -133,8 +125,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
 /*
  * Calculate effective address for an X-form instruction
  */
-static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs,
-				     int do_update)
+static unsigned long __kprobes xform_ea(unsigned int instr,
+					struct pt_regs *regs)
 {
 	int ra, rb;
 	unsigned long ea;
@@ -142,11 +134,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs
 	ra = (instr >> 16) & 0x1f;
 	rb = (instr >> 11) & 0x1f;
 	ea = regs->gpr[rb];
-	if (ra) {
+	if (ra)
 		ea += regs->gpr[ra];
-		if (do_update)		/* update forms */
-			regs->gpr[ra] = ea;
-	}
 
 	return truncate_if_32bit(regs->msr, ea);
 }
@@ -611,6 +600,23 @@ static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
 	regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
 }
 
+static int __kprobes trap_compare(long v1, long v2)
+{
+	int ret = 0;
+
+	if (v1 < v2)
+		ret |= 0x10;
+	else if (v1 > v2)
+		ret |= 0x08;
+	else
+		ret |= 0x04;
+	if ((unsigned long)v1 < (unsigned long)v2)
+		ret |= 0x02;
+	else if ((unsigned long)v1 > (unsigned long)v2)
+		ret |= 0x01;
+	return ret;
+}
+
 /*
  * Elements of 32-bit rotate and mask instructions.
  */
@@ -627,26 +633,27 @@ static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
 #define ROTATE(x, n)	((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x))
 
 /*
- * Emulate instructions that cause a transfer of control,
- * loads and stores, and a few other instructions.
- * Returns 1 if the step was emulated, 0 if not,
- * or -1 if the instruction is one that should not be stepped,
- * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ * Decode an instruction, and execute it if that can be done just by
+ * modifying *regs (i.e. integer arithmetic and logical instructions,
+ * branches, and barrier instructions).
+ * Returns 1 if the instruction has been executed, or 0 if not.
+ * Sets *op to indicate what the instruction does.
  */
-int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
+int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
+			    unsigned int instr)
 {
 	unsigned int opcode, ra, rb, rd, spr, u;
 	unsigned long int imm;
 	unsigned long int val, val2;
-	unsigned long int ea;
-	unsigned int cr, mb, me, sh;
-	int err;
-	unsigned long old_ra, val3;
+	unsigned int mb, me, sh;
 	long ival;
 
+	op->type = COMPUTE;
+
 	opcode = instr >> 26;
 	switch (opcode) {
 	case 16:	/* bc */
+		op->type = BRANCH;
 		imm = (signed short)(instr & 0xfffc);
 		if ((instr & 2) == 0)
 			imm += regs->nip;
@@ -659,26 +666,14 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		return 1;
 #ifdef CONFIG_PPC64
 	case 17:	/* sc */
-		/*
-		 * N.B. this uses knowledge about how the syscall
-		 * entry code works.  If that is changed, this will
-		 * need to be changed also.
-		 */
-		if (regs->gpr[0] == 0x1ebe &&
-		    cpu_has_feature(CPU_FTR_REAL_LE)) {
-			regs->msr ^= MSR_LE;
-			goto instr_done;
-		}
-		regs->gpr[9] = regs->gpr[13];
-		regs->gpr[10] = MSR_KERNEL;
-		regs->gpr[11] = regs->nip + 4;
-		regs->gpr[12] = regs->msr & MSR_MASK;
-		regs->gpr[13] = (unsigned long) get_paca();
-		regs->nip = (unsigned long) &system_call_common;
-		regs->msr = MSR_KERNEL;
-		return 1;
+		if ((instr & 0xfe2) == 2)
+			op->type = SYSCALL;
+		else
+			op->type = UNKNOWN;
+		return 0;
 #endif
 	case 18:	/* b */
+		op->type = BRANCH;
 		imm = instr & 0x03fffffc;
 		if (imm & 0x02000000)
 			imm -= 0x04000000;
@@ -693,6 +688,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		switch ((instr >> 1) & 0x3ff) {
 		case 16:	/* bclr */
 		case 528:	/* bcctr */
+			op->type = BRANCH;
 			imm = (instr & 0x400)? regs->ctr: regs->link;
 			regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
 			imm = truncate_if_32bit(regs->msr, imm);
@@ -703,9 +699,13 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 			return 1;
 
 		case 18:	/* rfid, scary */
-			return -1;
+			if (regs->msr & MSR_PR)
+				goto priv;
+			op->type = RFI;
+			return 0;
 
 		case 150:	/* isync */
+			op->type = BARRIER;
 			isync();
 			goto instr_done;
 
@@ -731,6 +731,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 	case 31:
 		switch ((instr >> 1) & 0x3ff) {
 		case 598:	/* sync */
+			op->type = BARRIER;
 #ifdef __powerpc64__
 			switch ((instr >> 21) & 3) {
 			case 1:		/* lwsync */
@@ -745,6 +746,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 			goto instr_done;
 
 		case 854:	/* eieio */
+			op->type = BARRIER;
 			eieio();
 			goto instr_done;
 		}
@@ -760,6 +762,17 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 	rb = (instr >> 11) & 0x1f;
 
 	switch (opcode) {
+#ifdef __powerpc64__
+	case 2:		/* tdi */
+		if (rd & trap_compare(regs->gpr[ra], (short) instr))
+			goto trap;
+		goto instr_done;
+#endif
+	case 3:		/* twi */
+		if (rd & trap_compare((int)regs->gpr[ra], (short) instr))
+			goto trap;
+		goto instr_done;
+
 	case 7:		/* mulli */
 		regs->gpr[rd] = regs->gpr[ra] * (short) instr;
 		goto instr_done;
@@ -908,35 +921,44 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 
 	case 31:
 		switch ((instr >> 1) & 0x3ff) {
+		case 4:		/* twi */
+			if (rd == 0x1f ||
+			    (rd & trap_compare((int)regs->gpr[ra],
+					       (int)regs->gpr[rb])))
+				goto trap;
+			goto instr_done;
+#ifdef __powerpc64__
+		case 68:	/* tdi */
+			if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb]))
+				goto trap;
+			goto instr_done;
+#endif
 		case 83:	/* mfmsr */
 			if (regs->msr & MSR_PR)
-				break;
-			regs->gpr[rd] = regs->msr & MSR_MASK;
-			goto instr_done;
+				goto priv;
+			op->type = MFMSR;
+			op->reg = rd;
+			return 0;
 		case 146:	/* mtmsr */
 			if (regs->msr & MSR_PR)
-				break;
-			imm = regs->gpr[rd];
-			if ((imm & MSR_RI) == 0)
-				/* can't step mtmsr that would clear MSR_RI */
-				return -1;
-			regs->msr = imm;
-			goto instr_done;
+				goto priv;
+			op->type = MTMSR;
+			op->reg = rd;
+			op->val = 0xffffffff & ~(MSR_ME | MSR_LE);
+			return 0;
 #ifdef CONFIG_PPC64
 		case 178:	/* mtmsrd */
-			/* only MSR_EE and MSR_RI get changed if bit 15 set */
-			/* mtmsrd doesn't change MSR_HV and MSR_ME */
 			if (regs->msr & MSR_PR)
-				break;
-			imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL;
-			imm = (regs->msr & MSR_MASK & ~imm)
-				| (regs->gpr[rd] & imm);
-			if ((imm & MSR_RI) == 0)
-				/* can't step mtmsrd that would clear MSR_RI */
-				return -1;
-			regs->msr = imm;
-			goto instr_done;
+				goto priv;
+			op->type = MTMSR;
+			op->reg = rd;
+			/* only MSR_EE and MSR_RI get changed if bit 15 set */
+			/* mtmsrd doesn't change MSR_HV, MSR_ME or MSR_LE */
+			imm = (instr & 0x10000)? 0x8002: 0xefffffffffffeffeUL;
+			op->val = imm;
+			return 0;
 #endif
+
 		case 19:	/* mfcr */
 			regs->gpr[rd] = regs->ccr;
 			regs->gpr[rd] &= 0xffffffffUL;
@@ -954,33 +976,43 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 			goto instr_done;
 
 		case 339:	/* mfspr */
-			spr = (instr >> 11) & 0x3ff;
+			spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
 			switch (spr) {
-			case 0x20:	/* mfxer */
+			case SPRN_XER:	/* mfxer */
 				regs->gpr[rd] = regs->xer;
 				regs->gpr[rd] &= 0xffffffffUL;
 				goto instr_done;
-			case 0x100:	/* mflr */
+			case SPRN_LR:	/* mflr */
 				regs->gpr[rd] = regs->link;
 				goto instr_done;
-			case 0x120:	/* mfctr */
+			case SPRN_CTR:	/* mfctr */
 				regs->gpr[rd] = regs->ctr;
 				goto instr_done;
+			default:
+				op->type = MFSPR;
+				op->reg = rd;
+				op->spr = spr;
+				return 0;
 			}
 			break;
 
 		case 467:	/* mtspr */
-			spr = (instr >> 11) & 0x3ff;
+			spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
 			switch (spr) {
-			case 0x20:	/* mtxer */
+			case SPRN_XER:	/* mtxer */
 				regs->xer = (regs->gpr[rd] & 0xffffffffUL);
 				goto instr_done;
-			case 0x100:	/* mtlr */
+			case SPRN_LR:	/* mtlr */
 				regs->link = regs->gpr[rd];
 				goto instr_done;
-			case 0x120:	/* mtctr */
+			case SPRN_CTR:	/* mtctr */
 				regs->ctr = regs->gpr[rd];
 				goto instr_done;
+			default:
+				op->type = MTSPR;
+				op->val = regs->gpr[rd];
+				op->spr = spr;
+				return 0;
 			}
 			break;
 
@@ -1257,294 +1289,215 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
  * Cache instructions
  */
 		case 54:	/* dcbst */
-			ea = xform_ea(instr, regs, 0);
-			if (!address_ok(regs, ea, 8))
-				return 0;
-			err = 0;
-			__cacheop_user_asmx(ea, err, "dcbst");
-			if (err)
-				return 0;
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBST, 0);
+			op->ea = xform_ea(instr, regs);
+			return 0;
 
 		case 86:	/* dcbf */
-			ea = xform_ea(instr, regs, 0);
-			if (!address_ok(regs, ea, 8))
-				return 0;
-			err = 0;
-			__cacheop_user_asmx(ea, err, "dcbf");
-			if (err)
-				return 0;
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBF, 0);
+			op->ea = xform_ea(instr, regs);
+			return 0;
 
 		case 246:	/* dcbtst */
-			if (rd == 0) {
-				ea = xform_ea(instr, regs, 0);
-				prefetchw((void *) ea);
-			}
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBTST, 0);
+			op->ea = xform_ea(instr, regs);
+			op->reg = rd;
+			return 0;
 
 		case 278:	/* dcbt */
-			if (rd == 0) {
-				ea = xform_ea(instr, regs, 0);
-				prefetch((void *) ea);
-			}
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBTST, 0);
+			op->ea = xform_ea(instr, regs);
+			op->reg = rd;
+			return 0;
 
+		case 982:	/* icbi */
+			op->type = MKOP(CACHEOP, ICBI, 0);
+			op->ea = xform_ea(instr, regs);
+			return 0;
 		}
 		break;
 	}
 
 	/*
-	 * Following cases are for loads and stores, so bail out
-	 * if we're in little-endian mode.
+	 * Loads and stores.
 	 */
-	if (regs->msr & MSR_LE)
-		return 0;
-
-	/*
-	 * Save register RA in case it's an update form load or store
-	 * and the access faults.
-	 */
-	old_ra = regs->gpr[ra];
+	op->type = UNKNOWN;
+	op->update_reg = ra;
+	op->reg = rd;
+	op->val = regs->gpr[rd];
+	u = (instr >> 20) & UPDATE;
 
 	switch (opcode) {
 	case 31:
-		u = instr & 0x40;
+		u = instr & UPDATE;
+		op->ea = xform_ea(instr, regs);
 		switch ((instr >> 1) & 0x3ff) {
 		case 20:	/* lwarx */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 3)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 4))
-				goto ldst_done;
-			err = 0;
-			__get_user_asmx(val, ea, err, "lwarx");
-			if (!err)
-				regs->gpr[rd] = val;
-			goto ldst_done;
+			op->type = MKOP(LARX, 0, 4);
+			break;
 
 		case 150:	/* stwcx. */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 3)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 4))
-				goto ldst_done;
-			err = 0;
-			__put_user_asmx(regs->gpr[rd], ea, err, "stwcx.", cr);
-			if (!err)
-				regs->ccr = (regs->ccr & 0x0fffffff) |
-					(cr & 0xe0000000) |
-					((regs->xer >> 3) & 0x10000000);
-			goto ldst_done;
+			op->type = MKOP(STCX, 0, 4);
+			break;
 
 #ifdef __powerpc64__
 		case 84:	/* ldarx */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 7)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 8))
-				goto ldst_done;
-			err = 0;
-			__get_user_asmx(val, ea, err, "ldarx");
-			if (!err)
-				regs->gpr[rd] = val;
-			goto ldst_done;
+			op->type = MKOP(LARX, 0, 8);
+			break;
 
 		case 214:	/* stdcx. */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 7)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 8))
-				goto ldst_done;
-			err = 0;
-			__put_user_asmx(regs->gpr[rd], ea, err, "stdcx.", cr);
-			if (!err)
-				regs->ccr = (regs->ccr & 0x0fffffff) |
-					(cr & 0xe0000000) |
-					((regs->xer >> 3) & 0x10000000);
-			goto ldst_done;
+			op->type = MKOP(STCX, 0, 8);
+			break;
 
 		case 21:	/* ldx */
 		case 53:	/* ldux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       8, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 8);
+			break;
 #endif
 
 		case 23:	/* lwzx */
 		case 55:	/* lwzux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       4, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 4);
+			break;
 
 		case 87:	/* lbzx */
 		case 119:	/* lbzux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       1, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 1);
+			break;
 
 #ifdef CONFIG_ALTIVEC
 		case 103:	/* lvx */
 		case 359:	/* lvxl */
 			if (!(regs->msr & MSR_VEC))
-				break;
-			ea = xform_ea(instr, regs, 0);
-			err = do_vec_load(rd, do_lvx, ea, regs);
-			goto ldst_done;
+				goto vecunavail;
+			op->type = MKOP(LOAD_VMX, 0, 16);
+			break;
 
 		case 231:	/* stvx */
 		case 487:	/* stvxl */
 			if (!(regs->msr & MSR_VEC))
-				break;
-			ea = xform_ea(instr, regs, 0);
-			err = do_vec_store(rd, do_stvx, ea, regs);
-			goto ldst_done;
+				goto vecunavail;
+			op->type = MKOP(STORE_VMX, 0, 16);
+			break;
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef __powerpc64__
 		case 149:	/* stdx */
 		case 181:	/* stdux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 8);
+			break;
 #endif
 
 		case 151:	/* stwx */
 		case 183:	/* stwux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 4, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 4);
+			break;
 
 		case 215:	/* stbx */
 		case 247:	/* stbux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 1, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 1);
+			break;
 
 		case 279:	/* lhzx */
 		case 311:	/* lhzux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       2, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 2);
+			break;
 
 #ifdef __powerpc64__
 		case 341:	/* lwax */
 		case 373:	/* lwaux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       4, regs);
-			if (!err)
-				regs->gpr[rd] = (signed int) regs->gpr[rd];
-			goto ldst_done;
+			op->type = MKOP(LOAD, SIGNEXT | u, 4);
+			break;
 #endif
 
 		case 343:	/* lhax */
 		case 375:	/* lhaux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       2, regs);
-			if (!err)
-				regs->gpr[rd] = (signed short) regs->gpr[rd];
-			goto ldst_done;
+			op->type = MKOP(LOAD, SIGNEXT | u, 2);
+			break;
 
 		case 407:	/* sthx */
 		case 439:	/* sthux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 2, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 2);
+			break;
 
 #ifdef __powerpc64__
 		case 532:	/* ldbrx */
-			err = read_mem(&val, xform_ea(instr, regs, 0), 8, regs);
-			if (!err)
-				regs->gpr[rd] = byterev_8(val);
-			goto ldst_done;
+			op->type = MKOP(LOAD, BYTEREV, 8);
+			break;
 
 #endif
 
 		case 534:	/* lwbrx */
-			err = read_mem(&val, xform_ea(instr, regs, 0), 4, regs);
-			if (!err)
-				regs->gpr[rd] = byterev_4(val);
-			goto ldst_done;
+			op->type = MKOP(LOAD, BYTEREV, 4);
+			break;
 
 #ifdef CONFIG_PPC_FPU
 		case 535:	/* lfsx */
 		case 567:	/* lfsux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_load(rd, do_lfs, ea, 4, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(LOAD_FP, u, 4);
+			break;
 
 		case 599:	/* lfdx */
 		case 631:	/* lfdux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_load(rd, do_lfd, ea, 8, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(LOAD_FP, u, 8);
+			break;
 
 		case 663:	/* stfsx */
 		case 695:	/* stfsux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_store(rd, do_stfs, ea, 4, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(STORE_FP, u, 4);
+			break;
 
 		case 727:	/* stfdx */
 		case 759:	/* stfdux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_store(rd, do_stfd, ea, 8, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(STORE_FP, u, 8);
+			break;
 #endif
 
 #ifdef __powerpc64__
 		case 660:	/* stdbrx */
-			val = byterev_8(regs->gpr[rd]);
-			err = write_mem(val, xform_ea(instr, regs, 0), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, BYTEREV, 8);
+			op->val = byterev_8(regs->gpr[rd]);
+			break;
 
 #endif
 		case 662:	/* stwbrx */
-			val = byterev_4(regs->gpr[rd]);
-			err = write_mem(val, xform_ea(instr, regs, 0), 4, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, BYTEREV, 4);
+			op->val = byterev_4(regs->gpr[rd]);
+			break;
 
 		case 790:	/* lhbrx */
-			err = read_mem(&val, xform_ea(instr, regs, 0), 2, regs);
-			if (!err)
-				regs->gpr[rd] = byterev_2(val);
-			goto ldst_done;
+			op->type = MKOP(LOAD, BYTEREV, 2);
+			break;
 
 		case 918:	/* sthbrx */
-			val = byterev_2(regs->gpr[rd]);
-			err = write_mem(val, xform_ea(instr, regs, 0), 2, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, BYTEREV, 2);
+			op->val = byterev_2(regs->gpr[rd]);
+			break;
 
 #ifdef CONFIG_VSX
 		case 844:	/* lxvd2x */
 		case 876:	/* lxvd2ux */
 			if (!(regs->msr & MSR_VSX))
-				break;
-			rd |= (instr & 1) << 5;
-			ea = xform_ea(instr, regs, u);
-			err = do_vsx_load(rd, do_lxvd2x, ea, regs);
-			goto ldst_done;
+				goto vsxunavail;
+			op->reg = rd | ((instr & 1) << 5);
+			op->type = MKOP(LOAD_VSX, u, 16);
+			break;
 
 		case 972:	/* stxvd2x */
 		case 1004:	/* stxvd2ux */
 			if (!(regs->msr & MSR_VSX))
-				break;
-			rd |= (instr & 1) << 5;
-			ea = xform_ea(instr, regs, u);
-			err = do_vsx_store(rd, do_stxvd2x, ea, regs);
-			goto ldst_done;
+				goto vsxunavail;
+			op->reg = rd | ((instr & 1) << 5);
+			op->type = MKOP(STORE_VSX, u, 16);
+			break;
 
 #endif /* CONFIG_VSX */
 		}
@@ -1552,178 +1505,124 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 
 	case 32:	/* lwz */
 	case 33:	/* lwzu */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 4, regs);
-		goto ldst_done;
+		op->type = MKOP(LOAD, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 34:	/* lbz */
 	case 35:	/* lbzu */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 1, regs);
-		goto ldst_done;
+		op->type = MKOP(LOAD, u, 1);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 36:	/* stw */
-		val = regs->gpr[rd];
-		err = write_mem(val, dform_ea(instr, regs), 4, regs);
-		goto ldst_done;
-
 	case 37:	/* stwu */
-		val = regs->gpr[rd];
-		val3 = dform_ea(instr, regs);
-		/*
-		 * For PPC32 we always use stwu to change stack point with r1. So
-		 * this emulated store may corrupt the exception frame, now we
-		 * have to provide the exception frame trampoline, which is pushed
-		 * below the kprobed function stack. So we only update gpr[1] but
-		 * don't emulate the real store operation. We will do real store
-		 * operation safely in exception return code by checking this flag.
-		 */
-		if ((ra == 1) && !(regs->msr & MSR_PR) \
-			&& (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) {
-#ifdef CONFIG_PPC32
-			/*
-			 * Check if we will touch kernel sack overflow
-			 */
-			if (val3 - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) {
-				printk(KERN_CRIT "Can't kprobe this since Kernel stack overflow.\n");
-				err = -EINVAL;
-				break;
-			}
-#endif /* CONFIG_PPC32 */
-			/*
-			 * Check if we already set since that means we'll
-			 * lose the previous value.
-			 */
-			WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
-			set_thread_flag(TIF_EMULATE_STACK_STORE);
-			err = 0;
-		} else
-			err = write_mem(val, val3, 4, regs);
-		goto ldst_done;
+		op->type = MKOP(STORE, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 38:	/* stb */
 	case 39:	/* stbu */
-		val = regs->gpr[rd];
-		err = write_mem(val, dform_ea(instr, regs), 1, regs);
-		goto ldst_done;
+		op->type = MKOP(STORE, u, 1);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 40:	/* lhz */
 	case 41:	/* lhzu */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
-		goto ldst_done;
+		op->type = MKOP(LOAD, u, 2);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 42:	/* lha */
 	case 43:	/* lhau */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
-		if (!err)
-			regs->gpr[rd] = (signed short) regs->gpr[rd];
-		goto ldst_done;
+		op->type = MKOP(LOAD, SIGNEXT | u, 2);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 44:	/* sth */
 	case 45:	/* sthu */
-		val = regs->gpr[rd];
-		err = write_mem(val, dform_ea(instr, regs), 2, regs);
-		goto ldst_done;
+		op->type = MKOP(STORE, u, 2);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 46:	/* lmw */
 		ra = (instr >> 16) & 0x1f;
 		if (ra >= rd)
 			break;		/* invalid form, ra in range to load */
-		ea = dform_ea(instr, regs);
-		do {
-			err = read_mem(&regs->gpr[rd], ea, 4, regs);
-			if (err)
-				return 0;
-			ea += 4;
-		} while (++rd < 32);
-		goto instr_done;
+		op->type = MKOP(LOAD_MULTI, 0, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 47:	/* stmw */
-		ea = dform_ea(instr, regs);
-		do {
-			err = write_mem(regs->gpr[rd], ea, 4, regs);
-			if (err)
-				return 0;
-			ea += 4;
-		} while (++rd < 32);
-		goto instr_done;
+		op->type = MKOP(STORE_MULTI, 0, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 #ifdef CONFIG_PPC_FPU
 	case 48:	/* lfs */
 	case 49:	/* lfsu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_load(rd, do_lfs, ea, 4, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(LOAD_FP, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 50:	/* lfd */
 	case 51:	/* lfdu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_load(rd, do_lfd, ea, 8, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(LOAD_FP, u, 8);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 52:	/* stfs */
 	case 53:	/* stfsu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_store(rd, do_stfs, ea, 4, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(STORE_FP, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 54:	/* stfd */
 	case 55:	/* stfdu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_store(rd, do_stfd, ea, 8, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(STORE_FP, u, 8);
+		op->ea = dform_ea(instr, regs);
+		break;
 #endif
 
 #ifdef __powerpc64__
 	case 58:	/* ld[u], lwa */
+		op->ea = dsform_ea(instr, regs);
 		switch (instr & 3) {
 		case 0:		/* ld */
-			err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-				       8, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, 0, 8);
+			break;
 		case 1:		/* ldu */
-			err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-				       8, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, UPDATE, 8);
+			break;
 		case 2:		/* lwa */
-			err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-				       4, regs);
-			if (!err)
-				regs->gpr[rd] = (signed int) regs->gpr[rd];
-			goto ldst_done;
+			op->type = MKOP(LOAD, SIGNEXT, 4);
+			break;
 		}
 		break;
 
 	case 62:	/* std[u] */
-		val = regs->gpr[rd];
+		op->ea = dsform_ea(instr, regs);
 		switch (instr & 3) {
 		case 0:		/* std */
-			err = write_mem(val, dsform_ea(instr, regs), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, 0, 8);
+			break;
 		case 1:		/* stdu */
-			err = write_mem(val, dsform_ea(instr, regs), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, UPDATE, 8);
+			break;
 		}
 		break;
 #endif /* __powerpc64__ */
 
 	}
-	err = -EINVAL;
-
- ldst_done:
-	if (err) {
-		regs->gpr[ra] = old_ra;
-		return 0;	/* invoke DSI if -EFAULT? */
-	}
- instr_done:
-	regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
-	return 1;
+	return 0;
 
  logical_done:
 	if (instr & 1)
@@ -1733,5 +1632,327 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
  arith_done:
 	if (instr & 1)
 		set_cr0(regs, rd);
-	goto instr_done;
+
+ instr_done:
+	regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
+	return 1;
+
+ priv:
+	op->type = INTERRUPT | 0x700;
+	op->val = SRR1_PROGPRIV;
+	return 0;
+
+ trap:
+	op->type = INTERRUPT | 0x700;
+	op->val = SRR1_PROGTRAP;
+	return 0;
+
+#ifdef CONFIG_PPC_FPU
+ fpunavail:
+	op->type = INTERRUPT | 0x800;
+	return 0;
+#endif
+
+#ifdef CONFIG_ALTIVEC
+ vecunavail:
+	op->type = INTERRUPT | 0xf20;
+	return 0;
+#endif
+
+#ifdef CONFIG_VSX
+ vsxunavail:
+	op->type = INTERRUPT | 0xf40;
+	return 0;
+#endif
+}
+EXPORT_SYMBOL_GPL(analyse_instr);
+
+/*
+ * For PPC32 we always use stwu with r1 to change the stack pointer.
+ * So this emulated store may corrupt the exception frame, now we
+ * have to provide the exception frame trampoline, which is pushed
+ * below the kprobed function stack. So we only update gpr[1] but
+ * don't emulate the real store operation. We will do real store
+ * operation safely in exception return code by checking this flag.
+ */
+static __kprobes int handle_stack_update(unsigned long ea, struct pt_regs *regs)
+{
+#ifdef CONFIG_PPC32
+	/*
+	 * Check if we will touch kernel stack overflow
+	 */
+	if (ea - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) {
+		printk(KERN_CRIT "Can't kprobe this since Kernel stack overflow.\n");
+		return -EINVAL;
+	}
+#endif /* CONFIG_PPC32 */
+	/*
+	 * Check if we already set since that means we'll
+	 * lose the previous value.
+	 */
+	WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
+	set_thread_flag(TIF_EMULATE_STACK_STORE);
+	return 0;
+}
+
+static __kprobes void do_signext(unsigned long *valp, int size)
+{
+	switch (size) {
+	case 2:
+		*valp = (signed short) *valp;
+		break;
+	case 4:
+		*valp = (signed int) *valp;
+		break;
+	}
+}
+
+static __kprobes void do_byterev(unsigned long *valp, int size)
+{
+	switch (size) {
+	case 2:
+		*valp = byterev_2(*valp);
+		break;
+	case 4:
+		*valp = byterev_4(*valp);
+		break;
+	case 8:
+		*valp = byterev_8(*valp);
+		break;
+	}
+}
+
+/*
+ * Emulate instructions that cause a transfer of control,
+ * loads and stores, and a few other instructions.
+ * Returns 1 if the step was emulated, 0 if not,
+ * or -1 if the instruction is one that should not be stepped,
+ * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ */
+int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
+{
+	struct instruction_op op;
+	int r, err, size;
+	unsigned long val;
+	unsigned int cr;
+	int rd;
+
+	r = analyse_instr(&op, regs, instr);
+	if (r != 0)
+		return r;
+
+	err = 0;
+	size = GETSIZE(op.type);
+	switch (op.type & INSTR_TYPE_MASK) {
+	case CACHEOP:
+		if (!address_ok(regs, op.ea, 8))
+			return 0;
+		switch (op.type & CACHEOP_MASK) {
+		case DCBST:
+			__cacheop_user_asmx(op.ea, err, "dcbst");
+			break;
+		case DCBF:
+			__cacheop_user_asmx(op.ea, err, "dcbf");
+			break;
+		case DCBTST:
+			if (op.reg == 0)
+				prefetchw((void *) op.ea);
+			break;
+		case DCBT:
+			if (op.reg == 0)
+				prefetch((void *) op.ea);
+			break;
+		}
+		if (err)
+			return 0;
+		goto instr_done;
+
+	case LARX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (op.ea & (size - 1))
+			break;		/* can't handle misaligned */
+		err = -EFAULT;
+		if (!address_ok(regs, op.ea, size))
+			goto ldst_done;
+		err = 0;
+		switch (size) {
+		case 4:
+			__get_user_asmx(val, op.ea, err, "lwarx");
+			break;
+		case 8:
+			__get_user_asmx(val, op.ea, err, "ldarx");
+			break;
+		default:
+			return 0;
+		}
+		if (!err)
+			regs->gpr[op.reg] = val;
+		goto ldst_done;
+
+	case STCX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (op.ea & (size - 1))
+			break;		/* can't handle misaligned */
+		err = -EFAULT;
+		if (!address_ok(regs, op.ea, size))
+			goto ldst_done;
+		err = 0;
+		switch (size) {
+		case 4:
+			__put_user_asmx(op.val, op.ea, err, "stwcx.", cr);
+			break;
+		case 8:
+			__put_user_asmx(op.val, op.ea, err, "stdcx.", cr);
+			break;
+		default:
+			return 0;
+		}
+		if (!err)
+			regs->ccr = (regs->ccr & 0x0fffffff) |
+				(cr & 0xe0000000) |
+				((regs->xer >> 3) & 0x10000000);
+		goto ldst_done;
+
+	case LOAD:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = read_mem(&regs->gpr[op.reg], op.ea, size, regs);
+		if (!err) {
+			if (op.type & SIGNEXT)
+				do_signext(&regs->gpr[op.reg], size);
+			if (op.type & BYTEREV)
+				do_byterev(&regs->gpr[op.reg], size);
+		}
+		goto ldst_done;
+
+	case LOAD_FP:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (size == 4)
+			err = do_fp_load(op.reg, do_lfs, op.ea, size, regs);
+		else
+			err = do_fp_load(op.reg, do_lfd, op.ea, size, regs);
+		goto ldst_done;
+
+	case LOAD_VMX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vec_load(op.reg, do_lvx, op.ea & ~0xfUL, regs);
+		goto ldst_done;
+
+	case LOAD_VSX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vsx_load(op.reg, do_lxvd2x, op.ea, regs);
+		goto ldst_done;
+
+	case LOAD_MULTI:
+		if (regs->msr & MSR_LE)
+			return 0;
+		rd = op.reg;
+		do {
+			err = read_mem(&regs->gpr[rd], op.ea, 4, regs);
+			if (err)
+				return 0;
+			op.ea += 4;
+		} while (++rd < 32);
+		goto instr_done;
+
+	case STORE:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if ((op.type & UPDATE) && size == sizeof(long) &&
+		    op.reg == 1 && op.update_reg == 1 &&
+		    !(regs->msr & MSR_PR) &&
+		    op.ea >= regs->gpr[1] - STACK_INT_FRAME_SIZE) {
+			err = handle_stack_update(op.ea, regs);
+			goto ldst_done;
+		}
+		err = write_mem(op.val, op.ea, size, regs);
+		goto ldst_done;
+
+	case STORE_FP:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (size == 4)
+			err = do_fp_store(op.reg, do_stfs, op.ea, size, regs);
+		else
+			err = do_fp_store(op.reg, do_stfd, op.ea, size, regs);
+		goto ldst_done;
+
+	case STORE_VMX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vec_store(op.reg, do_stvx, op.ea & ~0xfUL, regs);
+		goto ldst_done;
+
+	case STORE_VSX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vsx_store(op.reg, do_stxvd2x, op.ea, regs);
+		goto ldst_done;
+
+	case STORE_MULTI:
+		if (regs->msr & MSR_LE)
+			return 0;
+		rd = op.reg;
+		do {
+			err = write_mem(regs->gpr[rd], op.ea, 4, regs);
+			if (err)
+				return 0;
+			op.ea += 4;
+		} while (++rd < 32);
+		goto instr_done;
+
+	case MFMSR:
+		regs->gpr[op.reg] = regs->msr & MSR_MASK;
+		goto instr_done;
+
+	case MTMSR:
+		val = regs->gpr[op.reg];
+		if ((val & MSR_RI) == 0)
+			/* can't step mtmsr[d] that would clear MSR_RI */
+			return -1;
+		/* here op.val is the mask of bits to change */
+		regs->msr = (regs->msr & ~op.val) | (val & op.val);
+		goto instr_done;
+
+#ifdef CONFIG_PPC64
+	case SYSCALL:	/* sc */
+		/*
+		 * N.B. this uses knowledge about how the syscall
+		 * entry code works.  If that is changed, this will
+		 * need to be changed also.
+		 */
+		if (regs->gpr[0] == 0x1ebe &&
+		    cpu_has_feature(CPU_FTR_REAL_LE)) {
+			regs->msr ^= MSR_LE;
+			goto instr_done;
+		}
+		regs->gpr[9] = regs->gpr[13];
+		regs->gpr[10] = MSR_KERNEL;
+		regs->gpr[11] = regs->nip + 4;
+		regs->gpr[12] = regs->msr & MSR_MASK;
+		regs->gpr[13] = (unsigned long) get_paca();
+		regs->nip = (unsigned long) &system_call_common;
+		regs->msr = MSR_KERNEL;
+		return 1;
+
+	case RFI:
+		return -1;
+#endif
+	}
+	return 0;
+
+ ldst_done:
+	if (err)
+		return 0;
+	if (op.type & UPDATE)
+		regs->gpr[op.update_reg] = op.ea;
+
+ instr_done:
+	regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
+	return 1;
 }
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 1/5] powerpc: Split out instruction analysis part of emulate_step()
@ 2014-07-19 10:14   ` Paul Mackerras
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This splits out the instruction analysis part of emulate_step() into
a separate analyse_instr() function, which decodes the instruction,
but doesn't execute any load or store instructions.  It does execute
integer instructions and branches which can be executed purely by
updating register values in the pt_regs struct.  For other instructions,
it returns the instruction type and other details in a new
instruction_op struct.  emulate_step() then uses that information
to execute loads, stores, cache operations, mfmsr, mtmsr[d], and
(on 64-bit) sc instructions.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/sstep.h |  62 +++
 arch/powerpc/lib/sstep.c         | 939 ++++++++++++++++++++++++---------------
 2 files changed, 642 insertions(+), 359 deletions(-)

diff --git a/arch/powerpc/include/asm/sstep.h b/arch/powerpc/include/asm/sstep.h
index f593b0f..d3a42cc 100644
--- a/arch/powerpc/include/asm/sstep.h
+++ b/arch/powerpc/include/asm/sstep.h
@@ -25,3 +25,65 @@ struct pt_regs;
 
 /* Emulate instructions that cause a transfer of control. */
 extern int emulate_step(struct pt_regs *regs, unsigned int instr);
+
+enum instruction_type {
+	COMPUTE,		/* arith/logical/CR op, etc. */
+	LOAD,
+	LOAD_MULTI,
+	LOAD_FP,
+	LOAD_VMX,
+	LOAD_VSX,
+	STORE,
+	STORE_MULTI,
+	STORE_FP,
+	STORE_VMX,
+	STORE_VSX,
+	LARX,
+	STCX,
+	BRANCH,
+	MFSPR,
+	MTSPR,
+	CACHEOP,
+	BARRIER,
+	SYSCALL,
+	MFMSR,
+	MTMSR,
+	RFI,
+	INTERRUPT,
+	UNKNOWN
+};
+
+#define INSTR_TYPE_MASK	0x1f
+
+/* Load/store flags, ORed in with type */
+#define SIGNEXT		0x20
+#define UPDATE		0x40	/* matches bit in opcode 31 instructions */
+#define BYTEREV		0x80
+
+/* Cacheop values, ORed in with type */
+#define CACHEOP_MASK	0x700
+#define DCBST		0
+#define DCBF		0x100
+#define DCBTST		0x200
+#define DCBT		0x300
+#define ICBI		0x400
+
+/* Size field in type word */
+#define SIZE(n)		((n) << 8)
+#define GETSIZE(w)	((w) >> 8)
+
+#define MKOP(t, f, s)	((t) | (f) | SIZE(s))
+
+struct instruction_op {
+	int type;
+	int reg;
+	unsigned long val;
+	/* For LOAD/STORE/LARX/STCX */
+	unsigned long ea;
+	int update_reg;
+	/* For MFSPR */
+	int spr;
+};
+
+extern int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
+			 unsigned int instr);
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 5c09f36..7a54df2 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -98,13 +98,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs
 
 	ra = (instr >> 16) & 0x1f;
 	ea = (signed short) instr;		/* sign-extend */
-	if (ra) {
+	if (ra)
 		ea += regs->gpr[ra];
-		if (instr & 0x04000000) {		/* update forms */
-			if ((instr>>26) != 47) 		/* stmw is not an update form */
-				regs->gpr[ra] = ea;
-		}
-	}
 
 	return truncate_if_32bit(regs->msr, ea);
 }
@@ -120,11 +115,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
 
 	ra = (instr >> 16) & 0x1f;
 	ea = (signed short) (instr & ~3);	/* sign-extend */
-	if (ra) {
+	if (ra)
 		ea += regs->gpr[ra];
-		if ((instr & 3) = 1)		/* update forms */
-			regs->gpr[ra] = ea;
-	}
 
 	return truncate_if_32bit(regs->msr, ea);
 }
@@ -133,8 +125,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
 /*
  * Calculate effective address for an X-form instruction
  */
-static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs,
-				     int do_update)
+static unsigned long __kprobes xform_ea(unsigned int instr,
+					struct pt_regs *regs)
 {
 	int ra, rb;
 	unsigned long ea;
@@ -142,11 +134,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs
 	ra = (instr >> 16) & 0x1f;
 	rb = (instr >> 11) & 0x1f;
 	ea = regs->gpr[rb];
-	if (ra) {
+	if (ra)
 		ea += regs->gpr[ra];
-		if (do_update)		/* update forms */
-			regs->gpr[ra] = ea;
-	}
 
 	return truncate_if_32bit(regs->msr, ea);
 }
@@ -611,6 +600,23 @@ static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
 	regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
 }
 
+static int __kprobes trap_compare(long v1, long v2)
+{
+	int ret = 0;
+
+	if (v1 < v2)
+		ret |= 0x10;
+	else if (v1 > v2)
+		ret |= 0x08;
+	else
+		ret |= 0x04;
+	if ((unsigned long)v1 < (unsigned long)v2)
+		ret |= 0x02;
+	else if ((unsigned long)v1 > (unsigned long)v2)
+		ret |= 0x01;
+	return ret;
+}
+
 /*
  * Elements of 32-bit rotate and mask instructions.
  */
@@ -627,26 +633,27 @@ static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
 #define ROTATE(x, n)	((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x))
 
 /*
- * Emulate instructions that cause a transfer of control,
- * loads and stores, and a few other instructions.
- * Returns 1 if the step was emulated, 0 if not,
- * or -1 if the instruction is one that should not be stepped,
- * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ * Decode an instruction, and execute it if that can be done just by
+ * modifying *regs (i.e. integer arithmetic and logical instructions,
+ * branches, and barrier instructions).
+ * Returns 1 if the instruction has been executed, or 0 if not.
+ * Sets *op to indicate what the instruction does.
  */
-int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
+int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
+			    unsigned int instr)
 {
 	unsigned int opcode, ra, rb, rd, spr, u;
 	unsigned long int imm;
 	unsigned long int val, val2;
-	unsigned long int ea;
-	unsigned int cr, mb, me, sh;
-	int err;
-	unsigned long old_ra, val3;
+	unsigned int mb, me, sh;
 	long ival;
 
+	op->type = COMPUTE;
+
 	opcode = instr >> 26;
 	switch (opcode) {
 	case 16:	/* bc */
+		op->type = BRANCH;
 		imm = (signed short)(instr & 0xfffc);
 		if ((instr & 2) = 0)
 			imm += regs->nip;
@@ -659,26 +666,14 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		return 1;
 #ifdef CONFIG_PPC64
 	case 17:	/* sc */
-		/*
-		 * N.B. this uses knowledge about how the syscall
-		 * entry code works.  If that is changed, this will
-		 * need to be changed also.
-		 */
-		if (regs->gpr[0] = 0x1ebe &&
-		    cpu_has_feature(CPU_FTR_REAL_LE)) {
-			regs->msr ^= MSR_LE;
-			goto instr_done;
-		}
-		regs->gpr[9] = regs->gpr[13];
-		regs->gpr[10] = MSR_KERNEL;
-		regs->gpr[11] = regs->nip + 4;
-		regs->gpr[12] = regs->msr & MSR_MASK;
-		regs->gpr[13] = (unsigned long) get_paca();
-		regs->nip = (unsigned long) &system_call_common;
-		regs->msr = MSR_KERNEL;
-		return 1;
+		if ((instr & 0xfe2) = 2)
+			op->type = SYSCALL;
+		else
+			op->type = UNKNOWN;
+		return 0;
 #endif
 	case 18:	/* b */
+		op->type = BRANCH;
 		imm = instr & 0x03fffffc;
 		if (imm & 0x02000000)
 			imm -= 0x04000000;
@@ -693,6 +688,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		switch ((instr >> 1) & 0x3ff) {
 		case 16:	/* bclr */
 		case 528:	/* bcctr */
+			op->type = BRANCH;
 			imm = (instr & 0x400)? regs->ctr: regs->link;
 			regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
 			imm = truncate_if_32bit(regs->msr, imm);
@@ -703,9 +699,13 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 			return 1;
 
 		case 18:	/* rfid, scary */
-			return -1;
+			if (regs->msr & MSR_PR)
+				goto priv;
+			op->type = RFI;
+			return 0;
 
 		case 150:	/* isync */
+			op->type = BARRIER;
 			isync();
 			goto instr_done;
 
@@ -731,6 +731,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 	case 31:
 		switch ((instr >> 1) & 0x3ff) {
 		case 598:	/* sync */
+			op->type = BARRIER;
 #ifdef __powerpc64__
 			switch ((instr >> 21) & 3) {
 			case 1:		/* lwsync */
@@ -745,6 +746,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 			goto instr_done;
 
 		case 854:	/* eieio */
+			op->type = BARRIER;
 			eieio();
 			goto instr_done;
 		}
@@ -760,6 +762,17 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 	rb = (instr >> 11) & 0x1f;
 
 	switch (opcode) {
+#ifdef __powerpc64__
+	case 2:		/* tdi */
+		if (rd & trap_compare(regs->gpr[ra], (short) instr))
+			goto trap;
+		goto instr_done;
+#endif
+	case 3:		/* twi */
+		if (rd & trap_compare((int)regs->gpr[ra], (short) instr))
+			goto trap;
+		goto instr_done;
+
 	case 7:		/* mulli */
 		regs->gpr[rd] = regs->gpr[ra] * (short) instr;
 		goto instr_done;
@@ -908,35 +921,44 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 
 	case 31:
 		switch ((instr >> 1) & 0x3ff) {
+		case 4:		/* twi */
+			if (rd = 0x1f ||
+			    (rd & trap_compare((int)regs->gpr[ra],
+					       (int)regs->gpr[rb])))
+				goto trap;
+			goto instr_done;
+#ifdef __powerpc64__
+		case 68:	/* tdi */
+			if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb]))
+				goto trap;
+			goto instr_done;
+#endif
 		case 83:	/* mfmsr */
 			if (regs->msr & MSR_PR)
-				break;
-			regs->gpr[rd] = regs->msr & MSR_MASK;
-			goto instr_done;
+				goto priv;
+			op->type = MFMSR;
+			op->reg = rd;
+			return 0;
 		case 146:	/* mtmsr */
 			if (regs->msr & MSR_PR)
-				break;
-			imm = regs->gpr[rd];
-			if ((imm & MSR_RI) = 0)
-				/* can't step mtmsr that would clear MSR_RI */
-				return -1;
-			regs->msr = imm;
-			goto instr_done;
+				goto priv;
+			op->type = MTMSR;
+			op->reg = rd;
+			op->val = 0xffffffff & ~(MSR_ME | MSR_LE);
+			return 0;
 #ifdef CONFIG_PPC64
 		case 178:	/* mtmsrd */
-			/* only MSR_EE and MSR_RI get changed if bit 15 set */
-			/* mtmsrd doesn't change MSR_HV and MSR_ME */
 			if (regs->msr & MSR_PR)
-				break;
-			imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL;
-			imm = (regs->msr & MSR_MASK & ~imm)
-				| (regs->gpr[rd] & imm);
-			if ((imm & MSR_RI) = 0)
-				/* can't step mtmsrd that would clear MSR_RI */
-				return -1;
-			regs->msr = imm;
-			goto instr_done;
+				goto priv;
+			op->type = MTMSR;
+			op->reg = rd;
+			/* only MSR_EE and MSR_RI get changed if bit 15 set */
+			/* mtmsrd doesn't change MSR_HV, MSR_ME or MSR_LE */
+			imm = (instr & 0x10000)? 0x8002: 0xefffffffffffeffeUL;
+			op->val = imm;
+			return 0;
 #endif
+
 		case 19:	/* mfcr */
 			regs->gpr[rd] = regs->ccr;
 			regs->gpr[rd] &= 0xffffffffUL;
@@ -954,33 +976,43 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 			goto instr_done;
 
 		case 339:	/* mfspr */
-			spr = (instr >> 11) & 0x3ff;
+			spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
 			switch (spr) {
-			case 0x20:	/* mfxer */
+			case SPRN_XER:	/* mfxer */
 				regs->gpr[rd] = regs->xer;
 				regs->gpr[rd] &= 0xffffffffUL;
 				goto instr_done;
-			case 0x100:	/* mflr */
+			case SPRN_LR:	/* mflr */
 				regs->gpr[rd] = regs->link;
 				goto instr_done;
-			case 0x120:	/* mfctr */
+			case SPRN_CTR:	/* mfctr */
 				regs->gpr[rd] = regs->ctr;
 				goto instr_done;
+			default:
+				op->type = MFSPR;
+				op->reg = rd;
+				op->spr = spr;
+				return 0;
 			}
 			break;
 
 		case 467:	/* mtspr */
-			spr = (instr >> 11) & 0x3ff;
+			spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
 			switch (spr) {
-			case 0x20:	/* mtxer */
+			case SPRN_XER:	/* mtxer */
 				regs->xer = (regs->gpr[rd] & 0xffffffffUL);
 				goto instr_done;
-			case 0x100:	/* mtlr */
+			case SPRN_LR:	/* mtlr */
 				regs->link = regs->gpr[rd];
 				goto instr_done;
-			case 0x120:	/* mtctr */
+			case SPRN_CTR:	/* mtctr */
 				regs->ctr = regs->gpr[rd];
 				goto instr_done;
+			default:
+				op->type = MTSPR;
+				op->val = regs->gpr[rd];
+				op->spr = spr;
+				return 0;
 			}
 			break;
 
@@ -1257,294 +1289,215 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
  * Cache instructions
  */
 		case 54:	/* dcbst */
-			ea = xform_ea(instr, regs, 0);
-			if (!address_ok(regs, ea, 8))
-				return 0;
-			err = 0;
-			__cacheop_user_asmx(ea, err, "dcbst");
-			if (err)
-				return 0;
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBST, 0);
+			op->ea = xform_ea(instr, regs);
+			return 0;
 
 		case 86:	/* dcbf */
-			ea = xform_ea(instr, regs, 0);
-			if (!address_ok(regs, ea, 8))
-				return 0;
-			err = 0;
-			__cacheop_user_asmx(ea, err, "dcbf");
-			if (err)
-				return 0;
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBF, 0);
+			op->ea = xform_ea(instr, regs);
+			return 0;
 
 		case 246:	/* dcbtst */
-			if (rd = 0) {
-				ea = xform_ea(instr, regs, 0);
-				prefetchw((void *) ea);
-			}
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBTST, 0);
+			op->ea = xform_ea(instr, regs);
+			op->reg = rd;
+			return 0;
 
 		case 278:	/* dcbt */
-			if (rd = 0) {
-				ea = xform_ea(instr, regs, 0);
-				prefetch((void *) ea);
-			}
-			goto instr_done;
+			op->type = MKOP(CACHEOP, DCBTST, 0);
+			op->ea = xform_ea(instr, regs);
+			op->reg = rd;
+			return 0;
 
+		case 982:	/* icbi */
+			op->type = MKOP(CACHEOP, ICBI, 0);
+			op->ea = xform_ea(instr, regs);
+			return 0;
 		}
 		break;
 	}
 
 	/*
-	 * Following cases are for loads and stores, so bail out
-	 * if we're in little-endian mode.
+	 * Loads and stores.
 	 */
-	if (regs->msr & MSR_LE)
-		return 0;
-
-	/*
-	 * Save register RA in case it's an update form load or store
-	 * and the access faults.
-	 */
-	old_ra = regs->gpr[ra];
+	op->type = UNKNOWN;
+	op->update_reg = ra;
+	op->reg = rd;
+	op->val = regs->gpr[rd];
+	u = (instr >> 20) & UPDATE;
 
 	switch (opcode) {
 	case 31:
-		u = instr & 0x40;
+		u = instr & UPDATE;
+		op->ea = xform_ea(instr, regs);
 		switch ((instr >> 1) & 0x3ff) {
 		case 20:	/* lwarx */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 3)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 4))
-				goto ldst_done;
-			err = 0;
-			__get_user_asmx(val, ea, err, "lwarx");
-			if (!err)
-				regs->gpr[rd] = val;
-			goto ldst_done;
+			op->type = MKOP(LARX, 0, 4);
+			break;
 
 		case 150:	/* stwcx. */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 3)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 4))
-				goto ldst_done;
-			err = 0;
-			__put_user_asmx(regs->gpr[rd], ea, err, "stwcx.", cr);
-			if (!err)
-				regs->ccr = (regs->ccr & 0x0fffffff) |
-					(cr & 0xe0000000) |
-					((regs->xer >> 3) & 0x10000000);
-			goto ldst_done;
+			op->type = MKOP(STCX, 0, 4);
+			break;
 
 #ifdef __powerpc64__
 		case 84:	/* ldarx */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 7)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 8))
-				goto ldst_done;
-			err = 0;
-			__get_user_asmx(val, ea, err, "ldarx");
-			if (!err)
-				regs->gpr[rd] = val;
-			goto ldst_done;
+			op->type = MKOP(LARX, 0, 8);
+			break;
 
 		case 214:	/* stdcx. */
-			ea = xform_ea(instr, regs, 0);
-			if (ea & 7)
-				break;		/* can't handle misaligned */
-			err = -EFAULT;
-			if (!address_ok(regs, ea, 8))
-				goto ldst_done;
-			err = 0;
-			__put_user_asmx(regs->gpr[rd], ea, err, "stdcx.", cr);
-			if (!err)
-				regs->ccr = (regs->ccr & 0x0fffffff) |
-					(cr & 0xe0000000) |
-					((regs->xer >> 3) & 0x10000000);
-			goto ldst_done;
+			op->type = MKOP(STCX, 0, 8);
+			break;
 
 		case 21:	/* ldx */
 		case 53:	/* ldux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       8, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 8);
+			break;
 #endif
 
 		case 23:	/* lwzx */
 		case 55:	/* lwzux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       4, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 4);
+			break;
 
 		case 87:	/* lbzx */
 		case 119:	/* lbzux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       1, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 1);
+			break;
 
 #ifdef CONFIG_ALTIVEC
 		case 103:	/* lvx */
 		case 359:	/* lvxl */
 			if (!(regs->msr & MSR_VEC))
-				break;
-			ea = xform_ea(instr, regs, 0);
-			err = do_vec_load(rd, do_lvx, ea, regs);
-			goto ldst_done;
+				goto vecunavail;
+			op->type = MKOP(LOAD_VMX, 0, 16);
+			break;
 
 		case 231:	/* stvx */
 		case 487:	/* stvxl */
 			if (!(regs->msr & MSR_VEC))
-				break;
-			ea = xform_ea(instr, regs, 0);
-			err = do_vec_store(rd, do_stvx, ea, regs);
-			goto ldst_done;
+				goto vecunavail;
+			op->type = MKOP(STORE_VMX, 0, 16);
+			break;
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef __powerpc64__
 		case 149:	/* stdx */
 		case 181:	/* stdux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 8);
+			break;
 #endif
 
 		case 151:	/* stwx */
 		case 183:	/* stwux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 4, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 4);
+			break;
 
 		case 215:	/* stbx */
 		case 247:	/* stbux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 1, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 1);
+			break;
 
 		case 279:	/* lhzx */
 		case 311:	/* lhzux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       2, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, u, 2);
+			break;
 
 #ifdef __powerpc64__
 		case 341:	/* lwax */
 		case 373:	/* lwaux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       4, regs);
-			if (!err)
-				regs->gpr[rd] = (signed int) regs->gpr[rd];
-			goto ldst_done;
+			op->type = MKOP(LOAD, SIGNEXT | u, 4);
+			break;
 #endif
 
 		case 343:	/* lhax */
 		case 375:	/* lhaux */
-			err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-				       2, regs);
-			if (!err)
-				regs->gpr[rd] = (signed short) regs->gpr[rd];
-			goto ldst_done;
+			op->type = MKOP(LOAD, SIGNEXT | u, 2);
+			break;
 
 		case 407:	/* sthx */
 		case 439:	/* sthux */
-			val = regs->gpr[rd];
-			err = write_mem(val, xform_ea(instr, regs, u), 2, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, u, 2);
+			break;
 
 #ifdef __powerpc64__
 		case 532:	/* ldbrx */
-			err = read_mem(&val, xform_ea(instr, regs, 0), 8, regs);
-			if (!err)
-				regs->gpr[rd] = byterev_8(val);
-			goto ldst_done;
+			op->type = MKOP(LOAD, BYTEREV, 8);
+			break;
 
 #endif
 
 		case 534:	/* lwbrx */
-			err = read_mem(&val, xform_ea(instr, regs, 0), 4, regs);
-			if (!err)
-				regs->gpr[rd] = byterev_4(val);
-			goto ldst_done;
+			op->type = MKOP(LOAD, BYTEREV, 4);
+			break;
 
 #ifdef CONFIG_PPC_FPU
 		case 535:	/* lfsx */
 		case 567:	/* lfsux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_load(rd, do_lfs, ea, 4, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(LOAD_FP, u, 4);
+			break;
 
 		case 599:	/* lfdx */
 		case 631:	/* lfdux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_load(rd, do_lfd, ea, 8, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(LOAD_FP, u, 8);
+			break;
 
 		case 663:	/* stfsx */
 		case 695:	/* stfsux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_store(rd, do_stfs, ea, 4, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(STORE_FP, u, 4);
+			break;
 
 		case 727:	/* stfdx */
 		case 759:	/* stfdux */
 			if (!(regs->msr & MSR_FP))
-				break;
-			ea = xform_ea(instr, regs, u);
-			err = do_fp_store(rd, do_stfd, ea, 8, regs);
-			goto ldst_done;
+				goto fpunavail;
+			op->type = MKOP(STORE_FP, u, 8);
+			break;
 #endif
 
 #ifdef __powerpc64__
 		case 660:	/* stdbrx */
-			val = byterev_8(regs->gpr[rd]);
-			err = write_mem(val, xform_ea(instr, regs, 0), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, BYTEREV, 8);
+			op->val = byterev_8(regs->gpr[rd]);
+			break;
 
 #endif
 		case 662:	/* stwbrx */
-			val = byterev_4(regs->gpr[rd]);
-			err = write_mem(val, xform_ea(instr, regs, 0), 4, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, BYTEREV, 4);
+			op->val = byterev_4(regs->gpr[rd]);
+			break;
 
 		case 790:	/* lhbrx */
-			err = read_mem(&val, xform_ea(instr, regs, 0), 2, regs);
-			if (!err)
-				regs->gpr[rd] = byterev_2(val);
-			goto ldst_done;
+			op->type = MKOP(LOAD, BYTEREV, 2);
+			break;
 
 		case 918:	/* sthbrx */
-			val = byterev_2(regs->gpr[rd]);
-			err = write_mem(val, xform_ea(instr, regs, 0), 2, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, BYTEREV, 2);
+			op->val = byterev_2(regs->gpr[rd]);
+			break;
 
 #ifdef CONFIG_VSX
 		case 844:	/* lxvd2x */
 		case 876:	/* lxvd2ux */
 			if (!(regs->msr & MSR_VSX))
-				break;
-			rd |= (instr & 1) << 5;
-			ea = xform_ea(instr, regs, u);
-			err = do_vsx_load(rd, do_lxvd2x, ea, regs);
-			goto ldst_done;
+				goto vsxunavail;
+			op->reg = rd | ((instr & 1) << 5);
+			op->type = MKOP(LOAD_VSX, u, 16);
+			break;
 
 		case 972:	/* stxvd2x */
 		case 1004:	/* stxvd2ux */
 			if (!(regs->msr & MSR_VSX))
-				break;
-			rd |= (instr & 1) << 5;
-			ea = xform_ea(instr, regs, u);
-			err = do_vsx_store(rd, do_stxvd2x, ea, regs);
-			goto ldst_done;
+				goto vsxunavail;
+			op->reg = rd | ((instr & 1) << 5);
+			op->type = MKOP(STORE_VSX, u, 16);
+			break;
 
 #endif /* CONFIG_VSX */
 		}
@@ -1552,178 +1505,124 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 
 	case 32:	/* lwz */
 	case 33:	/* lwzu */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 4, regs);
-		goto ldst_done;
+		op->type = MKOP(LOAD, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 34:	/* lbz */
 	case 35:	/* lbzu */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 1, regs);
-		goto ldst_done;
+		op->type = MKOP(LOAD, u, 1);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 36:	/* stw */
-		val = regs->gpr[rd];
-		err = write_mem(val, dform_ea(instr, regs), 4, regs);
-		goto ldst_done;
-
 	case 37:	/* stwu */
-		val = regs->gpr[rd];
-		val3 = dform_ea(instr, regs);
-		/*
-		 * For PPC32 we always use stwu to change stack point with r1. So
-		 * this emulated store may corrupt the exception frame, now we
-		 * have to provide the exception frame trampoline, which is pushed
-		 * below the kprobed function stack. So we only update gpr[1] but
-		 * don't emulate the real store operation. We will do real store
-		 * operation safely in exception return code by checking this flag.
-		 */
-		if ((ra = 1) && !(regs->msr & MSR_PR) \
-			&& (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) {
-#ifdef CONFIG_PPC32
-			/*
-			 * Check if we will touch kernel sack overflow
-			 */
-			if (val3 - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) {
-				printk(KERN_CRIT "Can't kprobe this since Kernel stack overflow.\n");
-				err = -EINVAL;
-				break;
-			}
-#endif /* CONFIG_PPC32 */
-			/*
-			 * Check if we already set since that means we'll
-			 * lose the previous value.
-			 */
-			WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
-			set_thread_flag(TIF_EMULATE_STACK_STORE);
-			err = 0;
-		} else
-			err = write_mem(val, val3, 4, regs);
-		goto ldst_done;
+		op->type = MKOP(STORE, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 38:	/* stb */
 	case 39:	/* stbu */
-		val = regs->gpr[rd];
-		err = write_mem(val, dform_ea(instr, regs), 1, regs);
-		goto ldst_done;
+		op->type = MKOP(STORE, u, 1);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 40:	/* lhz */
 	case 41:	/* lhzu */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
-		goto ldst_done;
+		op->type = MKOP(LOAD, u, 2);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 42:	/* lha */
 	case 43:	/* lhau */
-		err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
-		if (!err)
-			regs->gpr[rd] = (signed short) regs->gpr[rd];
-		goto ldst_done;
+		op->type = MKOP(LOAD, SIGNEXT | u, 2);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 44:	/* sth */
 	case 45:	/* sthu */
-		val = regs->gpr[rd];
-		err = write_mem(val, dform_ea(instr, regs), 2, regs);
-		goto ldst_done;
+		op->type = MKOP(STORE, u, 2);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 46:	/* lmw */
 		ra = (instr >> 16) & 0x1f;
 		if (ra >= rd)
 			break;		/* invalid form, ra in range to load */
-		ea = dform_ea(instr, regs);
-		do {
-			err = read_mem(&regs->gpr[rd], ea, 4, regs);
-			if (err)
-				return 0;
-			ea += 4;
-		} while (++rd < 32);
-		goto instr_done;
+		op->type = MKOP(LOAD_MULTI, 0, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 47:	/* stmw */
-		ea = dform_ea(instr, regs);
-		do {
-			err = write_mem(regs->gpr[rd], ea, 4, regs);
-			if (err)
-				return 0;
-			ea += 4;
-		} while (++rd < 32);
-		goto instr_done;
+		op->type = MKOP(STORE_MULTI, 0, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 #ifdef CONFIG_PPC_FPU
 	case 48:	/* lfs */
 	case 49:	/* lfsu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_load(rd, do_lfs, ea, 4, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(LOAD_FP, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 50:	/* lfd */
 	case 51:	/* lfdu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_load(rd, do_lfd, ea, 8, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(LOAD_FP, u, 8);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 52:	/* stfs */
 	case 53:	/* stfsu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_store(rd, do_stfs, ea, 4, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(STORE_FP, u, 4);
+		op->ea = dform_ea(instr, regs);
+		break;
 
 	case 54:	/* stfd */
 	case 55:	/* stfdu */
 		if (!(regs->msr & MSR_FP))
-			break;
-		ea = dform_ea(instr, regs);
-		err = do_fp_store(rd, do_stfd, ea, 8, regs);
-		goto ldst_done;
+			goto fpunavail;
+		op->type = MKOP(STORE_FP, u, 8);
+		op->ea = dform_ea(instr, regs);
+		break;
 #endif
 
 #ifdef __powerpc64__
 	case 58:	/* ld[u], lwa */
+		op->ea = dsform_ea(instr, regs);
 		switch (instr & 3) {
 		case 0:		/* ld */
-			err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-				       8, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, 0, 8);
+			break;
 		case 1:		/* ldu */
-			err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-				       8, regs);
-			goto ldst_done;
+			op->type = MKOP(LOAD, UPDATE, 8);
+			break;
 		case 2:		/* lwa */
-			err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-				       4, regs);
-			if (!err)
-				regs->gpr[rd] = (signed int) regs->gpr[rd];
-			goto ldst_done;
+			op->type = MKOP(LOAD, SIGNEXT, 4);
+			break;
 		}
 		break;
 
 	case 62:	/* std[u] */
-		val = regs->gpr[rd];
+		op->ea = dsform_ea(instr, regs);
 		switch (instr & 3) {
 		case 0:		/* std */
-			err = write_mem(val, dsform_ea(instr, regs), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, 0, 8);
+			break;
 		case 1:		/* stdu */
-			err = write_mem(val, dsform_ea(instr, regs), 8, regs);
-			goto ldst_done;
+			op->type = MKOP(STORE, UPDATE, 8);
+			break;
 		}
 		break;
 #endif /* __powerpc64__ */
 
 	}
-	err = -EINVAL;
-
- ldst_done:
-	if (err) {
-		regs->gpr[ra] = old_ra;
-		return 0;	/* invoke DSI if -EFAULT? */
-	}
- instr_done:
-	regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
-	return 1;
+	return 0;
 
  logical_done:
 	if (instr & 1)
@@ -1733,5 +1632,327 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
  arith_done:
 	if (instr & 1)
 		set_cr0(regs, rd);
-	goto instr_done;
+
+ instr_done:
+	regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
+	return 1;
+
+ priv:
+	op->type = INTERRUPT | 0x700;
+	op->val = SRR1_PROGPRIV;
+	return 0;
+
+ trap:
+	op->type = INTERRUPT | 0x700;
+	op->val = SRR1_PROGTRAP;
+	return 0;
+
+#ifdef CONFIG_PPC_FPU
+ fpunavail:
+	op->type = INTERRUPT | 0x800;
+	return 0;
+#endif
+
+#ifdef CONFIG_ALTIVEC
+ vecunavail:
+	op->type = INTERRUPT | 0xf20;
+	return 0;
+#endif
+
+#ifdef CONFIG_VSX
+ vsxunavail:
+	op->type = INTERRUPT | 0xf40;
+	return 0;
+#endif
+}
+EXPORT_SYMBOL_GPL(analyse_instr);
+
+/*
+ * For PPC32 we always use stwu with r1 to change the stack pointer.
+ * So this emulated store may corrupt the exception frame, now we
+ * have to provide the exception frame trampoline, which is pushed
+ * below the kprobed function stack. So we only update gpr[1] but
+ * don't emulate the real store operation. We will do real store
+ * operation safely in exception return code by checking this flag.
+ */
+static __kprobes int handle_stack_update(unsigned long ea, struct pt_regs *regs)
+{
+#ifdef CONFIG_PPC32
+	/*
+	 * Check if we will touch kernel stack overflow
+	 */
+	if (ea - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) {
+		printk(KERN_CRIT "Can't kprobe this since Kernel stack overflow.\n");
+		return -EINVAL;
+	}
+#endif /* CONFIG_PPC32 */
+	/*
+	 * Check if we already set since that means we'll
+	 * lose the previous value.
+	 */
+	WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
+	set_thread_flag(TIF_EMULATE_STACK_STORE);
+	return 0;
+}
+
+static __kprobes void do_signext(unsigned long *valp, int size)
+{
+	switch (size) {
+	case 2:
+		*valp = (signed short) *valp;
+		break;
+	case 4:
+		*valp = (signed int) *valp;
+		break;
+	}
+}
+
+static __kprobes void do_byterev(unsigned long *valp, int size)
+{
+	switch (size) {
+	case 2:
+		*valp = byterev_2(*valp);
+		break;
+	case 4:
+		*valp = byterev_4(*valp);
+		break;
+	case 8:
+		*valp = byterev_8(*valp);
+		break;
+	}
+}
+
+/*
+ * Emulate instructions that cause a transfer of control,
+ * loads and stores, and a few other instructions.
+ * Returns 1 if the step was emulated, 0 if not,
+ * or -1 if the instruction is one that should not be stepped,
+ * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ */
+int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
+{
+	struct instruction_op op;
+	int r, err, size;
+	unsigned long val;
+	unsigned int cr;
+	int rd;
+
+	r = analyse_instr(&op, regs, instr);
+	if (r != 0)
+		return r;
+
+	err = 0;
+	size = GETSIZE(op.type);
+	switch (op.type & INSTR_TYPE_MASK) {
+	case CACHEOP:
+		if (!address_ok(regs, op.ea, 8))
+			return 0;
+		switch (op.type & CACHEOP_MASK) {
+		case DCBST:
+			__cacheop_user_asmx(op.ea, err, "dcbst");
+			break;
+		case DCBF:
+			__cacheop_user_asmx(op.ea, err, "dcbf");
+			break;
+		case DCBTST:
+			if (op.reg = 0)
+				prefetchw((void *) op.ea);
+			break;
+		case DCBT:
+			if (op.reg = 0)
+				prefetch((void *) op.ea);
+			break;
+		}
+		if (err)
+			return 0;
+		goto instr_done;
+
+	case LARX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (op.ea & (size - 1))
+			break;		/* can't handle misaligned */
+		err = -EFAULT;
+		if (!address_ok(regs, op.ea, size))
+			goto ldst_done;
+		err = 0;
+		switch (size) {
+		case 4:
+			__get_user_asmx(val, op.ea, err, "lwarx");
+			break;
+		case 8:
+			__get_user_asmx(val, op.ea, err, "ldarx");
+			break;
+		default:
+			return 0;
+		}
+		if (!err)
+			regs->gpr[op.reg] = val;
+		goto ldst_done;
+
+	case STCX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (op.ea & (size - 1))
+			break;		/* can't handle misaligned */
+		err = -EFAULT;
+		if (!address_ok(regs, op.ea, size))
+			goto ldst_done;
+		err = 0;
+		switch (size) {
+		case 4:
+			__put_user_asmx(op.val, op.ea, err, "stwcx.", cr);
+			break;
+		case 8:
+			__put_user_asmx(op.val, op.ea, err, "stdcx.", cr);
+			break;
+		default:
+			return 0;
+		}
+		if (!err)
+			regs->ccr = (regs->ccr & 0x0fffffff) |
+				(cr & 0xe0000000) |
+				((regs->xer >> 3) & 0x10000000);
+		goto ldst_done;
+
+	case LOAD:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = read_mem(&regs->gpr[op.reg], op.ea, size, regs);
+		if (!err) {
+			if (op.type & SIGNEXT)
+				do_signext(&regs->gpr[op.reg], size);
+			if (op.type & BYTEREV)
+				do_byterev(&regs->gpr[op.reg], size);
+		}
+		goto ldst_done;
+
+	case LOAD_FP:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (size = 4)
+			err = do_fp_load(op.reg, do_lfs, op.ea, size, regs);
+		else
+			err = do_fp_load(op.reg, do_lfd, op.ea, size, regs);
+		goto ldst_done;
+
+	case LOAD_VMX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vec_load(op.reg, do_lvx, op.ea & ~0xfUL, regs);
+		goto ldst_done;
+
+	case LOAD_VSX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vsx_load(op.reg, do_lxvd2x, op.ea, regs);
+		goto ldst_done;
+
+	case LOAD_MULTI:
+		if (regs->msr & MSR_LE)
+			return 0;
+		rd = op.reg;
+		do {
+			err = read_mem(&regs->gpr[rd], op.ea, 4, regs);
+			if (err)
+				return 0;
+			op.ea += 4;
+		} while (++rd < 32);
+		goto instr_done;
+
+	case STORE:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if ((op.type & UPDATE) && size = sizeof(long) &&
+		    op.reg = 1 && op.update_reg = 1 &&
+		    !(regs->msr & MSR_PR) &&
+		    op.ea >= regs->gpr[1] - STACK_INT_FRAME_SIZE) {
+			err = handle_stack_update(op.ea, regs);
+			goto ldst_done;
+		}
+		err = write_mem(op.val, op.ea, size, regs);
+		goto ldst_done;
+
+	case STORE_FP:
+		if (regs->msr & MSR_LE)
+			return 0;
+		if (size = 4)
+			err = do_fp_store(op.reg, do_stfs, op.ea, size, regs);
+		else
+			err = do_fp_store(op.reg, do_stfd, op.ea, size, regs);
+		goto ldst_done;
+
+	case STORE_VMX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vec_store(op.reg, do_stvx, op.ea & ~0xfUL, regs);
+		goto ldst_done;
+
+	case STORE_VSX:
+		if (regs->msr & MSR_LE)
+			return 0;
+		err = do_vsx_store(op.reg, do_stxvd2x, op.ea, regs);
+		goto ldst_done;
+
+	case STORE_MULTI:
+		if (regs->msr & MSR_LE)
+			return 0;
+		rd = op.reg;
+		do {
+			err = write_mem(regs->gpr[rd], op.ea, 4, regs);
+			if (err)
+				return 0;
+			op.ea += 4;
+		} while (++rd < 32);
+		goto instr_done;
+
+	case MFMSR:
+		regs->gpr[op.reg] = regs->msr & MSR_MASK;
+		goto instr_done;
+
+	case MTMSR:
+		val = regs->gpr[op.reg];
+		if ((val & MSR_RI) = 0)
+			/* can't step mtmsr[d] that would clear MSR_RI */
+			return -1;
+		/* here op.val is the mask of bits to change */
+		regs->msr = (regs->msr & ~op.val) | (val & op.val);
+		goto instr_done;
+
+#ifdef CONFIG_PPC64
+	case SYSCALL:	/* sc */
+		/*
+		 * N.B. this uses knowledge about how the syscall
+		 * entry code works.  If that is changed, this will
+		 * need to be changed also.
+		 */
+		if (regs->gpr[0] = 0x1ebe &&
+		    cpu_has_feature(CPU_FTR_REAL_LE)) {
+			regs->msr ^= MSR_LE;
+			goto instr_done;
+		}
+		regs->gpr[9] = regs->gpr[13];
+		regs->gpr[10] = MSR_KERNEL;
+		regs->gpr[11] = regs->nip + 4;
+		regs->gpr[12] = regs->msr & MSR_MASK;
+		regs->gpr[13] = (unsigned long) get_paca();
+		regs->nip = (unsigned long) &system_call_common;
+		regs->msr = MSR_KERNEL;
+		return 1;
+
+	case RFI:
+		return -1;
+#endif
+	}
+	return 0;
+
+ ldst_done:
+	if (err)
+		return 0;
+	if (op.type & UPDATE)
+		regs->gpr[op.update_reg] = op.ea;
+
+ instr_done:
+	regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
+	return 1;
 }
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 2/5] powerpc: Implement emulation of string loads and stores
  2014-07-19 10:14 ` Paul Mackerras
@ 2014-07-19 10:14   ` Paul Mackerras
  -1 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

The size field of the op.type word is now the total number of bytes
to be loaded or stored.

Also implement mcrf.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/lib/sstep.c | 66 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 56 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 7a54df2..bb9ee7b 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -686,6 +686,13 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		return 1;
 	case 19:
 		switch ((instr >> 1) & 0x3ff) {
+		case 0:		/* mcrf */
+			rd = (instr >> 21) & 0x1c;
+			ra = (instr >> 16) & 0x1c;
+			val = (regs->ccr >> ra) & 0xf;
+			regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
+			goto instr_done;
+
 		case 16:	/* bclr */
 		case 528:	/* bcctr */
 			op->type = BRANCH;
@@ -1426,11 +1433,24 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			break;
 
 #endif
+		case 533:	/* lswx */
+			op->type = MKOP(LOAD_MULTI, 0, regs->xer & 0x7f);
+			break;
 
 		case 534:	/* lwbrx */
 			op->type = MKOP(LOAD, BYTEREV, 4);
 			break;
 
+		case 597:	/* lswi */
+			if (rb == 0)
+				rb = 32;	/* # bytes to load */
+			op->type = MKOP(LOAD_MULTI, 0, rb);
+			op->ea = 0;
+			if (ra)
+				op->ea = truncate_if_32bit(regs->msr,
+							   regs->gpr[ra]);
+			break;
+
 #ifdef CONFIG_PPC_FPU
 		case 535:	/* lfsx */
 		case 567:	/* lfsux */
@@ -1468,11 +1488,25 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			break;
 
 #endif
+		case 661:	/* stswx */
+			op->type = MKOP(STORE_MULTI, 0, regs->xer & 0x7f);
+			break;
+
 		case 662:	/* stwbrx */
 			op->type = MKOP(STORE, BYTEREV, 4);
 			op->val = byterev_4(regs->gpr[rd]);
 			break;
 
+		case 725:
+			if (rb == 0)
+				rb = 32;	/* # bytes to store */
+			op->type = MKOP(STORE_MULTI, 0, rb);
+			op->ea = 0;
+			if (ra)
+				op->ea = truncate_if_32bit(regs->msr,
+							   regs->gpr[ra]);
+			break;
+
 		case 790:	/* lhbrx */
 			op->type = MKOP(LOAD, BYTEREV, 2);
 			break;
@@ -1546,15 +1580,14 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		break;
 
 	case 46:	/* lmw */
-		ra = (instr >> 16) & 0x1f;
 		if (ra >= rd)
 			break;		/* invalid form, ra in range to load */
-		op->type = MKOP(LOAD_MULTI, 0, 4);
+		op->type = MKOP(LOAD_MULTI, 0, 4 * (32 - rd));
 		op->ea = dform_ea(instr, regs);
 		break;
 
 	case 47:	/* stmw */
-		op->type = MKOP(STORE_MULTI, 0, 4);
+		op->type = MKOP(STORE_MULTI, 0, 4 * (32 - rd));
 		op->ea = dform_ea(instr, regs);
 		break;
 
@@ -1735,7 +1768,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 	int r, err, size;
 	unsigned long val;
 	unsigned int cr;
-	int rd;
+	int i, rd, nb;
 
 	r = analyse_instr(&op, regs, instr);
 	if (r != 0)
@@ -1852,12 +1885,18 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		if (regs->msr & MSR_LE)
 			return 0;
 		rd = op.reg;
-		do {
-			err = read_mem(&regs->gpr[rd], op.ea, 4, regs);
+		for (i = 0; i < size; i += 4) {
+			nb = size - i;
+			if (nb > 4)
+				nb = 4;
+			err = read_mem(&regs->gpr[rd], op.ea, nb, regs);
 			if (err)
 				return 0;
+			if (nb < 4)	/* left-justify last bytes */
+				regs->gpr[rd] <<= 32 - 8 * nb;
 			op.ea += 4;
-		} while (++rd < 32);
+			++rd;
+		}
 		goto instr_done;
 
 	case STORE:
@@ -1898,12 +1937,19 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		if (regs->msr & MSR_LE)
 			return 0;
 		rd = op.reg;
-		do {
-			err = write_mem(regs->gpr[rd], op.ea, 4, regs);
+		for (i = 0; i < size; i += 4) {
+			val = regs->gpr[rd];
+			nb = size - i;
+			if (nb > 4)
+				nb = 4;
+			else
+				val >>= 32 - 8 * nb;
+			err = write_mem(val, op.ea, nb, regs);
 			if (err)
 				return 0;
 			op.ea += 4;
-		} while (++rd < 32);
+			++rd;
+		}
 		goto instr_done;
 
 	case MFMSR:
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 2/5] powerpc: Implement emulation of string loads and stores
@ 2014-07-19 10:14   ` Paul Mackerras
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

The size field of the op.type word is now the total number of bytes
to be loaded or stored.

Also implement mcrf.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/lib/sstep.c | 66 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 56 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 7a54df2..bb9ee7b 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -686,6 +686,13 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		return 1;
 	case 19:
 		switch ((instr >> 1) & 0x3ff) {
+		case 0:		/* mcrf */
+			rd = (instr >> 21) & 0x1c;
+			ra = (instr >> 16) & 0x1c;
+			val = (regs->ccr >> ra) & 0xf;
+			regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
+			goto instr_done;
+
 		case 16:	/* bclr */
 		case 528:	/* bcctr */
 			op->type = BRANCH;
@@ -1426,11 +1433,24 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			break;
 
 #endif
+		case 533:	/* lswx */
+			op->type = MKOP(LOAD_MULTI, 0, regs->xer & 0x7f);
+			break;
 
 		case 534:	/* lwbrx */
 			op->type = MKOP(LOAD, BYTEREV, 4);
 			break;
 
+		case 597:	/* lswi */
+			if (rb = 0)
+				rb = 32;	/* # bytes to load */
+			op->type = MKOP(LOAD_MULTI, 0, rb);
+			op->ea = 0;
+			if (ra)
+				op->ea = truncate_if_32bit(regs->msr,
+							   regs->gpr[ra]);
+			break;
+
 #ifdef CONFIG_PPC_FPU
 		case 535:	/* lfsx */
 		case 567:	/* lfsux */
@@ -1468,11 +1488,25 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 			break;
 
 #endif
+		case 661:	/* stswx */
+			op->type = MKOP(STORE_MULTI, 0, regs->xer & 0x7f);
+			break;
+
 		case 662:	/* stwbrx */
 			op->type = MKOP(STORE, BYTEREV, 4);
 			op->val = byterev_4(regs->gpr[rd]);
 			break;
 
+		case 725:
+			if (rb = 0)
+				rb = 32;	/* # bytes to store */
+			op->type = MKOP(STORE_MULTI, 0, rb);
+			op->ea = 0;
+			if (ra)
+				op->ea = truncate_if_32bit(regs->msr,
+							   regs->gpr[ra]);
+			break;
+
 		case 790:	/* lhbrx */
 			op->type = MKOP(LOAD, BYTEREV, 2);
 			break;
@@ -1546,15 +1580,14 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
 		break;
 
 	case 46:	/* lmw */
-		ra = (instr >> 16) & 0x1f;
 		if (ra >= rd)
 			break;		/* invalid form, ra in range to load */
-		op->type = MKOP(LOAD_MULTI, 0, 4);
+		op->type = MKOP(LOAD_MULTI, 0, 4 * (32 - rd));
 		op->ea = dform_ea(instr, regs);
 		break;
 
 	case 47:	/* stmw */
-		op->type = MKOP(STORE_MULTI, 0, 4);
+		op->type = MKOP(STORE_MULTI, 0, 4 * (32 - rd));
 		op->ea = dform_ea(instr, regs);
 		break;
 
@@ -1735,7 +1768,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 	int r, err, size;
 	unsigned long val;
 	unsigned int cr;
-	int rd;
+	int i, rd, nb;
 
 	r = analyse_instr(&op, regs, instr);
 	if (r != 0)
@@ -1852,12 +1885,18 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		if (regs->msr & MSR_LE)
 			return 0;
 		rd = op.reg;
-		do {
-			err = read_mem(&regs->gpr[rd], op.ea, 4, regs);
+		for (i = 0; i < size; i += 4) {
+			nb = size - i;
+			if (nb > 4)
+				nb = 4;
+			err = read_mem(&regs->gpr[rd], op.ea, nb, regs);
 			if (err)
 				return 0;
+			if (nb < 4)	/* left-justify last bytes */
+				regs->gpr[rd] <<= 32 - 8 * nb;
 			op.ea += 4;
-		} while (++rd < 32);
+			++rd;
+		}
 		goto instr_done;
 
 	case STORE:
@@ -1898,12 +1937,19 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 		if (regs->msr & MSR_LE)
 			return 0;
 		rd = op.reg;
-		do {
-			err = write_mem(regs->gpr[rd], op.ea, 4, regs);
+		for (i = 0; i < size; i += 4) {
+			val = regs->gpr[rd];
+			nb = size - i;
+			if (nb > 4)
+				nb = 4;
+			else
+				val >>= 32 - 8 * nb;
+			err = write_mem(val, op.ea, nb, regs);
 			if (err)
 				return 0;
 			op.ea += 4;
-		} while (++rd < 32);
+			++rd;
+		}
 		goto instr_done;
 
 	case MFMSR:
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 3/5] KVM: PPC: Use pt_regs struct for integer registers in struct vcpu_arch
  2014-07-19 10:14 ` Paul Mackerras
@ 2014-07-19 10:14   ` Paul Mackerras
  -1 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This replaces the gpr, pc, ctr, lr, xer, cr and trap fields in the
struct vcpu_arch with a regs field, which is a struct pt_regs.
Similarly, it replaces gpr_tm, cr_tm, lr_tm, and ctr_tm with a
regs_tm field.  This then necessitates changes to the accessors
in kvm_book3s.h and kvm_booke.h, and changes to the KVM code where
it was not using the accessors.  Those places have either been
changed to use the accessors, or to access the fields using the
new names.

The reason for doing this is to make it possible to exploit more
of the non-KVM powerpc code in the kernel, thus reducing code
duplication.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/kvm_book3s.h | 24 +++++------
 arch/powerpc/include/asm/kvm_booke.h  | 24 +++++------
 arch/powerpc/include/asm/kvm_host.h   | 20 ++-------
 arch/powerpc/kernel/asm-offsets.c     | 32 +++++++--------
 arch/powerpc/kvm/book3s_32_mmu.c      |  2 +-
 arch/powerpc/kvm/book3s_64_mmu_hv.c   |  2 +-
 arch/powerpc/kvm/book3s_64_vio_hv.c   |  2 +-
 arch/powerpc/kvm/book3s_hv.c          | 42 ++++++++++---------
 arch/powerpc/kvm/book3s_hv_rm_mmu.c   | 10 ++---
 arch/powerpc/kvm/book3s_hv_rm_xics.c  |  2 +-
 arch/powerpc/kvm/book3s_pr.c          | 76 +++++++++++++++++------------------
 arch/powerpc/kvm/booke.c              | 36 +++++++++--------
 arch/powerpc/kvm/booke_emulate.c      |  4 +-
 arch/powerpc/kvm/e500_mmu.c           |  2 +-
 14 files changed, 134 insertions(+), 144 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 20fb6f2..b27cad8 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -212,62 +212,62 @@ static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
-	vcpu->arch.gpr[num] = val;
+	vcpu->arch.regs.gpr[num] = val;
 }
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-	return vcpu->arch.gpr[num];
+	return vcpu->arch.regs.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.cr = val;
+	vcpu->arch.regs.ccr = val;
 }
 
 static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.cr;
+	return vcpu->arch.regs.ccr;
 }
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.xer = val;
+	vcpu->arch.regs.xer = val;
 }
 
 static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.xer;
+	return vcpu->arch.regs.xer;
 }
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.ctr = val;
+	vcpu->arch.regs.ctr = val;
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.ctr;
+	return vcpu->arch.regs.ctr;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.lr = val;
+	vcpu->arch.regs.link = val;
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.lr;
+	return vcpu->arch.regs.link;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.pc = val;
+	vcpu->arch.regs.nip = val;
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.pc;
+	return vcpu->arch.regs.nip;
 }
 
 static inline u64 kvmppc_get_msr(struct kvm_vcpu *vcpu);
diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/include/asm/kvm_booke.h
index c7aed61..3274d63 100644
--- a/arch/powerpc/include/asm/kvm_booke.h
+++ b/arch/powerpc/include/asm/kvm_booke.h
@@ -35,32 +35,32 @@
 
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
-	vcpu->arch.gpr[num] = val;
+	vcpu->arch.regs.gpr[num] = val;
 }
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-	return vcpu->arch.gpr[num];
+	return vcpu->arch.regs.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.cr = val;
+	vcpu->arch.regs.ccr = val;
 }
 
 static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.cr;
+	return vcpu->arch.regs.ccr;
 }
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.xer = val;
+	vcpu->arch.regs.xer = val;
 }
 
 static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.xer;
+	return vcpu->arch.regs.xer;
 }
 
 static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
@@ -76,32 +76,32 @@ static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.ctr = val;
+	vcpu->arch.regs.ctr = val;
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.ctr;
+	return vcpu->arch.regs.ctr;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.lr = val;
+	vcpu->arch.regs.link = val;
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.lr;
+	return vcpu->arch.regs.link;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.pc = val;
+	vcpu->arch.regs.nip = val;
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.pc;
+	return vcpu->arch.regs.nip;
 }
 
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 855ba4d..0f3ac93 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -35,6 +35,7 @@
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 #include <asm/hvcall.h>
+#include <asm/ptrace.h>
 
 #define KVM_MAX_VCPUS		NR_CPUS
 #define KVM_MAX_VCORES		NR_CPUS
@@ -416,7 +417,7 @@ struct kvm_vcpu_arch {
 	struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
 #endif
 
-	ulong gpr[32];
+	struct pt_regs regs;
 
 	struct thread_fp_state fp;
 
@@ -449,19 +450,8 @@ struct kvm_vcpu_arch {
 #ifdef CONFIG_PPC_BOOK3S
 	/* For Gekko paired singles */
 	u32 qpr[32];
-#endif
 
-	ulong pc;
-	ulong ctr;
-	ulong lr;
-#ifdef CONFIG_PPC_BOOK3S
 	ulong tar;
-#endif
-
-	ulong xer;
-	u32 cr;
-
-#ifdef CONFIG_PPC_BOOK3S
 	ulong hflags;
 	ulong guest_owned_ext;
 	ulong purr;
@@ -538,15 +528,12 @@ struct kvm_vcpu_arch {
 	u64 texasr;
 	u64 tfiar;
 
-	u32 cr_tm;
-	u64 lr_tm;
-	u64 ctr_tm;
 	u64 amr_tm;
 	u64 ppr_tm;
 	u64 dscr_tm;
 	u64 tar_tm;
 
-	ulong gpr_tm[32];
+	struct pt_regs regs_tm;
 
 	struct thread_fp_state fp_tm;
 
@@ -627,7 +614,6 @@ struct kvm_vcpu_arch {
 	wait_queue_head_t *wqp;
 	struct kvmppc_vcore *vcore;
 	int ret;
-	int trap;
 	int state;
 	int ptid;
 	bool timer_running;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 17ffcb4..f5a154c 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -438,20 +438,20 @@ int main(void)
 	DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
 	DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
 	DEFINE(VCPU_GUEST_PID, offsetof(struct kvm_vcpu, arch.pid));
-	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
+	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.regs.gpr));
 	DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave));
 	DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fp.fpr));
 #ifdef CONFIG_ALTIVEC
 	DEFINE(VCPU_VRS, offsetof(struct kvm_vcpu, arch.vr.vr));
 #endif
-	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
-	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
-	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
+	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.regs.xer));
+	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.regs.ctr));
+	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.regs.link));
 #ifdef CONFIG_PPC_BOOK3S
 	DEFINE(VCPU_TAR, offsetof(struct kvm_vcpu, arch.tar));
 #endif
-	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
-	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
+	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.regs.ccr));
+	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.nip));
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 	DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.shregs.msr));
 	DEFINE(VCPU_SRR0, offsetof(struct kvm_vcpu, arch.shregs.srr0));
@@ -537,7 +537,7 @@ int main(void)
 	DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
 	DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
 	DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
-	DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
+	DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.regs.trap));
 	DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
 	DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr));
 	DEFINE(VCPU_FSCR, offsetof(struct kvm_vcpu, arch.fscr));
@@ -568,13 +568,13 @@ int main(void)
 	DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar));
 	DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar));
 	DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr));
-	DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.gpr_tm));
+	DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.gpr));
 	DEFINE(VCPU_FPRS_TM, offsetof(struct kvm_vcpu, arch.fp_tm.fpr));
 	DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
 	DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
-	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm));
-	DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
-	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
+	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.ccr));
+	DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.link));
+	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.ctr));
 	DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
 	DEFINE(VCPU_PPR_TM, offsetof(struct kvm_vcpu, arch.ppr_tm));
 	DEFINE(VCPU_DSCR_TM, offsetof(struct kvm_vcpu, arch.dscr_tm));
@@ -663,11 +663,11 @@ int main(void)
 #endif /* CONFIG_PPC_BOOK3S_64 */
 
 #else /* CONFIG_PPC_BOOK3S */
-	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
-	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
-	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
-	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
-	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
+	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.regs.ccr));
+	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.regs.xer));
+	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.regs.link));
+	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.regs.ctr));
+	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.nip));
 	DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
 	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c
index cd0b073..4eeb248 100644
--- a/arch/powerpc/kvm/book3s_32_mmu.c
+++ b/arch/powerpc/kvm/book3s_32_mmu.c
@@ -52,7 +52,7 @@
 static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
 {
 #ifdef DEBUG_MMU_PTE_IP
-	return vcpu->arch.pc == DEBUG_MMU_PTE_IP;
+	return kvmppc_get_pc(vcpu) == DEBUG_MMU_PTE_IP;
 #else
 	return true;
 #endif
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 2d154d9..b0c2514 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -409,7 +409,7 @@ long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 			     unsigned long ptel)
 {
 	return kvmppc_virtmode_do_h_enter(vcpu->kvm, flags, pte_index,
-					  pteh, ptel, &vcpu->arch.gpr[4]);
+					  pteh, ptel, &vcpu->arch.regs.gpr[4]);
 }
 
 static struct kvmppc_slb *kvmppc_mmu_book3s_hv_find_slbe(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index 89e96b3..bfcad1b 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -94,7 +94,7 @@ long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 			page = stt->pages[idx / TCES_PER_PAGE];
 			tbl = (u64 *)page_address(page);
 
-			vcpu->arch.gpr[4] = tbl[idx % TCES_PER_PAGE];
+			vcpu->arch.regs.gpr[4] = tbl[idx % TCES_PER_PAGE];
 			return H_SUCCESS;
 		}
 	}
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 0c5266e..74e110f 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -225,22 +225,24 @@ void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
 	int r;
 
 	pr_err("vcpu %p (%d):\n", vcpu, vcpu->vcpu_id);
-	pr_err("pc  = %.16lx  msr = %.16llx  trap = %x\n",
-	       vcpu->arch.pc, vcpu->arch.shregs.msr, vcpu->arch.trap);
+	pr_err("pc  = %.16lx  msr = %.16llx  trap = %lx\n",
+	       kvmppc_get_pc(vcpu), vcpu->arch.shregs.msr,
+	       vcpu->arch.regs.trap);
 	for (r = 0; r < 16; ++r)
 		pr_err("r%2d = %.16lx  r%d = %.16lx\n",
 		       r, kvmppc_get_gpr(vcpu, r),
 		       r+16, kvmppc_get_gpr(vcpu, r+16));
 	pr_err("ctr = %.16lx  lr  = %.16lx\n",
-	       vcpu->arch.ctr, vcpu->arch.lr);
+	       kvmppc_get_ctr(vcpu), kvmppc_get_lr(vcpu));
 	pr_err("srr0 = %.16llx srr1 = %.16llx\n",
 	       vcpu->arch.shregs.srr0, vcpu->arch.shregs.srr1);
 	pr_err("sprg0 = %.16llx sprg1 = %.16llx\n",
 	       vcpu->arch.shregs.sprg0, vcpu->arch.shregs.sprg1);
 	pr_err("sprg2 = %.16llx sprg3 = %.16llx\n",
 	       vcpu->arch.shregs.sprg2, vcpu->arch.shregs.sprg3);
-	pr_err("cr = %.8x  xer = %.16lx  dsisr = %.8x\n",
-	       vcpu->arch.cr, vcpu->arch.xer, vcpu->arch.shregs.dsisr);
+	pr_err("cr = %.8x  xer = %.8x  dsisr = %.8x\n",
+	       kvmppc_get_cr(vcpu), kvmppc_get_xer(vcpu),
+	       vcpu->arch.shregs.dsisr);
 	pr_err("dar = %.16llx\n", vcpu->arch.shregs.dar);
 	pr_err("fault dar = %.16lx dsisr = %.8x\n",
 	       vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
@@ -726,7 +728,7 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	run->ready_for_interrupt_injection = 1;
-	switch (vcpu->arch.trap) {
+	switch (vcpu->arch.regs.trap) {
 	/* We're good on these - the host merely wanted to get our attention */
 	case BOOK3S_INTERRUPT_HV_DECREMENTER:
 		vcpu->stat.dec_exits++;
@@ -817,10 +819,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		break;
 	default:
 		kvmppc_dump_regs(vcpu);
-		printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n",
-			vcpu->arch.trap, kvmppc_get_pc(vcpu),
+		printk(KERN_EMERG "trap=0x%lx | pc=0x%lx | msr=0x%llx\n",
+			vcpu->arch.regs.trap, kvmppc_get_pc(vcpu),
 			vcpu->arch.shregs.msr);
-		run->hw.hardware_exit_reason = vcpu->arch.trap;
+		run->hw.hardware_exit_reason = vcpu->arch.regs.trap;
 		r = RESUME_HOST;
 		break;
 	}
@@ -1034,7 +1036,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
 		i = id - KVM_REG_PPC_TM_GPR0;
-		*val = get_reg_val(id, vcpu->arch.gpr_tm[i]);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.gpr[i]);
 		break;
 	case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
 	{
@@ -1052,13 +1054,13 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	}
 	case KVM_REG_PPC_TM_CR:
-		*val = get_reg_val(id, vcpu->arch.cr_tm);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.ccr);
 		break;
 	case KVM_REG_PPC_TM_LR:
-		*val = get_reg_val(id, vcpu->arch.lr_tm);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.link);
 		break;
 	case KVM_REG_PPC_TM_CTR:
-		*val = get_reg_val(id, vcpu->arch.ctr_tm);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.ctr);
 		break;
 	case KVM_REG_PPC_TM_FPSCR:
 		*val = get_reg_val(id, vcpu->arch.fp_tm.fpscr);
@@ -1242,7 +1244,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
 		i = id - KVM_REG_PPC_TM_GPR0;
-		vcpu->arch.gpr_tm[i] = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.gpr[i] = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
 	{
@@ -1259,13 +1261,13 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	}
 	case KVM_REG_PPC_TM_CR:
-		vcpu->arch.cr_tm = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.ccr = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_LR:
-		vcpu->arch.lr_tm = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.ccr = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_CTR:
-		vcpu->arch.ctr_tm = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.ctr = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_FPSCR:
 		vcpu->arch.fp_tm.fpscr = set_reg_val(id, *val);
@@ -1685,12 +1687,12 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
 			kvmppc_core_dequeue_dec(vcpu);
 
 		ret = RESUME_GUEST;
-		if (vcpu->arch.trap)
+		if (vcpu->arch.regs.trap)
 			ret = kvmppc_handle_exit_hv(vcpu->arch.kvm_run, vcpu,
 						    vcpu->arch.run_task);
 
 		vcpu->arch.ret = ret;
-		vcpu->arch.trap = 0;
+		vcpu->arch.regs.trap = 0;
 
 		if (vcpu->arch.ceded) {
 			if (!is_kvmppc_resume_guest(ret))
@@ -1750,7 +1752,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 	kvm_run->exit_reason = 0;
 	vcpu->arch.ret = RESUME_GUEST;
-	vcpu->arch.trap = 0;
+	vcpu->arch.regs.trap = 0;
 	kvmppc_update_vpas(vcpu);
 
 	/*
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index e5c6063..b424499 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -368,7 +368,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 		    long pte_index, unsigned long pteh, unsigned long ptel)
 {
 	return kvmppc_do_h_enter(vcpu->kvm, flags, pte_index, pteh, ptel,
-				 vcpu->arch.pgdir, true, &vcpu->arch.gpr[4]);
+				 vcpu->arch.pgdir, true, &vcpu->arch.regs.gpr[4]);
 }
 
 #ifdef __BIG_ENDIAN__
@@ -517,13 +517,13 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
 		     unsigned long pte_index, unsigned long avpn)
 {
 	return kvmppc_do_h_remove(vcpu->kvm, flags, pte_index, avpn,
-				  &vcpu->arch.gpr[4]);
+				  &vcpu->arch.regs.gpr[4]);
 }
 
 long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long *args = &vcpu->arch.gpr[4];
+	unsigned long *args = &vcpu->arch.regs.gpr[4];
 	__be64 *hp, *hptes[4];
 	unsigned long tlbrb[4];
 	long int i, j, k, n, found, indexes[4];
@@ -733,8 +733,8 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
 			r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C));
 			r &= ~HPTE_GR_RESERVED;
 		}
-		vcpu->arch.gpr[4 + i * 2] = v;
-		vcpu->arch.gpr[5 + i * 2] = r;
+		kvmppc_set_gpr(vcpu, 4 + i * 2, v);
+		kvmppc_set_gpr(vcpu, 5 + i * 2, r);
 	}
 	return H_SUCCESS;
 }
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
index b4b0082..80a6948 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -221,7 +221,7 @@ unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu)
 	} while (!icp_rm_try_update(icp, old_state, new_state));
 
 	/* Return the result in GPR4 */
-	vcpu->arch.gpr[4] = xirr;
+	kvmppc_set_gpr(vcpu, 4, xirr);
 
 	return check_too_hard(xics, icp);
 }
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 84c7a47..29906af 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -145,25 +145,25 @@ static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
 void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu,
 			  struct kvm_vcpu *vcpu)
 {
-	svcpu->gpr[0] = vcpu->arch.gpr[0];
-	svcpu->gpr[1] = vcpu->arch.gpr[1];
-	svcpu->gpr[2] = vcpu->arch.gpr[2];
-	svcpu->gpr[3] = vcpu->arch.gpr[3];
-	svcpu->gpr[4] = vcpu->arch.gpr[4];
-	svcpu->gpr[5] = vcpu->arch.gpr[5];
-	svcpu->gpr[6] = vcpu->arch.gpr[6];
-	svcpu->gpr[7] = vcpu->arch.gpr[7];
-	svcpu->gpr[8] = vcpu->arch.gpr[8];
-	svcpu->gpr[9] = vcpu->arch.gpr[9];
-	svcpu->gpr[10] = vcpu->arch.gpr[10];
-	svcpu->gpr[11] = vcpu->arch.gpr[11];
-	svcpu->gpr[12] = vcpu->arch.gpr[12];
-	svcpu->gpr[13] = vcpu->arch.gpr[13];
-	svcpu->cr  = vcpu->arch.cr;
-	svcpu->xer = vcpu->arch.xer;
-	svcpu->ctr = vcpu->arch.ctr;
-	svcpu->lr  = vcpu->arch.lr;
-	svcpu->pc  = vcpu->arch.pc;
+	svcpu->gpr[0] = vcpu->arch.regs.gpr[0];
+	svcpu->gpr[1] = vcpu->arch.regs.gpr[1];
+	svcpu->gpr[2] = vcpu->arch.regs.gpr[2];
+	svcpu->gpr[3] = vcpu->arch.regs.gpr[3];
+	svcpu->gpr[4] = vcpu->arch.regs.gpr[4];
+	svcpu->gpr[5] = vcpu->arch.regs.gpr[5];
+	svcpu->gpr[6] = vcpu->arch.regs.gpr[6];
+	svcpu->gpr[7] = vcpu->arch.regs.gpr[7];
+	svcpu->gpr[8] = vcpu->arch.regs.gpr[8];
+	svcpu->gpr[9] = vcpu->arch.regs.gpr[9];
+	svcpu->gpr[10] = vcpu->arch.regs.gpr[10];
+	svcpu->gpr[11] = vcpu->arch.regs.gpr[11];
+	svcpu->gpr[12] = vcpu->arch.regs.gpr[12];
+	svcpu->gpr[13] = vcpu->arch.regs.gpr[13];
+	svcpu->cr  = vcpu->arch.regs.ccr;
+	svcpu->xer = vcpu->arch.regs.xer;
+	svcpu->ctr = vcpu->arch.regs.ctr;
+	svcpu->lr  = vcpu->arch.regs.link;
+	svcpu->pc  = vcpu->arch.regs.nip;
 #ifdef CONFIG_PPC_BOOK3S_64
 	svcpu->shadow_fscr = vcpu->arch.shadow_fscr;
 #endif
@@ -195,25 +195,25 @@ void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu,
 	if (!svcpu->in_use)
 		goto out;
 
-	vcpu->arch.gpr[0] = svcpu->gpr[0];
-	vcpu->arch.gpr[1] = svcpu->gpr[1];
-	vcpu->arch.gpr[2] = svcpu->gpr[2];
-	vcpu->arch.gpr[3] = svcpu->gpr[3];
-	vcpu->arch.gpr[4] = svcpu->gpr[4];
-	vcpu->arch.gpr[5] = svcpu->gpr[5];
-	vcpu->arch.gpr[6] = svcpu->gpr[6];
-	vcpu->arch.gpr[7] = svcpu->gpr[7];
-	vcpu->arch.gpr[8] = svcpu->gpr[8];
-	vcpu->arch.gpr[9] = svcpu->gpr[9];
-	vcpu->arch.gpr[10] = svcpu->gpr[10];
-	vcpu->arch.gpr[11] = svcpu->gpr[11];
-	vcpu->arch.gpr[12] = svcpu->gpr[12];
-	vcpu->arch.gpr[13] = svcpu->gpr[13];
-	vcpu->arch.cr  = svcpu->cr;
-	vcpu->arch.xer = svcpu->xer;
-	vcpu->arch.ctr = svcpu->ctr;
-	vcpu->arch.lr  = svcpu->lr;
-	vcpu->arch.pc  = svcpu->pc;
+	vcpu->arch.regs.gpr[0] = svcpu->gpr[0];
+	vcpu->arch.regs.gpr[1] = svcpu->gpr[1];
+	vcpu->arch.regs.gpr[2] = svcpu->gpr[2];
+	vcpu->arch.regs.gpr[3] = svcpu->gpr[3];
+	vcpu->arch.regs.gpr[4] = svcpu->gpr[4];
+	vcpu->arch.regs.gpr[5] = svcpu->gpr[5];
+	vcpu->arch.regs.gpr[6] = svcpu->gpr[6];
+	vcpu->arch.regs.gpr[7] = svcpu->gpr[7];
+	vcpu->arch.regs.gpr[8] = svcpu->gpr[8];
+	vcpu->arch.regs.gpr[9] = svcpu->gpr[9];
+	vcpu->arch.regs.gpr[10] = svcpu->gpr[10];
+	vcpu->arch.regs.gpr[11] = svcpu->gpr[11];
+	vcpu->arch.regs.gpr[12] = svcpu->gpr[12];
+	vcpu->arch.regs.gpr[13] = svcpu->gpr[13];
+	vcpu->arch.regs.ccr  = svcpu->cr;
+	vcpu->arch.regs.xer  = svcpu->xer;
+	vcpu->arch.regs.ctr  = svcpu->ctr;
+	vcpu->arch.regs.link = svcpu->lr;
+	vcpu->arch.regs.nip  = svcpu->pc;
 	vcpu->arch.shadow_srr1 = svcpu->shadow_srr1;
 	vcpu->arch.fault_dar   = svcpu->fault_dar;
 	vcpu->arch.fault_dsisr = svcpu->fault_dsisr;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index a06ef6b..e62d09e 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -75,8 +75,10 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
 {
 	int i;
 
-	printk("pc:   %08lx msr:  %08llx\n", vcpu->arch.pc, vcpu->arch.shared->msr);
-	printk("lr:   %08lx ctr:  %08lx\n", vcpu->arch.lr, vcpu->arch.ctr);
+	printk("pc:   %08lx msr:  %08llx\n", kvmppc_get_pc(vcpu),
+	       vcpu->arch.shared->msr);
+	printk("lr:   %08lx ctr:  %08lx\n", kvmppc_get_lr(vcpu),
+	       kvmppc_get_ctr(vcpu));
 	printk("srr0: %08llx srr1: %08llx\n", vcpu->arch.shared->srr0,
 					    vcpu->arch.shared->srr1);
 
@@ -381,24 +383,24 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
 	if (allowed) {
 		switch (int_class) {
 		case INT_CLASS_NONCRIT:
-			set_guest_srr(vcpu, vcpu->arch.pc,
+			set_guest_srr(vcpu, kvmppc_get_pc(vcpu),
 				      vcpu->arch.shared->msr);
 			break;
 		case INT_CLASS_CRIT:
-			set_guest_csrr(vcpu, vcpu->arch.pc,
+			set_guest_csrr(vcpu, kvmppc_get_pc(vcpu),
 				       vcpu->arch.shared->msr);
 			break;
 		case INT_CLASS_DBG:
-			set_guest_dsrr(vcpu, vcpu->arch.pc,
+			set_guest_dsrr(vcpu, kvmppc_get_pc(vcpu),
 				       vcpu->arch.shared->msr);
 			break;
 		case INT_CLASS_MC:
-			set_guest_mcsrr(vcpu, vcpu->arch.pc,
+			set_guest_mcsrr(vcpu, kvmppc_get_pc(vcpu),
 					vcpu->arch.shared->msr);
 			break;
 		}
 
-		vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
+		kvmppc_set_pc(vcpu, vcpu->arch.ivpr | vcpu->arch.ivor[priority]);
 		if (update_esr == true)
 			kvmppc_set_esr(vcpu, vcpu->arch.queued_esr);
 		if (update_dear == true)
@@ -708,7 +710,7 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
 	case EMULATE_FAIL:
 		printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
-		       __func__, vcpu->arch.pc, vcpu->arch.last_inst);
+		       __func__, kvmppc_get_pc(vcpu), vcpu->arch.last_inst);
 		/* For debugging, encode the failing instruction and
 		 * report it to userspace. */
 		run->hw.hardware_exit_reason = ~0ULL << 32;
@@ -963,7 +965,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	case BOOKE_INTERRUPT_SPE_FP_DATA:
 	case BOOKE_INTERRUPT_SPE_FP_ROUND:
 		printk(KERN_CRIT "%s: unexpected SPE interrupt %u at %08lx\n",
-		       __func__, exit_nr, vcpu->arch.pc);
+		       __func__, exit_nr, kvmppc_get_pc(vcpu));
 		run->hw.hardware_exit_reason = exit_nr;
 		r = RESUME_HOST;
 		break;
@@ -1077,7 +1079,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	}
 
 	case BOOKE_INTERRUPT_ITLB_MISS: {
-		unsigned long eaddr = vcpu->arch.pc;
+		unsigned long eaddr = kvmppc_get_pc(vcpu);
 		gpa_t gpaddr;
 		gfn_t gfn;
 		int gtlb_index;
@@ -1166,7 +1168,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	int i;
 	int r;
 
-	vcpu->arch.pc = 0;
+	kvmppc_set_pc(vcpu, 0);
 	vcpu->arch.shared->pir = vcpu->vcpu_id;
 	kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
 	kvmppc_set_msr(vcpu, 0);
@@ -1209,10 +1211,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	int i;
 
-	regs->pc = vcpu->arch.pc;
+	regs->pc = kvmppc_get_pc(vcpu);
 	regs->cr = kvmppc_get_cr(vcpu);
-	regs->ctr = vcpu->arch.ctr;
-	regs->lr = vcpu->arch.lr;
+	regs->ctr = kvmppc_get_ctr(vcpu);
+	regs->lr = kvmppc_get_lr(vcpu);
 	regs->xer = kvmppc_get_xer(vcpu);
 	regs->msr = vcpu->arch.shared->msr;
 	regs->srr0 = kvmppc_get_srr0(vcpu);
@@ -1237,10 +1239,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	int i;
 
-	vcpu->arch.pc = regs->pc;
+	kvmppc_set_pc(vcpu, regs->pc);
 	kvmppc_set_cr(vcpu, regs->cr);
-	vcpu->arch.ctr = regs->ctr;
-	vcpu->arch.lr = regs->lr;
+	kvmppc_set_ctr(vcpu, regs->ctr);
+	kvmppc_set_lr(vcpu, regs->lr);
 	kvmppc_set_xer(vcpu, regs->xer);
 	kvmppc_set_msr(vcpu, regs->msr);
 	kvmppc_set_srr0(vcpu, regs->srr0);
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 28c1588..6bef2c7 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -33,13 +33,13 @@
 
 static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.pc = vcpu->arch.shared->srr0;
+	kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0);
 	kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
 }
 
 static void kvmppc_emul_rfci(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.pc = vcpu->arch.csrr0;
+	kvmppc_set_pc(vcpu, vcpu->arch.csrr0);
 	kvmppc_set_msr(vcpu, vcpu->arch.csrr1);
 }
 
diff --git a/arch/powerpc/kvm/e500_mmu.c b/arch/powerpc/kvm/e500_mmu.c
index 50860e9..ef7671b 100644
--- a/arch/powerpc/kvm/e500_mmu.c
+++ b/arch/powerpc/kvm/e500_mmu.c
@@ -513,7 +513,7 @@ void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
 {
 	unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
 
-	kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.pc, as);
+	kvmppc_e500_deliver_tlb_miss(vcpu, kvmppc_get_pc(vcpu), as);
 }
 
 void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 3/5] KVM: PPC: Use pt_regs struct for integer registers in struct vcpu_arch
@ 2014-07-19 10:14   ` Paul Mackerras
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This replaces the gpr, pc, ctr, lr, xer, cr and trap fields in the
struct vcpu_arch with a regs field, which is a struct pt_regs.
Similarly, it replaces gpr_tm, cr_tm, lr_tm, and ctr_tm with a
regs_tm field.  This then necessitates changes to the accessors
in kvm_book3s.h and kvm_booke.h, and changes to the KVM code where
it was not using the accessors.  Those places have either been
changed to use the accessors, or to access the fields using the
new names.

The reason for doing this is to make it possible to exploit more
of the non-KVM powerpc code in the kernel, thus reducing code
duplication.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/kvm_book3s.h | 24 +++++------
 arch/powerpc/include/asm/kvm_booke.h  | 24 +++++------
 arch/powerpc/include/asm/kvm_host.h   | 20 ++-------
 arch/powerpc/kernel/asm-offsets.c     | 32 +++++++--------
 arch/powerpc/kvm/book3s_32_mmu.c      |  2 +-
 arch/powerpc/kvm/book3s_64_mmu_hv.c   |  2 +-
 arch/powerpc/kvm/book3s_64_vio_hv.c   |  2 +-
 arch/powerpc/kvm/book3s_hv.c          | 42 ++++++++++---------
 arch/powerpc/kvm/book3s_hv_rm_mmu.c   | 10 ++---
 arch/powerpc/kvm/book3s_hv_rm_xics.c  |  2 +-
 arch/powerpc/kvm/book3s_pr.c          | 76 +++++++++++++++++------------------
 arch/powerpc/kvm/booke.c              | 36 +++++++++--------
 arch/powerpc/kvm/booke_emulate.c      |  4 +-
 arch/powerpc/kvm/e500_mmu.c           |  2 +-
 14 files changed, 134 insertions(+), 144 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 20fb6f2..b27cad8 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -212,62 +212,62 @@ static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
-	vcpu->arch.gpr[num] = val;
+	vcpu->arch.regs.gpr[num] = val;
 }
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-	return vcpu->arch.gpr[num];
+	return vcpu->arch.regs.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.cr = val;
+	vcpu->arch.regs.ccr = val;
 }
 
 static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.cr;
+	return vcpu->arch.regs.ccr;
 }
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.xer = val;
+	vcpu->arch.regs.xer = val;
 }
 
 static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.xer;
+	return vcpu->arch.regs.xer;
 }
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.ctr = val;
+	vcpu->arch.regs.ctr = val;
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.ctr;
+	return vcpu->arch.regs.ctr;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.lr = val;
+	vcpu->arch.regs.link = val;
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.lr;
+	return vcpu->arch.regs.link;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.pc = val;
+	vcpu->arch.regs.nip = val;
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.pc;
+	return vcpu->arch.regs.nip;
 }
 
 static inline u64 kvmppc_get_msr(struct kvm_vcpu *vcpu);
diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/include/asm/kvm_booke.h
index c7aed61..3274d63 100644
--- a/arch/powerpc/include/asm/kvm_booke.h
+++ b/arch/powerpc/include/asm/kvm_booke.h
@@ -35,32 +35,32 @@
 
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
-	vcpu->arch.gpr[num] = val;
+	vcpu->arch.regs.gpr[num] = val;
 }
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-	return vcpu->arch.gpr[num];
+	return vcpu->arch.regs.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.cr = val;
+	vcpu->arch.regs.ccr = val;
 }
 
 static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.cr;
+	return vcpu->arch.regs.ccr;
 }
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
 {
-	vcpu->arch.xer = val;
+	vcpu->arch.regs.xer = val;
 }
 
 static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.xer;
+	return vcpu->arch.regs.xer;
 }
 
 static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
@@ -76,32 +76,32 @@ static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.ctr = val;
+	vcpu->arch.regs.ctr = val;
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.ctr;
+	return vcpu->arch.regs.ctr;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.lr = val;
+	vcpu->arch.regs.link = val;
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.lr;
+	return vcpu->arch.regs.link;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-	vcpu->arch.pc = val;
+	vcpu->arch.regs.nip = val;
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.pc;
+	return vcpu->arch.regs.nip;
 }
 
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 855ba4d..0f3ac93 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -35,6 +35,7 @@
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 #include <asm/hvcall.h>
+#include <asm/ptrace.h>
 
 #define KVM_MAX_VCPUS		NR_CPUS
 #define KVM_MAX_VCORES		NR_CPUS
@@ -416,7 +417,7 @@ struct kvm_vcpu_arch {
 	struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
 #endif
 
-	ulong gpr[32];
+	struct pt_regs regs;
 
 	struct thread_fp_state fp;
 
@@ -449,19 +450,8 @@ struct kvm_vcpu_arch {
 #ifdef CONFIG_PPC_BOOK3S
 	/* For Gekko paired singles */
 	u32 qpr[32];
-#endif
 
-	ulong pc;
-	ulong ctr;
-	ulong lr;
-#ifdef CONFIG_PPC_BOOK3S
 	ulong tar;
-#endif
-
-	ulong xer;
-	u32 cr;
-
-#ifdef CONFIG_PPC_BOOK3S
 	ulong hflags;
 	ulong guest_owned_ext;
 	ulong purr;
@@ -538,15 +528,12 @@ struct kvm_vcpu_arch {
 	u64 texasr;
 	u64 tfiar;
 
-	u32 cr_tm;
-	u64 lr_tm;
-	u64 ctr_tm;
 	u64 amr_tm;
 	u64 ppr_tm;
 	u64 dscr_tm;
 	u64 tar_tm;
 
-	ulong gpr_tm[32];
+	struct pt_regs regs_tm;
 
 	struct thread_fp_state fp_tm;
 
@@ -627,7 +614,6 @@ struct kvm_vcpu_arch {
 	wait_queue_head_t *wqp;
 	struct kvmppc_vcore *vcore;
 	int ret;
-	int trap;
 	int state;
 	int ptid;
 	bool timer_running;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 17ffcb4..f5a154c 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -438,20 +438,20 @@ int main(void)
 	DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
 	DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
 	DEFINE(VCPU_GUEST_PID, offsetof(struct kvm_vcpu, arch.pid));
-	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
+	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.regs.gpr));
 	DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave));
 	DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fp.fpr));
 #ifdef CONFIG_ALTIVEC
 	DEFINE(VCPU_VRS, offsetof(struct kvm_vcpu, arch.vr.vr));
 #endif
-	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
-	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
-	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
+	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.regs.xer));
+	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.regs.ctr));
+	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.regs.link));
 #ifdef CONFIG_PPC_BOOK3S
 	DEFINE(VCPU_TAR, offsetof(struct kvm_vcpu, arch.tar));
 #endif
-	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
-	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
+	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.regs.ccr));
+	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.nip));
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 	DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.shregs.msr));
 	DEFINE(VCPU_SRR0, offsetof(struct kvm_vcpu, arch.shregs.srr0));
@@ -537,7 +537,7 @@ int main(void)
 	DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
 	DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
 	DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
-	DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
+	DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.regs.trap));
 	DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
 	DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr));
 	DEFINE(VCPU_FSCR, offsetof(struct kvm_vcpu, arch.fscr));
@@ -568,13 +568,13 @@ int main(void)
 	DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar));
 	DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar));
 	DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr));
-	DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.gpr_tm));
+	DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.gpr));
 	DEFINE(VCPU_FPRS_TM, offsetof(struct kvm_vcpu, arch.fp_tm.fpr));
 	DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
 	DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
-	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm));
-	DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
-	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
+	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.ccr));
+	DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.link));
+	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.regs_tm.ctr));
 	DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
 	DEFINE(VCPU_PPR_TM, offsetof(struct kvm_vcpu, arch.ppr_tm));
 	DEFINE(VCPU_DSCR_TM, offsetof(struct kvm_vcpu, arch.dscr_tm));
@@ -663,11 +663,11 @@ int main(void)
 #endif /* CONFIG_PPC_BOOK3S_64 */
 
 #else /* CONFIG_PPC_BOOK3S */
-	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
-	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
-	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
-	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
-	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
+	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.regs.ccr));
+	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.regs.xer));
+	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.regs.link));
+	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.regs.ctr));
+	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.nip));
 	DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
 	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c
index cd0b073..4eeb248 100644
--- a/arch/powerpc/kvm/book3s_32_mmu.c
+++ b/arch/powerpc/kvm/book3s_32_mmu.c
@@ -52,7 +52,7 @@
 static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
 {
 #ifdef DEBUG_MMU_PTE_IP
-	return vcpu->arch.pc = DEBUG_MMU_PTE_IP;
+	return kvmppc_get_pc(vcpu) = DEBUG_MMU_PTE_IP;
 #else
 	return true;
 #endif
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 2d154d9..b0c2514 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -409,7 +409,7 @@ long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 			     unsigned long ptel)
 {
 	return kvmppc_virtmode_do_h_enter(vcpu->kvm, flags, pte_index,
-					  pteh, ptel, &vcpu->arch.gpr[4]);
+					  pteh, ptel, &vcpu->arch.regs.gpr[4]);
 }
 
 static struct kvmppc_slb *kvmppc_mmu_book3s_hv_find_slbe(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index 89e96b3..bfcad1b 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -94,7 +94,7 @@ long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 			page = stt->pages[idx / TCES_PER_PAGE];
 			tbl = (u64 *)page_address(page);
 
-			vcpu->arch.gpr[4] = tbl[idx % TCES_PER_PAGE];
+			vcpu->arch.regs.gpr[4] = tbl[idx % TCES_PER_PAGE];
 			return H_SUCCESS;
 		}
 	}
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 0c5266e..74e110f 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -225,22 +225,24 @@ void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
 	int r;
 
 	pr_err("vcpu %p (%d):\n", vcpu, vcpu->vcpu_id);
-	pr_err("pc  = %.16lx  msr = %.16llx  trap = %x\n",
-	       vcpu->arch.pc, vcpu->arch.shregs.msr, vcpu->arch.trap);
+	pr_err("pc  = %.16lx  msr = %.16llx  trap = %lx\n",
+	       kvmppc_get_pc(vcpu), vcpu->arch.shregs.msr,
+	       vcpu->arch.regs.trap);
 	for (r = 0; r < 16; ++r)
 		pr_err("r%2d = %.16lx  r%d = %.16lx\n",
 		       r, kvmppc_get_gpr(vcpu, r),
 		       r+16, kvmppc_get_gpr(vcpu, r+16));
 	pr_err("ctr = %.16lx  lr  = %.16lx\n",
-	       vcpu->arch.ctr, vcpu->arch.lr);
+	       kvmppc_get_ctr(vcpu), kvmppc_get_lr(vcpu));
 	pr_err("srr0 = %.16llx srr1 = %.16llx\n",
 	       vcpu->arch.shregs.srr0, vcpu->arch.shregs.srr1);
 	pr_err("sprg0 = %.16llx sprg1 = %.16llx\n",
 	       vcpu->arch.shregs.sprg0, vcpu->arch.shregs.sprg1);
 	pr_err("sprg2 = %.16llx sprg3 = %.16llx\n",
 	       vcpu->arch.shregs.sprg2, vcpu->arch.shregs.sprg3);
-	pr_err("cr = %.8x  xer = %.16lx  dsisr = %.8x\n",
-	       vcpu->arch.cr, vcpu->arch.xer, vcpu->arch.shregs.dsisr);
+	pr_err("cr = %.8x  xer = %.8x  dsisr = %.8x\n",
+	       kvmppc_get_cr(vcpu), kvmppc_get_xer(vcpu),
+	       vcpu->arch.shregs.dsisr);
 	pr_err("dar = %.16llx\n", vcpu->arch.shregs.dar);
 	pr_err("fault dar = %.16lx dsisr = %.8x\n",
 	       vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
@@ -726,7 +728,7 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	run->ready_for_interrupt_injection = 1;
-	switch (vcpu->arch.trap) {
+	switch (vcpu->arch.regs.trap) {
 	/* We're good on these - the host merely wanted to get our attention */
 	case BOOK3S_INTERRUPT_HV_DECREMENTER:
 		vcpu->stat.dec_exits++;
@@ -817,10 +819,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		break;
 	default:
 		kvmppc_dump_regs(vcpu);
-		printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n",
-			vcpu->arch.trap, kvmppc_get_pc(vcpu),
+		printk(KERN_EMERG "trap=0x%lx | pc=0x%lx | msr=0x%llx\n",
+			vcpu->arch.regs.trap, kvmppc_get_pc(vcpu),
 			vcpu->arch.shregs.msr);
-		run->hw.hardware_exit_reason = vcpu->arch.trap;
+		run->hw.hardware_exit_reason = vcpu->arch.regs.trap;
 		r = RESUME_HOST;
 		break;
 	}
@@ -1034,7 +1036,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
 		i = id - KVM_REG_PPC_TM_GPR0;
-		*val = get_reg_val(id, vcpu->arch.gpr_tm[i]);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.gpr[i]);
 		break;
 	case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
 	{
@@ -1052,13 +1054,13 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	}
 	case KVM_REG_PPC_TM_CR:
-		*val = get_reg_val(id, vcpu->arch.cr_tm);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.ccr);
 		break;
 	case KVM_REG_PPC_TM_LR:
-		*val = get_reg_val(id, vcpu->arch.lr_tm);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.link);
 		break;
 	case KVM_REG_PPC_TM_CTR:
-		*val = get_reg_val(id, vcpu->arch.ctr_tm);
+		*val = get_reg_val(id, vcpu->arch.regs_tm.ctr);
 		break;
 	case KVM_REG_PPC_TM_FPSCR:
 		*val = get_reg_val(id, vcpu->arch.fp_tm.fpscr);
@@ -1242,7 +1244,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
 		i = id - KVM_REG_PPC_TM_GPR0;
-		vcpu->arch.gpr_tm[i] = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.gpr[i] = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
 	{
@@ -1259,13 +1261,13 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
 		break;
 	}
 	case KVM_REG_PPC_TM_CR:
-		vcpu->arch.cr_tm = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.ccr = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_LR:
-		vcpu->arch.lr_tm = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.ccr = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_CTR:
-		vcpu->arch.ctr_tm = set_reg_val(id, *val);
+		vcpu->arch.regs_tm.ctr = set_reg_val(id, *val);
 		break;
 	case KVM_REG_PPC_TM_FPSCR:
 		vcpu->arch.fp_tm.fpscr = set_reg_val(id, *val);
@@ -1685,12 +1687,12 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
 			kvmppc_core_dequeue_dec(vcpu);
 
 		ret = RESUME_GUEST;
-		if (vcpu->arch.trap)
+		if (vcpu->arch.regs.trap)
 			ret = kvmppc_handle_exit_hv(vcpu->arch.kvm_run, vcpu,
 						    vcpu->arch.run_task);
 
 		vcpu->arch.ret = ret;
-		vcpu->arch.trap = 0;
+		vcpu->arch.regs.trap = 0;
 
 		if (vcpu->arch.ceded) {
 			if (!is_kvmppc_resume_guest(ret))
@@ -1750,7 +1752,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 	kvm_run->exit_reason = 0;
 	vcpu->arch.ret = RESUME_GUEST;
-	vcpu->arch.trap = 0;
+	vcpu->arch.regs.trap = 0;
 	kvmppc_update_vpas(vcpu);
 
 	/*
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index e5c6063..b424499 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -368,7 +368,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
 		    long pte_index, unsigned long pteh, unsigned long ptel)
 {
 	return kvmppc_do_h_enter(vcpu->kvm, flags, pte_index, pteh, ptel,
-				 vcpu->arch.pgdir, true, &vcpu->arch.gpr[4]);
+				 vcpu->arch.pgdir, true, &vcpu->arch.regs.gpr[4]);
 }
 
 #ifdef __BIG_ENDIAN__
@@ -517,13 +517,13 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
 		     unsigned long pte_index, unsigned long avpn)
 {
 	return kvmppc_do_h_remove(vcpu->kvm, flags, pte_index, avpn,
-				  &vcpu->arch.gpr[4]);
+				  &vcpu->arch.regs.gpr[4]);
 }
 
 long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long *args = &vcpu->arch.gpr[4];
+	unsigned long *args = &vcpu->arch.regs.gpr[4];
 	__be64 *hp, *hptes[4];
 	unsigned long tlbrb[4];
 	long int i, j, k, n, found, indexes[4];
@@ -733,8 +733,8 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
 			r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C));
 			r &= ~HPTE_GR_RESERVED;
 		}
-		vcpu->arch.gpr[4 + i * 2] = v;
-		vcpu->arch.gpr[5 + i * 2] = r;
+		kvmppc_set_gpr(vcpu, 4 + i * 2, v);
+		kvmppc_set_gpr(vcpu, 5 + i * 2, r);
 	}
 	return H_SUCCESS;
 }
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
index b4b0082..80a6948 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -221,7 +221,7 @@ unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu)
 	} while (!icp_rm_try_update(icp, old_state, new_state));
 
 	/* Return the result in GPR4 */
-	vcpu->arch.gpr[4] = xirr;
+	kvmppc_set_gpr(vcpu, 4, xirr);
 
 	return check_too_hard(xics, icp);
 }
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 84c7a47..29906af 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -145,25 +145,25 @@ static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
 void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu,
 			  struct kvm_vcpu *vcpu)
 {
-	svcpu->gpr[0] = vcpu->arch.gpr[0];
-	svcpu->gpr[1] = vcpu->arch.gpr[1];
-	svcpu->gpr[2] = vcpu->arch.gpr[2];
-	svcpu->gpr[3] = vcpu->arch.gpr[3];
-	svcpu->gpr[4] = vcpu->arch.gpr[4];
-	svcpu->gpr[5] = vcpu->arch.gpr[5];
-	svcpu->gpr[6] = vcpu->arch.gpr[6];
-	svcpu->gpr[7] = vcpu->arch.gpr[7];
-	svcpu->gpr[8] = vcpu->arch.gpr[8];
-	svcpu->gpr[9] = vcpu->arch.gpr[9];
-	svcpu->gpr[10] = vcpu->arch.gpr[10];
-	svcpu->gpr[11] = vcpu->arch.gpr[11];
-	svcpu->gpr[12] = vcpu->arch.gpr[12];
-	svcpu->gpr[13] = vcpu->arch.gpr[13];
-	svcpu->cr  = vcpu->arch.cr;
-	svcpu->xer = vcpu->arch.xer;
-	svcpu->ctr = vcpu->arch.ctr;
-	svcpu->lr  = vcpu->arch.lr;
-	svcpu->pc  = vcpu->arch.pc;
+	svcpu->gpr[0] = vcpu->arch.regs.gpr[0];
+	svcpu->gpr[1] = vcpu->arch.regs.gpr[1];
+	svcpu->gpr[2] = vcpu->arch.regs.gpr[2];
+	svcpu->gpr[3] = vcpu->arch.regs.gpr[3];
+	svcpu->gpr[4] = vcpu->arch.regs.gpr[4];
+	svcpu->gpr[5] = vcpu->arch.regs.gpr[5];
+	svcpu->gpr[6] = vcpu->arch.regs.gpr[6];
+	svcpu->gpr[7] = vcpu->arch.regs.gpr[7];
+	svcpu->gpr[8] = vcpu->arch.regs.gpr[8];
+	svcpu->gpr[9] = vcpu->arch.regs.gpr[9];
+	svcpu->gpr[10] = vcpu->arch.regs.gpr[10];
+	svcpu->gpr[11] = vcpu->arch.regs.gpr[11];
+	svcpu->gpr[12] = vcpu->arch.regs.gpr[12];
+	svcpu->gpr[13] = vcpu->arch.regs.gpr[13];
+	svcpu->cr  = vcpu->arch.regs.ccr;
+	svcpu->xer = vcpu->arch.regs.xer;
+	svcpu->ctr = vcpu->arch.regs.ctr;
+	svcpu->lr  = vcpu->arch.regs.link;
+	svcpu->pc  = vcpu->arch.regs.nip;
 #ifdef CONFIG_PPC_BOOK3S_64
 	svcpu->shadow_fscr = vcpu->arch.shadow_fscr;
 #endif
@@ -195,25 +195,25 @@ void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu,
 	if (!svcpu->in_use)
 		goto out;
 
-	vcpu->arch.gpr[0] = svcpu->gpr[0];
-	vcpu->arch.gpr[1] = svcpu->gpr[1];
-	vcpu->arch.gpr[2] = svcpu->gpr[2];
-	vcpu->arch.gpr[3] = svcpu->gpr[3];
-	vcpu->arch.gpr[4] = svcpu->gpr[4];
-	vcpu->arch.gpr[5] = svcpu->gpr[5];
-	vcpu->arch.gpr[6] = svcpu->gpr[6];
-	vcpu->arch.gpr[7] = svcpu->gpr[7];
-	vcpu->arch.gpr[8] = svcpu->gpr[8];
-	vcpu->arch.gpr[9] = svcpu->gpr[9];
-	vcpu->arch.gpr[10] = svcpu->gpr[10];
-	vcpu->arch.gpr[11] = svcpu->gpr[11];
-	vcpu->arch.gpr[12] = svcpu->gpr[12];
-	vcpu->arch.gpr[13] = svcpu->gpr[13];
-	vcpu->arch.cr  = svcpu->cr;
-	vcpu->arch.xer = svcpu->xer;
-	vcpu->arch.ctr = svcpu->ctr;
-	vcpu->arch.lr  = svcpu->lr;
-	vcpu->arch.pc  = svcpu->pc;
+	vcpu->arch.regs.gpr[0] = svcpu->gpr[0];
+	vcpu->arch.regs.gpr[1] = svcpu->gpr[1];
+	vcpu->arch.regs.gpr[2] = svcpu->gpr[2];
+	vcpu->arch.regs.gpr[3] = svcpu->gpr[3];
+	vcpu->arch.regs.gpr[4] = svcpu->gpr[4];
+	vcpu->arch.regs.gpr[5] = svcpu->gpr[5];
+	vcpu->arch.regs.gpr[6] = svcpu->gpr[6];
+	vcpu->arch.regs.gpr[7] = svcpu->gpr[7];
+	vcpu->arch.regs.gpr[8] = svcpu->gpr[8];
+	vcpu->arch.regs.gpr[9] = svcpu->gpr[9];
+	vcpu->arch.regs.gpr[10] = svcpu->gpr[10];
+	vcpu->arch.regs.gpr[11] = svcpu->gpr[11];
+	vcpu->arch.regs.gpr[12] = svcpu->gpr[12];
+	vcpu->arch.regs.gpr[13] = svcpu->gpr[13];
+	vcpu->arch.regs.ccr  = svcpu->cr;
+	vcpu->arch.regs.xer  = svcpu->xer;
+	vcpu->arch.regs.ctr  = svcpu->ctr;
+	vcpu->arch.regs.link = svcpu->lr;
+	vcpu->arch.regs.nip  = svcpu->pc;
 	vcpu->arch.shadow_srr1 = svcpu->shadow_srr1;
 	vcpu->arch.fault_dar   = svcpu->fault_dar;
 	vcpu->arch.fault_dsisr = svcpu->fault_dsisr;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index a06ef6b..e62d09e 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -75,8 +75,10 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
 {
 	int i;
 
-	printk("pc:   %08lx msr:  %08llx\n", vcpu->arch.pc, vcpu->arch.shared->msr);
-	printk("lr:   %08lx ctr:  %08lx\n", vcpu->arch.lr, vcpu->arch.ctr);
+	printk("pc:   %08lx msr:  %08llx\n", kvmppc_get_pc(vcpu),
+	       vcpu->arch.shared->msr);
+	printk("lr:   %08lx ctr:  %08lx\n", kvmppc_get_lr(vcpu),
+	       kvmppc_get_ctr(vcpu));
 	printk("srr0: %08llx srr1: %08llx\n", vcpu->arch.shared->srr0,
 					    vcpu->arch.shared->srr1);
 
@@ -381,24 +383,24 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
 	if (allowed) {
 		switch (int_class) {
 		case INT_CLASS_NONCRIT:
-			set_guest_srr(vcpu, vcpu->arch.pc,
+			set_guest_srr(vcpu, kvmppc_get_pc(vcpu),
 				      vcpu->arch.shared->msr);
 			break;
 		case INT_CLASS_CRIT:
-			set_guest_csrr(vcpu, vcpu->arch.pc,
+			set_guest_csrr(vcpu, kvmppc_get_pc(vcpu),
 				       vcpu->arch.shared->msr);
 			break;
 		case INT_CLASS_DBG:
-			set_guest_dsrr(vcpu, vcpu->arch.pc,
+			set_guest_dsrr(vcpu, kvmppc_get_pc(vcpu),
 				       vcpu->arch.shared->msr);
 			break;
 		case INT_CLASS_MC:
-			set_guest_mcsrr(vcpu, vcpu->arch.pc,
+			set_guest_mcsrr(vcpu, kvmppc_get_pc(vcpu),
 					vcpu->arch.shared->msr);
 			break;
 		}
 
-		vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
+		kvmppc_set_pc(vcpu, vcpu->arch.ivpr | vcpu->arch.ivor[priority]);
 		if (update_esr = true)
 			kvmppc_set_esr(vcpu, vcpu->arch.queued_esr);
 		if (update_dear = true)
@@ -708,7 +710,7 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
 	case EMULATE_FAIL:
 		printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
-		       __func__, vcpu->arch.pc, vcpu->arch.last_inst);
+		       __func__, kvmppc_get_pc(vcpu), vcpu->arch.last_inst);
 		/* For debugging, encode the failing instruction and
 		 * report it to userspace. */
 		run->hw.hardware_exit_reason = ~0ULL << 32;
@@ -963,7 +965,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	case BOOKE_INTERRUPT_SPE_FP_DATA:
 	case BOOKE_INTERRUPT_SPE_FP_ROUND:
 		printk(KERN_CRIT "%s: unexpected SPE interrupt %u at %08lx\n",
-		       __func__, exit_nr, vcpu->arch.pc);
+		       __func__, exit_nr, kvmppc_get_pc(vcpu));
 		run->hw.hardware_exit_reason = exit_nr;
 		r = RESUME_HOST;
 		break;
@@ -1077,7 +1079,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	}
 
 	case BOOKE_INTERRUPT_ITLB_MISS: {
-		unsigned long eaddr = vcpu->arch.pc;
+		unsigned long eaddr = kvmppc_get_pc(vcpu);
 		gpa_t gpaddr;
 		gfn_t gfn;
 		int gtlb_index;
@@ -1166,7 +1168,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	int i;
 	int r;
 
-	vcpu->arch.pc = 0;
+	kvmppc_set_pc(vcpu, 0);
 	vcpu->arch.shared->pir = vcpu->vcpu_id;
 	kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
 	kvmppc_set_msr(vcpu, 0);
@@ -1209,10 +1211,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	int i;
 
-	regs->pc = vcpu->arch.pc;
+	regs->pc = kvmppc_get_pc(vcpu);
 	regs->cr = kvmppc_get_cr(vcpu);
-	regs->ctr = vcpu->arch.ctr;
-	regs->lr = vcpu->arch.lr;
+	regs->ctr = kvmppc_get_ctr(vcpu);
+	regs->lr = kvmppc_get_lr(vcpu);
 	regs->xer = kvmppc_get_xer(vcpu);
 	regs->msr = vcpu->arch.shared->msr;
 	regs->srr0 = kvmppc_get_srr0(vcpu);
@@ -1237,10 +1239,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	int i;
 
-	vcpu->arch.pc = regs->pc;
+	kvmppc_set_pc(vcpu, regs->pc);
 	kvmppc_set_cr(vcpu, regs->cr);
-	vcpu->arch.ctr = regs->ctr;
-	vcpu->arch.lr = regs->lr;
+	kvmppc_set_ctr(vcpu, regs->ctr);
+	kvmppc_set_lr(vcpu, regs->lr);
 	kvmppc_set_xer(vcpu, regs->xer);
 	kvmppc_set_msr(vcpu, regs->msr);
 	kvmppc_set_srr0(vcpu, regs->srr0);
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 28c1588..6bef2c7 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -33,13 +33,13 @@
 
 static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.pc = vcpu->arch.shared->srr0;
+	kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0);
 	kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
 }
 
 static void kvmppc_emul_rfci(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.pc = vcpu->arch.csrr0;
+	kvmppc_set_pc(vcpu, vcpu->arch.csrr0);
 	kvmppc_set_msr(vcpu, vcpu->arch.csrr1);
 }
 
diff --git a/arch/powerpc/kvm/e500_mmu.c b/arch/powerpc/kvm/e500_mmu.c
index 50860e9..ef7671b 100644
--- a/arch/powerpc/kvm/e500_mmu.c
+++ b/arch/powerpc/kvm/e500_mmu.c
@@ -513,7 +513,7 @@ void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
 {
 	unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
 
-	kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.pc, as);
+	kvmppc_e500_deliver_tlb_miss(vcpu, kvmppc_get_pc(vcpu), as);
 }
 
 void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 4/5] KVM: PPC: Use analyse_instr() in kvmppc_emulate_instruction()
  2014-07-19 10:14 ` Paul Mackerras
@ 2014-07-19 10:14   ` Paul Mackerras
  -1 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This changes kvmppc_emulate_instruction() to use the common instruction
decoding code from arch/powerpc/lib/sstep.c.  This expands the set of
instructions that we recognize to include all of the integer load and
store instructions except for the string (lsw*, stsw*) and multiple
(lmw, stmw) instructions and reduces the total amount of code.

This removes kvmppc_handle_loads() and instead adds a 'sign_extend'
parameter to kvmppc_handle_load().  (In fact kvmppc_handle_loads()
could not have worked previously; it sets vcpu->arch.mmio_sign_extend
to 1 before calling kvmppc_handle_load, which sets it back to 0.)

The instruction emulation for specific CPU flavours is largely unchanged,
except that emulation of mfmsr, eieio, and (for book 3S) mtmsr[d] has
moved into the generic code, and tlbsync emulation into the CPU-specific
code.

At this point the code still assumes that the instruction caused the
most recent guest exit, and that if the instruction is a load or store,
it must have been an emulated MMIO access and vcpu->arch.paddr_accessed
already contains the guest physical address being accessed.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/kvm_ppc.h       |   5 +-
 arch/powerpc/kvm/book3s_emulate.c        |  22 +--
 arch/powerpc/kvm/book3s_paired_singles.c |   6 +-
 arch/powerpc/kvm/booke_emulate.c         |   8 +-
 arch/powerpc/kvm/emulate.c               | 317 ++++++++++---------------------
 arch/powerpc/kvm/powerpc.c               |  17 +-
 6 files changed, 110 insertions(+), 265 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 246fb9a..9318cf3 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -54,10 +54,7 @@ extern void kvmppc_handler_highmem(void);
 extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
 extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
                               unsigned int rt, unsigned int bytes,
-			      int is_default_endian);
-extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                               unsigned int rt, unsigned int bytes,
-			       int is_default_endian);
+			      int is_default_endian, int sign_extend);
 extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			       u64 val, unsigned int bytes,
 			       int is_default_endian);
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
index 84fddcd..f74b8d5 100644
--- a/arch/powerpc/kvm/book3s_emulate.c
+++ b/arch/powerpc/kvm/book3s_emulate.c
@@ -129,24 +129,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		break;
 	case 31:
 		switch (get_xop(inst)) {
-		case OP_31_XOP_MFMSR:
-			kvmppc_set_gpr(vcpu, rt, kvmppc_get_msr(vcpu));
-			break;
-		case OP_31_XOP_MTMSRD:
-		{
-			ulong rs_val = kvmppc_get_gpr(vcpu, rs);
-			if (inst & 0x10000) {
-				ulong new_msr = kvmppc_get_msr(vcpu);
-				new_msr &= ~(MSR_RI | MSR_EE);
-				new_msr |= rs_val & (MSR_RI | MSR_EE);
-				kvmppc_set_msr_fast(vcpu, new_msr);
-			} else
-				kvmppc_set_msr(vcpu, rs_val);
-			break;
-		}
-		case OP_31_XOP_MTMSR:
-			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
-			break;
 		case OP_31_XOP_MFSR:
 		{
 			int srnum;
@@ -189,6 +171,8 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			vcpu->arch.mmu.tlbie(vcpu, addr, large);
 			break;
 		}
+		case OP_31_XOP_TLBSYNC:
+			break;
 #ifdef CONFIG_PPC_BOOK3S_64
 		case OP_31_XOP_FAKE_SC1:
 		{
@@ -217,8 +201,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			break;
 		}
 #endif
-		case OP_31_XOP_EIOIO:
-			break;
 		case OP_31_XOP_SLBMTE:
 			if (!vcpu->arch.mmu.slbmte)
 				return EMULATE_FAIL;
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index 6c8011f..a5bde19 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -200,7 +200,7 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		goto done_load;
 	} else if (r == EMULATE_DO_MMIO) {
 		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      len, 1);
+					      len, 1, 0);
 		goto done_load;
 	}
 
@@ -291,12 +291,12 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		goto done_load;
 	} else if ((r == EMULATE_DO_MMIO) && w) {
 		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      4, 1);
+					      4, 1, 0);
 		vcpu->arch.qpr[rs] = tmp[1];
 		goto done_load;
 	} else if (r == EMULATE_DO_MMIO) {
 		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
-					      8, 1);
+					      8, 1, 0);
 		goto done_load;
 	}
 
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 6bef2c7..81519b3 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -74,11 +74,6 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	case 31:
 		switch (get_xop(inst)) {
 
-		case OP_31_XOP_MFMSR:
-			kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr);
-			kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
-			break;
-
 		case OP_31_XOP_MTMSR:
 			kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
 			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
@@ -96,6 +91,9 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
 			break;
 
+		case OP_31_XOP_TLBSYNC:
+			break;
+
 		default:
 			emulated = EMULATE_FAIL;
 		}
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index da86d9b..0e66230 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -31,6 +31,7 @@
 #include <asm/kvm_ppc.h>
 #include <asm/disassemble.h>
 #include <asm/ppc-opcode.h>
+#include <asm/sstep.h>
 #include "timing.h"
 #include "trace.h"
 
@@ -90,10 +91,9 @@ u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
 	return vcpu->arch.dec - jd;
 }
 
-static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
+static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
 {
 	enum emulation_result emulated = EMULATE_DONE;
-	ulong spr_val = kvmppc_get_gpr(vcpu, rs);
 
 	switch (sprn) {
 	case SPRN_SRR0:
@@ -207,255 +207,135 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
 	return emulated;
 }
 
+static ulong maybe_truncate(struct kvm_vcpu *vcpu, ulong addr)
+{
+	if (!(kvmppc_get_msr(vcpu) & MSR_64BIT))
+		addr &= 0xffffffffUL;
+	return addr;
+}
+
+#ifdef CONFIG_PPC_BOOK3S
+static enum emulation_result deliver_interrupt(struct kvm_vcpu *vcpu,
+					       struct instruction_op *op)
+{
+	ulong vec = op->type & ~INSTR_TYPE_MASK;
+
+	if (vec == BOOK3S_INTERRUPT_PROGRAM)
+		kvmppc_core_queue_program(vcpu, op->val);
+	else
+		kvmppc_book3s_queue_irqprio(vcpu, vec);
+	return EMULATE_DONE;
+}
+#else
+static enum emulation_result deliver_interrupt(struct kvm_vcpu *vcpu,
+					       struct instruction_op *op)
+{
+	ulong vec = op->type & ~INSTR_TYPE_MASK;
+	ulong esr = 0;
+
+	switch (vec) {
+	case BOOK3S_INTERRUPT_PROGRAM:
+		if (srr1 == SRR1_PROGTRAP)
+			esr = ESR_PTR;
+		else if (srr1 == SRR1_PROGPRIV)
+			esr = ESR_PPR;
+		else
+			esr = 0;
+		kvmppc_core_queue_program(vcpu, esr);
+		break;
+	case BOOK3S_INTERRUPT_FP_UNAVAIL:
+		kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_FP_UNAVAIL);
+		break;
+	default:
+		return EMULATE_FAIL;
+	}
+	return EMULATE_DONE;
+}
+#endif /* CONFIG_PPC_BOOK3S */
+
 /* XXX to do:
- * lhax
- * lhaux
  * lswx
  * lswi
  * stswx
  * stswi
- * lha
- * lhau
  * lmw
  * stmw
  *
  */
-/* XXX Should probably auto-generate instruction decoding for a particular core
- * from opcode tables in the future. */
 int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
 	u32 inst = kvmppc_get_last_inst(vcpu);
-	int ra = get_ra(inst);
-	int rs = get_rs(inst);
-	int rt = get_rt(inst);
-	int sprn = get_sprn(inst);
 	enum emulation_result emulated = EMULATE_DONE;
 	int advance = 1;
+	ulong pc;
+	ulong val;
+	struct instruction_op op;
 
 	/* this default type might be overwritten by subcategories */
 	kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
 
 	pr_debug("Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
 
-	switch (get_op(inst)) {
-	case OP_TRAP:
-#ifdef CONFIG_PPC_BOOK3S
-	case OP_TRAP_64:
-		kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
-#else
-		kvmppc_core_queue_program(vcpu,
-					  vcpu->arch.shared->esr | ESR_PTR);
-#endif
-		advance = 0;
-		break;
-
-	case 31:
-		switch (get_xop(inst)) {
-
-		case OP_31_XOP_TRAP:
-#ifdef CONFIG_64BIT
-		case OP_31_XOP_TRAP_64:
-#endif
-#ifdef CONFIG_PPC_BOOK3S
-			kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
-#else
-			kvmppc_core_queue_program(vcpu,
-					vcpu->arch.shared->esr | ESR_PTR);
-#endif
-			advance = 0;
-			break;
-		case OP_31_XOP_LWZX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-			break;
-
-		case OP_31_XOP_LBZX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-			break;
-
-		case OP_31_XOP_LBZUX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_STWX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               4, 1);
-			break;
-
-		case OP_31_XOP_STBX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               1, 1);
-			break;
-
-		case OP_31_XOP_STBUX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               1, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_LHAX:
-			emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-			break;
-
-		case OP_31_XOP_LHZX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-			break;
-
-		case OP_31_XOP_LHZUX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_MFSPR:
-			emulated = kvmppc_emulate_mfspr(vcpu, sprn, rt);
-			break;
-
-		case OP_31_XOP_STHX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               2, 1);
-			break;
-
-		case OP_31_XOP_STHUX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               2, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_MTSPR:
-			emulated = kvmppc_emulate_mtspr(vcpu, sprn, rs);
-			break;
-
-		case OP_31_XOP_DCBST:
-		case OP_31_XOP_DCBF:
-		case OP_31_XOP_DCBI:
-			/* Do nothing. The guest is performing dcbi because
-			 * hardware DMA is not snooped by the dcache, but
-			 * emulated DMA either goes through the dcache as
-			 * normal writes, or the host kernel has handled dcache
-			 * coherence. */
-			break;
-
-		case OP_31_XOP_LWBRX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0);
-			break;
-
-		case OP_31_XOP_TLBSYNC:
-			break;
-
-		case OP_31_XOP_STWBRX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               4, 0);
-			break;
-
-		case OP_31_XOP_LHBRX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0);
-			break;
-
-		case OP_31_XOP_STHBRX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               2, 0);
-			break;
-
-		default:
-			/* Attempt core-specific emulation below. */
-			emulated = EMULATE_FAIL;
-		}
-		break;
-
-	case OP_LWZ:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-		break;
-
-	/* TBD: Add support for other 64 bit load variants like ldu, ldux, ldx etc. */
-	case OP_LD:
-		rt = get_rt(inst);
-		emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
-		break;
-
-	case OP_LWZU:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-		break;
-
-	case OP_LBZ:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-		break;
-
-	case OP_LBZU:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-		break;
-
-	case OP_STW:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               4, 1);
-		break;
-
-	/* TBD: Add support for other 64 bit store variants like stdu, stdux, stdx etc. */
-	case OP_STD:
-		rs = get_rs(inst);
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               8, 1);
-		break;
-
-	case OP_STWU:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               4, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-		break;
+	pc = kvmppc_get_pc(vcpu);
+	vcpu->arch.regs.msr = kvmppc_get_msr(vcpu);
+	if (analyse_instr(&op, &vcpu->arch.regs, inst)) {
+		/* Instruction has been executed by updating vcpu->arch.regs */
+		advance = 0;		/* already advanced */
+		goto out;
+	}
 
-	case OP_STB:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               1, 1);
+	switch (op.type & INSTR_TYPE_MASK) {
+	case INTERRUPT:
+		emulated = deliver_interrupt(vcpu, &op);
+		advance = 0;
 		break;
 
-	case OP_STBU:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               1, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case LOAD:
+		/* address already in vcpu->arch.paddr_accessed */
+		emulated = kvmppc_handle_load(run, vcpu, op.reg,
+					      GETSIZE(op.type),
+					      !(op.type & BYTEREV),
+					      !!(op.type & SIGNEXT));
+		if (op.type & UPDATE)
+			kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 		break;
 
-	case OP_LHZ:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+	case STORE:
+		/* address already in vcpu->arch.paddr_accessed */
+		emulated = kvmppc_handle_store(run, vcpu, op.val,
+					       GETSIZE(op.type), 1);
+		if (op.type & UPDATE)
+			kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 		break;
 
-	case OP_LHZU:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case MFSPR:
+		emulated = kvmppc_emulate_mfspr(vcpu, op.spr, op.reg);
 		break;
 
-	case OP_LHA:
-		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
+	case MTSPR:
+		emulated = kvmppc_emulate_mtspr(vcpu, op.spr, op.val);
 		break;
 
-	case OP_LHAU:
-		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case MFMSR:
+		kvmppc_set_gpr(vcpu, op.reg, kvmppc_get_msr(vcpu));
+		kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
 		break;
 
-	case OP_STH:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               2, 1);
+#ifdef CONFIG_PPC_BOOK3S
+	case MTMSR:
+		val = kvmppc_get_gpr(vcpu, op.reg);
+		val = (val & op.val) | (kvmppc_get_msr(vcpu) & ~op.val);
+		kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
+		kvmppc_set_msr(vcpu, val);
 		break;
+#endif
 
-	case OP_STHU:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               2, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case CACHEOP:
+		/* Do nothing. The guest is performing dcbi because
+		 * hardware DMA is not snooped by the dcache, but
+		 * emulated DMA either goes through the dcache as
+		 * normal writes, or the host kernel has handled dcache
+		 * coherence. */
 		break;
 
 	default:
@@ -475,11 +355,12 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		}
 	}
 
-	trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated);
+ out:
+	trace_kvm_ppc_instr(inst, pc, emulated);
 
 	/* Advance past emulated instruction. */
 	if (advance)
-		kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
+		kvmppc_set_pc(vcpu, maybe_truncate(vcpu, pc + 4));
 
 	return emulated;
 }
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index fe0257a..7e57ea9 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -729,7 +729,7 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 
 int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		       unsigned int rt, unsigned int bytes,
-		       int is_default_endian)
+		       int is_default_endian, int sign_extend)
 {
 	int idx, ret;
 	int is_bigendian;
@@ -755,7 +755,7 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	vcpu->arch.mmio_is_bigendian = is_bigendian;
 	vcpu->mmio_needed = 1;
 	vcpu->mmio_is_write = 0;
-	vcpu->arch.mmio_sign_extend = 0;
+	vcpu->arch.mmio_sign_extend = sign_extend;
 
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 
@@ -774,19 +774,6 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 }
 EXPORT_SYMBOL_GPL(kvmppc_handle_load);
 
-/* Same as above, but sign extends */
-int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
-			unsigned int rt, unsigned int bytes,
-			int is_default_endian)
-{
-	int r;
-
-	vcpu->arch.mmio_sign_extend = 1;
-	r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian);
-
-	return r;
-}
-
 int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			u64 val, unsigned int bytes, int is_default_endian)
 {
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 4/5] KVM: PPC: Use analyse_instr() in kvmppc_emulate_instruction()
@ 2014-07-19 10:14   ` Paul Mackerras
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

This changes kvmppc_emulate_instruction() to use the common instruction
decoding code from arch/powerpc/lib/sstep.c.  This expands the set of
instructions that we recognize to include all of the integer load and
store instructions except for the string (lsw*, stsw*) and multiple
(lmw, stmw) instructions and reduces the total amount of code.

This removes kvmppc_handle_loads() and instead adds a 'sign_extend'
parameter to kvmppc_handle_load().  (In fact kvmppc_handle_loads()
could not have worked previously; it sets vcpu->arch.mmio_sign_extend
to 1 before calling kvmppc_handle_load, which sets it back to 0.)

The instruction emulation for specific CPU flavours is largely unchanged,
except that emulation of mfmsr, eieio, and (for book 3S) mtmsr[d] has
moved into the generic code, and tlbsync emulation into the CPU-specific
code.

At this point the code still assumes that the instruction caused the
most recent guest exit, and that if the instruction is a load or store,
it must have been an emulated MMIO access and vcpu->arch.paddr_accessed
already contains the guest physical address being accessed.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/kvm_ppc.h       |   5 +-
 arch/powerpc/kvm/book3s_emulate.c        |  22 +--
 arch/powerpc/kvm/book3s_paired_singles.c |   6 +-
 arch/powerpc/kvm/booke_emulate.c         |   8 +-
 arch/powerpc/kvm/emulate.c               | 317 ++++++++++---------------------
 arch/powerpc/kvm/powerpc.c               |  17 +-
 6 files changed, 110 insertions(+), 265 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 246fb9a..9318cf3 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -54,10 +54,7 @@ extern void kvmppc_handler_highmem(void);
 extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
 extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
                               unsigned int rt, unsigned int bytes,
-			      int is_default_endian);
-extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                               unsigned int rt, unsigned int bytes,
-			       int is_default_endian);
+			      int is_default_endian, int sign_extend);
 extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			       u64 val, unsigned int bytes,
 			       int is_default_endian);
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
index 84fddcd..f74b8d5 100644
--- a/arch/powerpc/kvm/book3s_emulate.c
+++ b/arch/powerpc/kvm/book3s_emulate.c
@@ -129,24 +129,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		break;
 	case 31:
 		switch (get_xop(inst)) {
-		case OP_31_XOP_MFMSR:
-			kvmppc_set_gpr(vcpu, rt, kvmppc_get_msr(vcpu));
-			break;
-		case OP_31_XOP_MTMSRD:
-		{
-			ulong rs_val = kvmppc_get_gpr(vcpu, rs);
-			if (inst & 0x10000) {
-				ulong new_msr = kvmppc_get_msr(vcpu);
-				new_msr &= ~(MSR_RI | MSR_EE);
-				new_msr |= rs_val & (MSR_RI | MSR_EE);
-				kvmppc_set_msr_fast(vcpu, new_msr);
-			} else
-				kvmppc_set_msr(vcpu, rs_val);
-			break;
-		}
-		case OP_31_XOP_MTMSR:
-			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
-			break;
 		case OP_31_XOP_MFSR:
 		{
 			int srnum;
@@ -189,6 +171,8 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			vcpu->arch.mmu.tlbie(vcpu, addr, large);
 			break;
 		}
+		case OP_31_XOP_TLBSYNC:
+			break;
 #ifdef CONFIG_PPC_BOOK3S_64
 		case OP_31_XOP_FAKE_SC1:
 		{
@@ -217,8 +201,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			break;
 		}
 #endif
-		case OP_31_XOP_EIOIO:
-			break;
 		case OP_31_XOP_SLBMTE:
 			if (!vcpu->arch.mmu.slbmte)
 				return EMULATE_FAIL;
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index 6c8011f..a5bde19 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -200,7 +200,7 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		goto done_load;
 	} else if (r = EMULATE_DO_MMIO) {
 		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      len, 1);
+					      len, 1, 0);
 		goto done_load;
 	}
 
@@ -291,12 +291,12 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		goto done_load;
 	} else if ((r = EMULATE_DO_MMIO) && w) {
 		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      4, 1);
+					      4, 1, 0);
 		vcpu->arch.qpr[rs] = tmp[1];
 		goto done_load;
 	} else if (r = EMULATE_DO_MMIO) {
 		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
-					      8, 1);
+					      8, 1, 0);
 		goto done_load;
 	}
 
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 6bef2c7..81519b3 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -74,11 +74,6 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	case 31:
 		switch (get_xop(inst)) {
 
-		case OP_31_XOP_MFMSR:
-			kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr);
-			kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
-			break;
-
 		case OP_31_XOP_MTMSR:
 			kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
 			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
@@ -96,6 +91,9 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
 			break;
 
+		case OP_31_XOP_TLBSYNC:
+			break;
+
 		default:
 			emulated = EMULATE_FAIL;
 		}
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index da86d9b..0e66230 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -31,6 +31,7 @@
 #include <asm/kvm_ppc.h>
 #include <asm/disassemble.h>
 #include <asm/ppc-opcode.h>
+#include <asm/sstep.h>
 #include "timing.h"
 #include "trace.h"
 
@@ -90,10 +91,9 @@ u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
 	return vcpu->arch.dec - jd;
 }
 
-static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
+static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
 {
 	enum emulation_result emulated = EMULATE_DONE;
-	ulong spr_val = kvmppc_get_gpr(vcpu, rs);
 
 	switch (sprn) {
 	case SPRN_SRR0:
@@ -207,255 +207,135 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
 	return emulated;
 }
 
+static ulong maybe_truncate(struct kvm_vcpu *vcpu, ulong addr)
+{
+	if (!(kvmppc_get_msr(vcpu) & MSR_64BIT))
+		addr &= 0xffffffffUL;
+	return addr;
+}
+
+#ifdef CONFIG_PPC_BOOK3S
+static enum emulation_result deliver_interrupt(struct kvm_vcpu *vcpu,
+					       struct instruction_op *op)
+{
+	ulong vec = op->type & ~INSTR_TYPE_MASK;
+
+	if (vec = BOOK3S_INTERRUPT_PROGRAM)
+		kvmppc_core_queue_program(vcpu, op->val);
+	else
+		kvmppc_book3s_queue_irqprio(vcpu, vec);
+	return EMULATE_DONE;
+}
+#else
+static enum emulation_result deliver_interrupt(struct kvm_vcpu *vcpu,
+					       struct instruction_op *op)
+{
+	ulong vec = op->type & ~INSTR_TYPE_MASK;
+	ulong esr = 0;
+
+	switch (vec) {
+	case BOOK3S_INTERRUPT_PROGRAM:
+		if (srr1 = SRR1_PROGTRAP)
+			esr = ESR_PTR;
+		else if (srr1 = SRR1_PROGPRIV)
+			esr = ESR_PPR;
+		else
+			esr = 0;
+		kvmppc_core_queue_program(vcpu, esr);
+		break;
+	case BOOK3S_INTERRUPT_FP_UNAVAIL:
+		kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_FP_UNAVAIL);
+		break;
+	default:
+		return EMULATE_FAIL;
+	}
+	return EMULATE_DONE;
+}
+#endif /* CONFIG_PPC_BOOK3S */
+
 /* XXX to do:
- * lhax
- * lhaux
  * lswx
  * lswi
  * stswx
  * stswi
- * lha
- * lhau
  * lmw
  * stmw
  *
  */
-/* XXX Should probably auto-generate instruction decoding for a particular core
- * from opcode tables in the future. */
 int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
 	u32 inst = kvmppc_get_last_inst(vcpu);
-	int ra = get_ra(inst);
-	int rs = get_rs(inst);
-	int rt = get_rt(inst);
-	int sprn = get_sprn(inst);
 	enum emulation_result emulated = EMULATE_DONE;
 	int advance = 1;
+	ulong pc;
+	ulong val;
+	struct instruction_op op;
 
 	/* this default type might be overwritten by subcategories */
 	kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
 
 	pr_debug("Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
 
-	switch (get_op(inst)) {
-	case OP_TRAP:
-#ifdef CONFIG_PPC_BOOK3S
-	case OP_TRAP_64:
-		kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
-#else
-		kvmppc_core_queue_program(vcpu,
-					  vcpu->arch.shared->esr | ESR_PTR);
-#endif
-		advance = 0;
-		break;
-
-	case 31:
-		switch (get_xop(inst)) {
-
-		case OP_31_XOP_TRAP:
-#ifdef CONFIG_64BIT
-		case OP_31_XOP_TRAP_64:
-#endif
-#ifdef CONFIG_PPC_BOOK3S
-			kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
-#else
-			kvmppc_core_queue_program(vcpu,
-					vcpu->arch.shared->esr | ESR_PTR);
-#endif
-			advance = 0;
-			break;
-		case OP_31_XOP_LWZX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-			break;
-
-		case OP_31_XOP_LBZX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-			break;
-
-		case OP_31_XOP_LBZUX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_STWX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               4, 1);
-			break;
-
-		case OP_31_XOP_STBX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               1, 1);
-			break;
-
-		case OP_31_XOP_STBUX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               1, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_LHAX:
-			emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-			break;
-
-		case OP_31_XOP_LHZX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-			break;
-
-		case OP_31_XOP_LHZUX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_MFSPR:
-			emulated = kvmppc_emulate_mfspr(vcpu, sprn, rt);
-			break;
-
-		case OP_31_XOP_STHX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               2, 1);
-			break;
-
-		case OP_31_XOP_STHUX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               2, 1);
-			kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-			break;
-
-		case OP_31_XOP_MTSPR:
-			emulated = kvmppc_emulate_mtspr(vcpu, sprn, rs);
-			break;
-
-		case OP_31_XOP_DCBST:
-		case OP_31_XOP_DCBF:
-		case OP_31_XOP_DCBI:
-			/* Do nothing. The guest is performing dcbi because
-			 * hardware DMA is not snooped by the dcache, but
-			 * emulated DMA either goes through the dcache as
-			 * normal writes, or the host kernel has handled dcache
-			 * coherence. */
-			break;
-
-		case OP_31_XOP_LWBRX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0);
-			break;
-
-		case OP_31_XOP_TLBSYNC:
-			break;
-
-		case OP_31_XOP_STWBRX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               4, 0);
-			break;
-
-		case OP_31_XOP_LHBRX:
-			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0);
-			break;
-
-		case OP_31_XOP_STHBRX:
-			emulated = kvmppc_handle_store(run, vcpu,
-						       kvmppc_get_gpr(vcpu, rs),
-			                               2, 0);
-			break;
-
-		default:
-			/* Attempt core-specific emulation below. */
-			emulated = EMULATE_FAIL;
-		}
-		break;
-
-	case OP_LWZ:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-		break;
-
-	/* TBD: Add support for other 64 bit load variants like ldu, ldux, ldx etc. */
-	case OP_LD:
-		rt = get_rt(inst);
-		emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
-		break;
-
-	case OP_LWZU:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-		break;
-
-	case OP_LBZ:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-		break;
-
-	case OP_LBZU:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-		break;
-
-	case OP_STW:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               4, 1);
-		break;
-
-	/* TBD: Add support for other 64 bit store variants like stdu, stdux, stdx etc. */
-	case OP_STD:
-		rs = get_rs(inst);
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               8, 1);
-		break;
-
-	case OP_STWU:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               4, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-		break;
+	pc = kvmppc_get_pc(vcpu);
+	vcpu->arch.regs.msr = kvmppc_get_msr(vcpu);
+	if (analyse_instr(&op, &vcpu->arch.regs, inst)) {
+		/* Instruction has been executed by updating vcpu->arch.regs */
+		advance = 0;		/* already advanced */
+		goto out;
+	}
 
-	case OP_STB:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               1, 1);
+	switch (op.type & INSTR_TYPE_MASK) {
+	case INTERRUPT:
+		emulated = deliver_interrupt(vcpu, &op);
+		advance = 0;
 		break;
 
-	case OP_STBU:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               1, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case LOAD:
+		/* address already in vcpu->arch.paddr_accessed */
+		emulated = kvmppc_handle_load(run, vcpu, op.reg,
+					      GETSIZE(op.type),
+					      !(op.type & BYTEREV),
+					      !!(op.type & SIGNEXT));
+		if (op.type & UPDATE)
+			kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 		break;
 
-	case OP_LHZ:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+	case STORE:
+		/* address already in vcpu->arch.paddr_accessed */
+		emulated = kvmppc_handle_store(run, vcpu, op.val,
+					       GETSIZE(op.type), 1);
+		if (op.type & UPDATE)
+			kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 		break;
 
-	case OP_LHZU:
-		emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case MFSPR:
+		emulated = kvmppc_emulate_mfspr(vcpu, op.spr, op.reg);
 		break;
 
-	case OP_LHA:
-		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
+	case MTSPR:
+		emulated = kvmppc_emulate_mtspr(vcpu, op.spr, op.val);
 		break;
 
-	case OP_LHAU:
-		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case MFMSR:
+		kvmppc_set_gpr(vcpu, op.reg, kvmppc_get_msr(vcpu));
+		kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
 		break;
 
-	case OP_STH:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               2, 1);
+#ifdef CONFIG_PPC_BOOK3S
+	case MTMSR:
+		val = kvmppc_get_gpr(vcpu, op.reg);
+		val = (val & op.val) | (kvmppc_get_msr(vcpu) & ~op.val);
+		kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
+		kvmppc_set_msr(vcpu, val);
 		break;
+#endif
 
-	case OP_STHU:
-		emulated = kvmppc_handle_store(run, vcpu,
-					       kvmppc_get_gpr(vcpu, rs),
-		                               2, 1);
-		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+	case CACHEOP:
+		/* Do nothing. The guest is performing dcbi because
+		 * hardware DMA is not snooped by the dcache, but
+		 * emulated DMA either goes through the dcache as
+		 * normal writes, or the host kernel has handled dcache
+		 * coherence. */
 		break;
 
 	default:
@@ -475,11 +355,12 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		}
 	}
 
-	trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated);
+ out:
+	trace_kvm_ppc_instr(inst, pc, emulated);
 
 	/* Advance past emulated instruction. */
 	if (advance)
-		kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
+		kvmppc_set_pc(vcpu, maybe_truncate(vcpu, pc + 4));
 
 	return emulated;
 }
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index fe0257a..7e57ea9 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -729,7 +729,7 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 
 int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		       unsigned int rt, unsigned int bytes,
-		       int is_default_endian)
+		       int is_default_endian, int sign_extend)
 {
 	int idx, ret;
 	int is_bigendian;
@@ -755,7 +755,7 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	vcpu->arch.mmio_is_bigendian = is_bigendian;
 	vcpu->mmio_needed = 1;
 	vcpu->mmio_is_write = 0;
-	vcpu->arch.mmio_sign_extend = 0;
+	vcpu->arch.mmio_sign_extend = sign_extend;
 
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 
@@ -774,19 +774,6 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 }
 EXPORT_SYMBOL_GPL(kvmppc_handle_load);
 
-/* Same as above, but sign extends */
-int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
-			unsigned int rt, unsigned int bytes,
-			int is_default_endian)
-{
-	int r;
-
-	vcpu->arch.mmio_sign_extend = 1;
-	r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian);
-
-	return r;
-}
-
 int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 			u64 val, unsigned int bytes, int is_default_endian)
 {
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 5/5] KVM: PPC: Book3S: Make kvmppc_handle_load/store handle any load or store
  2014-07-19 10:14 ` Paul Mackerras
@ 2014-07-19 10:14   ` Paul Mackerras
  -1 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

At present, kvmppc_handle_load and kvmppc_handle_store only handle
emulated MMIO loads and stores.  This extends them to be able to handle
loads and stores to guest memory as well.  This is so that
kvmppc_emulate_instruction can be used to emulate loads and stores
in cases other than when an attempt to execute the instruction by the
CPU has resulted in an interrupt.

To avoid having to look up the translation for the effective address
again in kvmppc_handle_load/store when the caller of kvmppc_emulate_mmio
has already done it, we arrange to pass down the translation in a new
struct kvmppc_translated_address, which is a new argument to
kvmppc_emulate_mmio() and kvmppc_emulate_instruction().  This also
enables us to check that the guest hasn't replaced a load with a store
instruction.

This also makes the register updates for the paired-single FPU registers
match for emulated MMIO accesses what is done for accesses to normal
memory.

The new code for accessing normal guest memory uses kvmppc_ld and kvmppc_st,
which call kvmppc_xlate, which is only defined for Book 3S.  For Book E,
kvmppc_handle_load/store still only work for emulated MMIO.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/kvm_host.h      |   2 -
 arch/powerpc/include/asm/kvm_ppc.h       |  16 +++-
 arch/powerpc/kvm/Makefile                |   1 +
 arch/powerpc/kvm/book3s_64_mmu_hv.c      |   8 +-
 arch/powerpc/kvm/book3s_paired_singles.c | 121 ++++++++--------------------
 arch/powerpc/kvm/book3s_pr.c             |  12 +--
 arch/powerpc/kvm/booke.c                 |   9 ++-
 arch/powerpc/kvm/emulate.c               |   9 +--
 arch/powerpc/kvm/powerpc.c               | 131 +++++++++++++++++++++++--------
 9 files changed, 167 insertions(+), 142 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 0f3ac93..7c1b695 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -581,8 +581,6 @@ struct kvm_vcpu_arch {
 	/* hardware visible debug registers when in guest state */
 	struct debug_reg shadow_dbg_reg;
 #endif
-	gpa_t paddr_accessed;
-	gva_t vaddr_accessed;
 	pgd_t *pgdir;
 
 	u8 io_gpr; /* GPR used as IO source/target */
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 9318cf3..fc9cfcd 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -47,21 +47,33 @@ enum emulation_result {
 	EMULATE_EXIT_USER,    /* emulation requires exit to user-space */
 };
 
+struct kvmppc_translated_address {
+	ulong eaddr;
+	ulong raddr;
+	bool  is_store;
+};
+
 extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
 extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
 extern void kvmppc_handler_highmem(void);
 
 extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
 extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			      unsigned long ea,
+			      struct kvmppc_translated_address *ta,
                               unsigned int rt, unsigned int bytes,
 			      int is_default_endian, int sign_extend);
 extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			       unsigned long ea,
+			       struct kvmppc_translated_address *ta,
 			       u64 val, unsigned int bytes,
 			       int is_default_endian);
 
 extern int kvmppc_emulate_instruction(struct kvm_run *run,
-                                      struct kvm_vcpu *vcpu);
-extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
+                                      struct kvm_vcpu *vcpu,
+				      struct kvmppc_translated_address *ta);
+extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			       struct kvmppc_translated_address *ta);
 extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
 extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
 extern void kvmppc_decrementer_func(unsigned long data);
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index ce569b6..d5f1cd4 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -102,6 +102,7 @@ kvm-book3s_64-module-objs += \
 	$(KVM)/eventfd.o \
 	powerpc.o \
 	emulate.o \
+	fpu.o \
 	book3s.o \
 	book3s_64_vio.o \
 	book3s_rtas.o \
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index b0c2514..eda12cd 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -533,6 +533,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	int ret;
 	u32 last_inst;
 	unsigned long srr0 = kvmppc_get_pc(vcpu);
+	struct kvmppc_translated_address ta;
 
 	/* We try to load the last instruction.  We don't let
 	 * emulate_instruction do it as it doesn't check what
@@ -574,9 +575,10 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	 * a certain extent but we'll ignore it for now.
 	 */
 
-	vcpu->arch.paddr_accessed = gpa;
-	vcpu->arch.vaddr_accessed = ea;
-	return kvmppc_emulate_mmio(run, vcpu);
+	ta.eaddr = ea;
+	ta.raddr = gpa;
+	ta.is_store = !!is_store;
+	return kvmppc_emulate_mmio(run, vcpu, &ta);
 }
 
 int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index a5bde19..8ad0b33 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -183,132 +183,80 @@ static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
 static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				   int rs, ulong addr, int ls_type)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
-	char tmp[8];
+	int emulated;
 	int len = sizeof(u32);
 
 	if (ls_type == FPU_LS_DOUBLE)
 		len = sizeof(u64);
 
 	/* read from memory */
-	r = kvmppc_ld(vcpu, &addr, len, tmp, true);
-	vcpu->arch.paddr_accessed = addr;
-
-	if (r < 0) {
+	emulated = kvmppc_handle_load(run, vcpu, addr, NULL,
+				      KVM_MMIO_REG_FPR | rs, len, 1, 0);
+	if (emulated < 0) {
 		kvmppc_inject_pf(vcpu, addr, false);
-		goto done_load;
-	} else if (r == EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      len, 1, 0);
-		goto done_load;
-	}
-
-	emulated = EMULATE_DONE;
-
-	/* put in registers */
-	switch (ls_type) {
-	case FPU_LS_SINGLE:
-		kvm_cvt_fd((u32*)tmp, &VCPU_FPR(vcpu, rs));
-		vcpu->arch.qpr[rs] = *((u32*)tmp);
-		break;
-	case FPU_LS_DOUBLE:
-		VCPU_FPR(vcpu, rs) = *((u64*)tmp);
-		break;
+		emulated = EMULATE_FAIL;
 	}
 
-	dprintk(KERN_INFO "KVM: FPR_LD [0x%llx] at 0x%lx (%d)\n", *(u64*)tmp,
-			  addr, len);
-
-done_load:
 	return emulated;
 }
 
 static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				    int rs, ulong addr, int ls_type)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
-	char tmp[8];
+	int emulated;
+	u32 tmp;
 	u64 val;
 	int len;
 
 	switch (ls_type) {
 	case FPU_LS_SINGLE:
-		kvm_cvt_df(&VCPU_FPR(vcpu, rs), (u32*)tmp);
-		val = *((u32*)tmp);
+		kvm_cvt_df(&VCPU_FPR(vcpu, rs), &tmp);
+		val = tmp;
 		len = sizeof(u32);
 		break;
 	case FPU_LS_SINGLE_LOW:
-		*((u32*)tmp) = VCPU_FPR(vcpu, rs);
 		val = VCPU_FPR(vcpu, rs) & 0xffffffff;
 		len = sizeof(u32);
 		break;
 	case FPU_LS_DOUBLE:
-		*((u64*)tmp) = VCPU_FPR(vcpu, rs);
 		val = VCPU_FPR(vcpu, rs);
 		len = sizeof(u64);
 		break;
 	default:
-		val = 0;
-		len = 0;
+		return EMULATE_DONE;
 	}
 
-	r = kvmppc_st(vcpu, &addr, len, tmp, true);
-	vcpu->arch.paddr_accessed = addr;
-	if (r < 0) {
+	emulated = kvmppc_handle_store(run, vcpu, addr, NULL, val, len, 1);
+	if (emulated < 0) {
 		kvmppc_inject_pf(vcpu, addr, true);
-	} else if (r == EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_store(run, vcpu, val, len, 1);
-	} else {
-		emulated = EMULATE_DONE;
+		emulated = EMULATE_FAIL;
 	}
 
-	dprintk(KERN_INFO "KVM: FPR_ST [0x%llx] at 0x%lx (%d)\n",
-			  val, addr, len);
-
 	return emulated;
 }
 
 static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				   int rs, ulong addr, bool w, int i)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
-	float one = 1.0;
-	u32 tmp[2];
+	int emulated;
 
 	/* read from memory */
 	if (w) {
-		r = kvmppc_ld(vcpu, &addr, sizeof(u32), tmp, true);
-		memcpy(&tmp[1], &one, sizeof(u32));
+		emulated = kvmppc_handle_load(run, vcpu, addr, NULL,
+					      KVM_MMIO_REG_FPR | rs, 4, 1, 0);
+		
 	} else {
-		r = kvmppc_ld(vcpu, &addr, sizeof(u32) * 2, tmp, true);
+		emulated = kvmppc_handle_load(run, vcpu, addr, NULL,
+					      KVM_MMIO_REG_FQPR | rs, 8, 1, 0);
 	}
-	vcpu->arch.paddr_accessed = addr;
-	if (r < 0) {
+	if (emulated < 0) {
 		kvmppc_inject_pf(vcpu, addr, false);
-		goto done_load;
-	} else if ((r == EMULATE_DO_MMIO) && w) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      4, 1, 0);
-		vcpu->arch.qpr[rs] = tmp[1];
-		goto done_load;
-	} else if (r == EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
-					      8, 1, 0);
+		emulated = EMULATE_FAIL;
 		goto done_load;
 	}
 
 	emulated = EMULATE_DONE;
 
-	/* put in registers */
-	kvm_cvt_fd(&tmp[0], &VCPU_FPR(vcpu, rs));
-	vcpu->arch.qpr[rs] = tmp[1];
-
-	dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
-			  tmp[1], addr, w ? 4 : 8);
-
 done_load:
 	return emulated;
 }
@@ -316,29 +264,24 @@ done_load:
 static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				    int rs, ulong addr, bool w, int i)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
+	int emulated;
 	u32 tmp[2];
-	int len = w ? sizeof(u32) : sizeof(u64);
 
 	kvm_cvt_df(&VCPU_FPR(vcpu, rs), &tmp[0]);
 	tmp[1] = vcpu->arch.qpr[rs];
 
-	r = kvmppc_st(vcpu, &addr, len, tmp, true);
-	vcpu->arch.paddr_accessed = addr;
-	if (r < 0) {
-		kvmppc_inject_pf(vcpu, addr, true);
-	} else if ((r == EMULATE_DO_MMIO) && w) {
-		emulated = kvmppc_handle_store(run, vcpu, tmp[0], 4, 1);
-	} else if (r == EMULATE_DO_MMIO) {
-		u64 val = ((u64)tmp[0] << 32) | tmp[1];
-		emulated = kvmppc_handle_store(run, vcpu, val, 8, 1);
+	if (w) {
+		emulated = kvmppc_handle_store(run, vcpu, addr, NULL,
+					       tmp[0], 4, 1);
 	} else {
-		emulated = EMULATE_DONE;
+		u64 val = ((u64)tmp[0] << 32) | tmp[1];
+		emulated = kvmppc_handle_store(run, vcpu, addr, NULL,
+					       val, 8, 1);
+	}
+	if (emulated < 0) {
+		kvmppc_inject_pf(vcpu, addr, true);
+		emulated = EMULATE_FAIL;
 	}
-
-	dprintk(KERN_INFO "KVM: PSQ_ST [0x%x, 0x%x] at 0x%lx (%d)\n",
-			  tmp[0], tmp[1], addr, len);
 
 	return emulated;
 }
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 29906af..98aa40a 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -539,6 +539,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	bool dr = (kvmppc_get_msr(vcpu) & MSR_DR) ? true : false;
 	bool ir = (kvmppc_get_msr(vcpu) & MSR_IR) ? true : false;
 	u64 vsid;
+	struct kvmppc_translated_address ta;
 
 	relocated = data ? dr : ir;
 	if (data && (vcpu->arch.fault_dsisr & DSISR_ISSTORE))
@@ -633,9 +634,10 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	} else {
 		/* MMIO */
 		vcpu->stat.mmio_exits++;
-		vcpu->arch.paddr_accessed = pte.raddr;
-		vcpu->arch.vaddr_accessed = pte.eaddr;
-		r = kvmppc_emulate_mmio(run, vcpu);
+		ta.eaddr = pte.eaddr;
+		ta.raddr = pte.raddr;
+		ta.is_store = iswrite;
+		r = kvmppc_emulate_mmio(run, vcpu, &ta);
 		if ( r == RESUME_HOST_NV )
 			r = RESUME_HOST;
 	}
@@ -856,7 +858,7 @@ static void kvmppc_emulate_fac(struct kvm_vcpu *vcpu, ulong fac)
 	enum emulation_result er = EMULATE_FAIL;
 
 	if (!(kvmppc_get_msr(vcpu) & MSR_PR))
-		er = kvmppc_emulate_instruction(vcpu->run, vcpu);
+		er = kvmppc_emulate_instruction(vcpu->run, vcpu, NULL);
 
 	if ((er != EMULATE_DONE) && (er != EMULATE_AGAIN)) {
 		/* Couldn't emulate, trigger interrupt in guest */
@@ -1071,7 +1073,7 @@ program_interrupt:
 		}
 
 		vcpu->stat.emulated_inst_exits++;
-		er = kvmppc_emulate_instruction(run, vcpu);
+		er = kvmppc_emulate_instruction(run, vcpu, NULL);
 		switch (er) {
 		case EMULATE_DONE:
 			r = RESUME_GUEST_NV;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index e62d09e..e5740db 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -695,7 +695,7 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
 	enum emulation_result er;
 
-	er = kvmppc_emulate_instruction(run, vcpu);
+	er = kvmppc_emulate_instruction(run, vcpu, NULL);
 	switch (er) {
 	case EMULATE_DONE:
 		/* don't overwrite subtypes, just account kvm_stats */
@@ -1068,9 +1068,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		} else {
 			/* Guest has mapped and accessed a page which is not
 			 * actually RAM. */
-			vcpu->arch.paddr_accessed = gpaddr;
-			vcpu->arch.vaddr_accessed = eaddr;
-			r = kvmppc_emulate_mmio(run, vcpu);
+			ta.eaddr = eaddr;
+			ta.raddr = gpaddr;
+			ta.is_store = true;
+			r = kvmppc_emulate_mmio(run, vcpu, &ta);
 			kvmppc_account_exit(vcpu, MMIO_EXITS);
 		}
 
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index 0e66230..a5dfd00 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -262,7 +262,8 @@ static enum emulation_result deliver_interrupt(struct kvm_vcpu *vcpu,
  * stmw
  *
  */
-int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
+int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			       struct kvmppc_translated_address *ta)
 {
 	u32 inst = kvmppc_get_last_inst(vcpu);
 	enum emulation_result emulated = EMULATE_DONE;
@@ -291,8 +292,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		break;
 
 	case LOAD:
-		/* address already in vcpu->arch.paddr_accessed */
-		emulated = kvmppc_handle_load(run, vcpu, op.reg,
+		emulated = kvmppc_handle_load(run, vcpu, op.ea, ta, op.reg,
 					      GETSIZE(op.type),
 					      !(op.type & BYTEREV),
 					      !!(op.type & SIGNEXT));
@@ -301,8 +301,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		break;
 
 	case STORE:
-		/* address already in vcpu->arch.paddr_accessed */
-		emulated = kvmppc_handle_store(run, vcpu, op.val,
+		emulated = kvmppc_handle_store(run, vcpu, op.ea, ta, op.val,
 					       GETSIZE(op.type), 1);
 		if (op.type & UPDATE)
 			kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 7e57ea9..d31b525 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -33,6 +33,7 @@
 #include <asm/tlbflush.h>
 #include <asm/cputhreads.h>
 #include <asm/irqflags.h>
+#include <asm/kvm_fpu.h>
 #include "timing.h"
 #include "irq.h"
 #include "../mm/mmu_decl.h"
@@ -268,12 +269,13 @@ out:
 }
 EXPORT_SYMBOL_GPL(kvmppc_sanity_check);
 
-int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
+int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			struct kvmppc_translated_address *ta)
 {
 	enum emulation_result er;
 	int r;
 
-	er = kvmppc_emulate_instruction(run, vcpu);
+	er = kvmppc_emulate_instruction(run, vcpu, ta);
 	switch (er) {
 	case EMULATE_DONE:
 		/* Future optimization: only reload non-volatiles if they were
@@ -662,34 +664,36 @@ static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,
 	kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, run->dcr.data);
 }
 
-static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
-                                      struct kvm_run *run)
+static void kvmppc_complete_load(struct kvm_vcpu *vcpu,
+				 u8 *data, int len, unsigned int io_gpr,
+				 bool is_bigendian, bool sign_extend)
 {
 	u64 uninitialized_var(gpr);
+	u32 val32;
 
-	if (run->mmio.len > sizeof(gpr)) {
-		printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len);
+	if (len > sizeof(gpr)) {
+		printk(KERN_ERR "bad MMIO length: %d\n", len);
 		return;
 	}
 
-	if (vcpu->arch.mmio_is_bigendian) {
-		switch (run->mmio.len) {
-		case 8: gpr = *(u64 *)run->mmio.data; break;
-		case 4: gpr = *(u32 *)run->mmio.data; break;
-		case 2: gpr = *(u16 *)run->mmio.data; break;
-		case 1: gpr = *(u8 *)run->mmio.data; break;
+	if (is_bigendian) {
+		switch (len) {
+		case 8: gpr = *(u64 *)data; break;
+		case 4: gpr = *(u32 *)data; break;
+		case 2: gpr = *(u16 *)data; break;
+		case 1: gpr = *(u8 *)data; break;
 		}
 	} else {
 		/* Convert BE data from userland back to LE. */
-		switch (run->mmio.len) {
-		case 4: gpr = ld_le32((u32 *)run->mmio.data); break;
-		case 2: gpr = ld_le16((u16 *)run->mmio.data); break;
-		case 1: gpr = *(u8 *)run->mmio.data; break;
+		switch (len) {
+		case 4: gpr = ld_le32((u32 *)data); break;
+		case 2: gpr = ld_le16((u16 *)data); break;
+		case 1: gpr = *(u8 *)data; break;
 		}
 	}
 
 	if (vcpu->arch.mmio_sign_extend) {
-		switch (run->mmio.len) {
+		switch (len) {
 #ifdef CONFIG_PPC64
 		case 4:
 			gpr = (s64)(s32)gpr;
@@ -704,22 +708,31 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 		}
 	}
 
-	kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
-
-	switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) {
+	switch (io_gpr & KVM_MMIO_REG_EXT_MASK) {
 	case KVM_MMIO_REG_GPR:
-		kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
+		kvmppc_set_gpr(vcpu, io_gpr, gpr);
 		break;
 	case KVM_MMIO_REG_FPR:
-		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
+		if (len == 4) {
+			val32 = gpr;
+			kvm_cvt_fd(&val32, &gpr);
+		}
+		VCPU_FPR(vcpu, io_gpr & KVM_MMIO_REG_MASK) = gpr;
 		break;
 #ifdef CONFIG_PPC_BOOK3S
 	case KVM_MMIO_REG_QPR:
-		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+		vcpu->arch.qpr[io_gpr & KVM_MMIO_REG_MASK] = gpr;
 		break;
 	case KVM_MMIO_REG_FQPR:
-		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
-		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+		val32 = gpr >> 32;
+		kvm_cvt_fd(&val32, &gpr);
+		VCPU_FPR(vcpu, io_gpr & KVM_MMIO_REG_MASK) = gpr;
+		if (len == 4) {
+			float one = 1.0;
+			memcpy(&vcpu->arch.qpr[io_gpr & KVM_MMIO_REG_MASK],
+			       &one, sizeof(u32));
+		} else
+			vcpu->arch.qpr[io_gpr & KVM_MMIO_REG_MASK] = gpr;
 		break;
 #endif
 	default:
@@ -727,12 +740,24 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 	}
 }
 
+static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
+                                      struct kvm_run *run)
+{
+	kvmppc_complete_load(vcpu, run->mmio.data, run->mmio.len,
+			     vcpu->arch.io_gpr, vcpu->arch.mmio_is_bigendian,
+			     vcpu->arch.mmio_sign_extend);
+}
+
 int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+		       unsigned long ea, struct kvmppc_translated_address *ta,
 		       unsigned int rt, unsigned int bytes,
 		       int is_default_endian, int sign_extend)
 {
 	int idx, ret;
 	int is_bigendian;
+#ifdef CONFIG_PPC_BOOK3S
+	struct kvmppc_translated_address local_ta;
+#endif
 
 	if (kvmppc_need_byteswap(vcpu)) {
 		/* Default endianness is "little endian". */
@@ -742,12 +767,33 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		is_bigendian = is_default_endian;
 	}
 
+#ifdef CONFIG_PPC_BOOK3S
+	if (!ta || ea != ta->eaddr) {
+		unsigned long addr;
+		u8 buf[8];
+		int r;
+
+		addr = ea;
+		r = kvmppc_ld(vcpu, &addr, bytes, buf, true);
+		if (r != EMULATE_DO_MMIO) {
+			if (r >= 0)
+				kvmppc_complete_load(vcpu, buf, bytes, rt,
+						is_bigendian, sign_extend);
+			return r;
+		}
+		local_ta.eaddr = ea;
+		local_ta.raddr = addr;
+		local_ta.is_store = false;
+		ta = &local_ta;
+	}
+#endif
+
 	if (bytes > sizeof(run->mmio.data)) {
 		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
 		       run->mmio.len);
 	}
 
-	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
+	run->mmio.phys_addr = ta->raddr;
 	run->mmio.len = bytes;
 	run->mmio.is_write = 0;
 
@@ -775,11 +821,15 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 EXPORT_SYMBOL_GPL(kvmppc_handle_load);
 
 int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			unsigned long ea, struct kvmppc_translated_address *ta,
 			u64 val, unsigned int bytes, int is_default_endian)
 {
 	void *data = run->mmio.data;
 	int idx, ret;
 	int is_bigendian;
+#ifdef CONFIG_PPC_BOOK3S
+	struct kvmppc_translated_address local_ta;
+#endif
 
 	if (kvmppc_need_byteswap(vcpu)) {
 		/* Default endianness is "little endian". */
@@ -794,12 +844,6 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		       run->mmio.len);
 	}
 
-	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
-	run->mmio.len = bytes;
-	run->mmio.is_write = 1;
-	vcpu->mmio_needed = 1;
-	vcpu->mmio_is_write = 1;
-
 	/* Store the value at the lowest bytes in 'data'. */
 	if (is_bigendian) {
 		switch (bytes) {
@@ -817,6 +861,29 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		}
 	}
 
+#ifdef CONFIG_PPC_BOOK3S
+	if (!ta || ea != ta->eaddr || !ta->is_store) {
+		unsigned long addr;
+		int r;
+
+		addr = ea;
+		r = kvmppc_st(vcpu, &addr, bytes, data, true);
+		if (r != EMULATE_DO_MMIO)
+			return r;
+
+		local_ta.eaddr = ea;
+		local_ta.raddr = addr;
+		local_ta.is_store = true;
+		ta = &local_ta;
+	}
+#endif
+
+	run->mmio.phys_addr = ta->raddr;
+	run->mmio.len = bytes;
+	run->mmio.is_write = 1;
+	vcpu->mmio_needed = 1;
+	vcpu->mmio_is_write = 1;
+
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 
 	ret = kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr,
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [RFC PATCH 5/5] KVM: PPC: Book3S: Make kvmppc_handle_load/store handle any load or store
@ 2014-07-19 10:14   ` Paul Mackerras
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Mackerras @ 2014-07-19 10:14 UTC (permalink / raw)
  To: Alexander Graf, kvm-ppc; +Cc: kvm

At present, kvmppc_handle_load and kvmppc_handle_store only handle
emulated MMIO loads and stores.  This extends them to be able to handle
loads and stores to guest memory as well.  This is so that
kvmppc_emulate_instruction can be used to emulate loads and stores
in cases other than when an attempt to execute the instruction by the
CPU has resulted in an interrupt.

To avoid having to look up the translation for the effective address
again in kvmppc_handle_load/store when the caller of kvmppc_emulate_mmio
has already done it, we arrange to pass down the translation in a new
struct kvmppc_translated_address, which is a new argument to
kvmppc_emulate_mmio() and kvmppc_emulate_instruction().  This also
enables us to check that the guest hasn't replaced a load with a store
instruction.

This also makes the register updates for the paired-single FPU registers
match for emulated MMIO accesses what is done for accesses to normal
memory.

The new code for accessing normal guest memory uses kvmppc_ld and kvmppc_st,
which call kvmppc_xlate, which is only defined for Book 3S.  For Book E,
kvmppc_handle_load/store still only work for emulated MMIO.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/kvm_host.h      |   2 -
 arch/powerpc/include/asm/kvm_ppc.h       |  16 +++-
 arch/powerpc/kvm/Makefile                |   1 +
 arch/powerpc/kvm/book3s_64_mmu_hv.c      |   8 +-
 arch/powerpc/kvm/book3s_paired_singles.c | 121 ++++++++--------------------
 arch/powerpc/kvm/book3s_pr.c             |  12 +--
 arch/powerpc/kvm/booke.c                 |   9 ++-
 arch/powerpc/kvm/emulate.c               |   9 +--
 arch/powerpc/kvm/powerpc.c               | 131 +++++++++++++++++++++++--------
 9 files changed, 167 insertions(+), 142 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 0f3ac93..7c1b695 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -581,8 +581,6 @@ struct kvm_vcpu_arch {
 	/* hardware visible debug registers when in guest state */
 	struct debug_reg shadow_dbg_reg;
 #endif
-	gpa_t paddr_accessed;
-	gva_t vaddr_accessed;
 	pgd_t *pgdir;
 
 	u8 io_gpr; /* GPR used as IO source/target */
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 9318cf3..fc9cfcd 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -47,21 +47,33 @@ enum emulation_result {
 	EMULATE_EXIT_USER,    /* emulation requires exit to user-space */
 };
 
+struct kvmppc_translated_address {
+	ulong eaddr;
+	ulong raddr;
+	bool  is_store;
+};
+
 extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
 extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
 extern void kvmppc_handler_highmem(void);
 
 extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
 extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			      unsigned long ea,
+			      struct kvmppc_translated_address *ta,
                               unsigned int rt, unsigned int bytes,
 			      int is_default_endian, int sign_extend);
 extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			       unsigned long ea,
+			       struct kvmppc_translated_address *ta,
 			       u64 val, unsigned int bytes,
 			       int is_default_endian);
 
 extern int kvmppc_emulate_instruction(struct kvm_run *run,
-                                      struct kvm_vcpu *vcpu);
-extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
+                                      struct kvm_vcpu *vcpu,
+				      struct kvmppc_translated_address *ta);
+extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			       struct kvmppc_translated_address *ta);
 extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
 extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
 extern void kvmppc_decrementer_func(unsigned long data);
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index ce569b6..d5f1cd4 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -102,6 +102,7 @@ kvm-book3s_64-module-objs += \
 	$(KVM)/eventfd.o \
 	powerpc.o \
 	emulate.o \
+	fpu.o \
 	book3s.o \
 	book3s_64_vio.o \
 	book3s_rtas.o \
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index b0c2514..eda12cd 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -533,6 +533,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	int ret;
 	u32 last_inst;
 	unsigned long srr0 = kvmppc_get_pc(vcpu);
+	struct kvmppc_translated_address ta;
 
 	/* We try to load the last instruction.  We don't let
 	 * emulate_instruction do it as it doesn't check what
@@ -574,9 +575,10 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	 * a certain extent but we'll ignore it for now.
 	 */
 
-	vcpu->arch.paddr_accessed = gpa;
-	vcpu->arch.vaddr_accessed = ea;
-	return kvmppc_emulate_mmio(run, vcpu);
+	ta.eaddr = ea;
+	ta.raddr = gpa;
+	ta.is_store = !!is_store;
+	return kvmppc_emulate_mmio(run, vcpu, &ta);
 }
 
 int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index a5bde19..8ad0b33 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -183,132 +183,80 @@ static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
 static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				   int rs, ulong addr, int ls_type)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
-	char tmp[8];
+	int emulated;
 	int len = sizeof(u32);
 
 	if (ls_type = FPU_LS_DOUBLE)
 		len = sizeof(u64);
 
 	/* read from memory */
-	r = kvmppc_ld(vcpu, &addr, len, tmp, true);
-	vcpu->arch.paddr_accessed = addr;
-
-	if (r < 0) {
+	emulated = kvmppc_handle_load(run, vcpu, addr, NULL,
+				      KVM_MMIO_REG_FPR | rs, len, 1, 0);
+	if (emulated < 0) {
 		kvmppc_inject_pf(vcpu, addr, false);
-		goto done_load;
-	} else if (r = EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      len, 1, 0);
-		goto done_load;
-	}
-
-	emulated = EMULATE_DONE;
-
-	/* put in registers */
-	switch (ls_type) {
-	case FPU_LS_SINGLE:
-		kvm_cvt_fd((u32*)tmp, &VCPU_FPR(vcpu, rs));
-		vcpu->arch.qpr[rs] = *((u32*)tmp);
-		break;
-	case FPU_LS_DOUBLE:
-		VCPU_FPR(vcpu, rs) = *((u64*)tmp);
-		break;
+		emulated = EMULATE_FAIL;
 	}
 
-	dprintk(KERN_INFO "KVM: FPR_LD [0x%llx] at 0x%lx (%d)\n", *(u64*)tmp,
-			  addr, len);
-
-done_load:
 	return emulated;
 }
 
 static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				    int rs, ulong addr, int ls_type)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
-	char tmp[8];
+	int emulated;
+	u32 tmp;
 	u64 val;
 	int len;
 
 	switch (ls_type) {
 	case FPU_LS_SINGLE:
-		kvm_cvt_df(&VCPU_FPR(vcpu, rs), (u32*)tmp);
-		val = *((u32*)tmp);
+		kvm_cvt_df(&VCPU_FPR(vcpu, rs), &tmp);
+		val = tmp;
 		len = sizeof(u32);
 		break;
 	case FPU_LS_SINGLE_LOW:
-		*((u32*)tmp) = VCPU_FPR(vcpu, rs);
 		val = VCPU_FPR(vcpu, rs) & 0xffffffff;
 		len = sizeof(u32);
 		break;
 	case FPU_LS_DOUBLE:
-		*((u64*)tmp) = VCPU_FPR(vcpu, rs);
 		val = VCPU_FPR(vcpu, rs);
 		len = sizeof(u64);
 		break;
 	default:
-		val = 0;
-		len = 0;
+		return EMULATE_DONE;
 	}
 
-	r = kvmppc_st(vcpu, &addr, len, tmp, true);
-	vcpu->arch.paddr_accessed = addr;
-	if (r < 0) {
+	emulated = kvmppc_handle_store(run, vcpu, addr, NULL, val, len, 1);
+	if (emulated < 0) {
 		kvmppc_inject_pf(vcpu, addr, true);
-	} else if (r = EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_store(run, vcpu, val, len, 1);
-	} else {
-		emulated = EMULATE_DONE;
+		emulated = EMULATE_FAIL;
 	}
 
-	dprintk(KERN_INFO "KVM: FPR_ST [0x%llx] at 0x%lx (%d)\n",
-			  val, addr, len);
-
 	return emulated;
 }
 
 static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				   int rs, ulong addr, bool w, int i)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
-	float one = 1.0;
-	u32 tmp[2];
+	int emulated;
 
 	/* read from memory */
 	if (w) {
-		r = kvmppc_ld(vcpu, &addr, sizeof(u32), tmp, true);
-		memcpy(&tmp[1], &one, sizeof(u32));
+		emulated = kvmppc_handle_load(run, vcpu, addr, NULL,
+					      KVM_MMIO_REG_FPR | rs, 4, 1, 0);
+		
 	} else {
-		r = kvmppc_ld(vcpu, &addr, sizeof(u32) * 2, tmp, true);
+		emulated = kvmppc_handle_load(run, vcpu, addr, NULL,
+					      KVM_MMIO_REG_FQPR | rs, 8, 1, 0);
 	}
-	vcpu->arch.paddr_accessed = addr;
-	if (r < 0) {
+	if (emulated < 0) {
 		kvmppc_inject_pf(vcpu, addr, false);
-		goto done_load;
-	} else if ((r = EMULATE_DO_MMIO) && w) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
-					      4, 1, 0);
-		vcpu->arch.qpr[rs] = tmp[1];
-		goto done_load;
-	} else if (r = EMULATE_DO_MMIO) {
-		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
-					      8, 1, 0);
+		emulated = EMULATE_FAIL;
 		goto done_load;
 	}
 
 	emulated = EMULATE_DONE;
 
-	/* put in registers */
-	kvm_cvt_fd(&tmp[0], &VCPU_FPR(vcpu, rs));
-	vcpu->arch.qpr[rs] = tmp[1];
-
-	dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
-			  tmp[1], addr, w ? 4 : 8);
-
 done_load:
 	return emulated;
 }
@@ -316,29 +264,24 @@ done_load:
 static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				    int rs, ulong addr, bool w, int i)
 {
-	int emulated = EMULATE_FAIL;
-	int r;
+	int emulated;
 	u32 tmp[2];
-	int len = w ? sizeof(u32) : sizeof(u64);
 
 	kvm_cvt_df(&VCPU_FPR(vcpu, rs), &tmp[0]);
 	tmp[1] = vcpu->arch.qpr[rs];
 
-	r = kvmppc_st(vcpu, &addr, len, tmp, true);
-	vcpu->arch.paddr_accessed = addr;
-	if (r < 0) {
-		kvmppc_inject_pf(vcpu, addr, true);
-	} else if ((r = EMULATE_DO_MMIO) && w) {
-		emulated = kvmppc_handle_store(run, vcpu, tmp[0], 4, 1);
-	} else if (r = EMULATE_DO_MMIO) {
-		u64 val = ((u64)tmp[0] << 32) | tmp[1];
-		emulated = kvmppc_handle_store(run, vcpu, val, 8, 1);
+	if (w) {
+		emulated = kvmppc_handle_store(run, vcpu, addr, NULL,
+					       tmp[0], 4, 1);
 	} else {
-		emulated = EMULATE_DONE;
+		u64 val = ((u64)tmp[0] << 32) | tmp[1];
+		emulated = kvmppc_handle_store(run, vcpu, addr, NULL,
+					       val, 8, 1);
+	}
+	if (emulated < 0) {
+		kvmppc_inject_pf(vcpu, addr, true);
+		emulated = EMULATE_FAIL;
 	}
-
-	dprintk(KERN_INFO "KVM: PSQ_ST [0x%x, 0x%x] at 0x%lx (%d)\n",
-			  tmp[0], tmp[1], addr, len);
 
 	return emulated;
 }
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 29906af..98aa40a 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -539,6 +539,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	bool dr = (kvmppc_get_msr(vcpu) & MSR_DR) ? true : false;
 	bool ir = (kvmppc_get_msr(vcpu) & MSR_IR) ? true : false;
 	u64 vsid;
+	struct kvmppc_translated_address ta;
 
 	relocated = data ? dr : ir;
 	if (data && (vcpu->arch.fault_dsisr & DSISR_ISSTORE))
@@ -633,9 +634,10 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	} else {
 		/* MMIO */
 		vcpu->stat.mmio_exits++;
-		vcpu->arch.paddr_accessed = pte.raddr;
-		vcpu->arch.vaddr_accessed = pte.eaddr;
-		r = kvmppc_emulate_mmio(run, vcpu);
+		ta.eaddr = pte.eaddr;
+		ta.raddr = pte.raddr;
+		ta.is_store = iswrite;
+		r = kvmppc_emulate_mmio(run, vcpu, &ta);
 		if ( r = RESUME_HOST_NV )
 			r = RESUME_HOST;
 	}
@@ -856,7 +858,7 @@ static void kvmppc_emulate_fac(struct kvm_vcpu *vcpu, ulong fac)
 	enum emulation_result er = EMULATE_FAIL;
 
 	if (!(kvmppc_get_msr(vcpu) & MSR_PR))
-		er = kvmppc_emulate_instruction(vcpu->run, vcpu);
+		er = kvmppc_emulate_instruction(vcpu->run, vcpu, NULL);
 
 	if ((er != EMULATE_DONE) && (er != EMULATE_AGAIN)) {
 		/* Couldn't emulate, trigger interrupt in guest */
@@ -1071,7 +1073,7 @@ program_interrupt:
 		}
 
 		vcpu->stat.emulated_inst_exits++;
-		er = kvmppc_emulate_instruction(run, vcpu);
+		er = kvmppc_emulate_instruction(run, vcpu, NULL);
 		switch (er) {
 		case EMULATE_DONE:
 			r = RESUME_GUEST_NV;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index e62d09e..e5740db 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -695,7 +695,7 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
 	enum emulation_result er;
 
-	er = kvmppc_emulate_instruction(run, vcpu);
+	er = kvmppc_emulate_instruction(run, vcpu, NULL);
 	switch (er) {
 	case EMULATE_DONE:
 		/* don't overwrite subtypes, just account kvm_stats */
@@ -1068,9 +1068,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		} else {
 			/* Guest has mapped and accessed a page which is not
 			 * actually RAM. */
-			vcpu->arch.paddr_accessed = gpaddr;
-			vcpu->arch.vaddr_accessed = eaddr;
-			r = kvmppc_emulate_mmio(run, vcpu);
+			ta.eaddr = eaddr;
+			ta.raddr = gpaddr;
+			ta.is_store = true;
+			r = kvmppc_emulate_mmio(run, vcpu, &ta);
 			kvmppc_account_exit(vcpu, MMIO_EXITS);
 		}
 
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index 0e66230..a5dfd00 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -262,7 +262,8 @@ static enum emulation_result deliver_interrupt(struct kvm_vcpu *vcpu,
  * stmw
  *
  */
-int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
+int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			       struct kvmppc_translated_address *ta)
 {
 	u32 inst = kvmppc_get_last_inst(vcpu);
 	enum emulation_result emulated = EMULATE_DONE;
@@ -291,8 +292,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		break;
 
 	case LOAD:
-		/* address already in vcpu->arch.paddr_accessed */
-		emulated = kvmppc_handle_load(run, vcpu, op.reg,
+		emulated = kvmppc_handle_load(run, vcpu, op.ea, ta, op.reg,
 					      GETSIZE(op.type),
 					      !(op.type & BYTEREV),
 					      !!(op.type & SIGNEXT));
@@ -301,8 +301,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		break;
 
 	case STORE:
-		/* address already in vcpu->arch.paddr_accessed */
-		emulated = kvmppc_handle_store(run, vcpu, op.val,
+		emulated = kvmppc_handle_store(run, vcpu, op.ea, ta, op.val,
 					       GETSIZE(op.type), 1);
 		if (op.type & UPDATE)
 			kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 7e57ea9..d31b525 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -33,6 +33,7 @@
 #include <asm/tlbflush.h>
 #include <asm/cputhreads.h>
 #include <asm/irqflags.h>
+#include <asm/kvm_fpu.h>
 #include "timing.h"
 #include "irq.h"
 #include "../mm/mmu_decl.h"
@@ -268,12 +269,13 @@ out:
 }
 EXPORT_SYMBOL_GPL(kvmppc_sanity_check);
 
-int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
+int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			struct kvmppc_translated_address *ta)
 {
 	enum emulation_result er;
 	int r;
 
-	er = kvmppc_emulate_instruction(run, vcpu);
+	er = kvmppc_emulate_instruction(run, vcpu, ta);
 	switch (er) {
 	case EMULATE_DONE:
 		/* Future optimization: only reload non-volatiles if they were
@@ -662,34 +664,36 @@ static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,
 	kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, run->dcr.data);
 }
 
-static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
-                                      struct kvm_run *run)
+static void kvmppc_complete_load(struct kvm_vcpu *vcpu,
+				 u8 *data, int len, unsigned int io_gpr,
+				 bool is_bigendian, bool sign_extend)
 {
 	u64 uninitialized_var(gpr);
+	u32 val32;
 
-	if (run->mmio.len > sizeof(gpr)) {
-		printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len);
+	if (len > sizeof(gpr)) {
+		printk(KERN_ERR "bad MMIO length: %d\n", len);
 		return;
 	}
 
-	if (vcpu->arch.mmio_is_bigendian) {
-		switch (run->mmio.len) {
-		case 8: gpr = *(u64 *)run->mmio.data; break;
-		case 4: gpr = *(u32 *)run->mmio.data; break;
-		case 2: gpr = *(u16 *)run->mmio.data; break;
-		case 1: gpr = *(u8 *)run->mmio.data; break;
+	if (is_bigendian) {
+		switch (len) {
+		case 8: gpr = *(u64 *)data; break;
+		case 4: gpr = *(u32 *)data; break;
+		case 2: gpr = *(u16 *)data; break;
+		case 1: gpr = *(u8 *)data; break;
 		}
 	} else {
 		/* Convert BE data from userland back to LE. */
-		switch (run->mmio.len) {
-		case 4: gpr = ld_le32((u32 *)run->mmio.data); break;
-		case 2: gpr = ld_le16((u16 *)run->mmio.data); break;
-		case 1: gpr = *(u8 *)run->mmio.data; break;
+		switch (len) {
+		case 4: gpr = ld_le32((u32 *)data); break;
+		case 2: gpr = ld_le16((u16 *)data); break;
+		case 1: gpr = *(u8 *)data; break;
 		}
 	}
 
 	if (vcpu->arch.mmio_sign_extend) {
-		switch (run->mmio.len) {
+		switch (len) {
 #ifdef CONFIG_PPC64
 		case 4:
 			gpr = (s64)(s32)gpr;
@@ -704,22 +708,31 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 		}
 	}
 
-	kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
-
-	switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) {
+	switch (io_gpr & KVM_MMIO_REG_EXT_MASK) {
 	case KVM_MMIO_REG_GPR:
-		kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
+		kvmppc_set_gpr(vcpu, io_gpr, gpr);
 		break;
 	case KVM_MMIO_REG_FPR:
-		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
+		if (len = 4) {
+			val32 = gpr;
+			kvm_cvt_fd(&val32, &gpr);
+		}
+		VCPU_FPR(vcpu, io_gpr & KVM_MMIO_REG_MASK) = gpr;
 		break;
 #ifdef CONFIG_PPC_BOOK3S
 	case KVM_MMIO_REG_QPR:
-		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+		vcpu->arch.qpr[io_gpr & KVM_MMIO_REG_MASK] = gpr;
 		break;
 	case KVM_MMIO_REG_FQPR:
-		VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
-		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+		val32 = gpr >> 32;
+		kvm_cvt_fd(&val32, &gpr);
+		VCPU_FPR(vcpu, io_gpr & KVM_MMIO_REG_MASK) = gpr;
+		if (len = 4) {
+			float one = 1.0;
+			memcpy(&vcpu->arch.qpr[io_gpr & KVM_MMIO_REG_MASK],
+			       &one, sizeof(u32));
+		} else
+			vcpu->arch.qpr[io_gpr & KVM_MMIO_REG_MASK] = gpr;
 		break;
 #endif
 	default:
@@ -727,12 +740,24 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 	}
 }
 
+static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
+                                      struct kvm_run *run)
+{
+	kvmppc_complete_load(vcpu, run->mmio.data, run->mmio.len,
+			     vcpu->arch.io_gpr, vcpu->arch.mmio_is_bigendian,
+			     vcpu->arch.mmio_sign_extend);
+}
+
 int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+		       unsigned long ea, struct kvmppc_translated_address *ta,
 		       unsigned int rt, unsigned int bytes,
 		       int is_default_endian, int sign_extend)
 {
 	int idx, ret;
 	int is_bigendian;
+#ifdef CONFIG_PPC_BOOK3S
+	struct kvmppc_translated_address local_ta;
+#endif
 
 	if (kvmppc_need_byteswap(vcpu)) {
 		/* Default endianness is "little endian". */
@@ -742,12 +767,33 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		is_bigendian = is_default_endian;
 	}
 
+#ifdef CONFIG_PPC_BOOK3S
+	if (!ta || ea != ta->eaddr) {
+		unsigned long addr;
+		u8 buf[8];
+		int r;
+
+		addr = ea;
+		r = kvmppc_ld(vcpu, &addr, bytes, buf, true);
+		if (r != EMULATE_DO_MMIO) {
+			if (r >= 0)
+				kvmppc_complete_load(vcpu, buf, bytes, rt,
+						is_bigendian, sign_extend);
+			return r;
+		}
+		local_ta.eaddr = ea;
+		local_ta.raddr = addr;
+		local_ta.is_store = false;
+		ta = &local_ta;
+	}
+#endif
+
 	if (bytes > sizeof(run->mmio.data)) {
 		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
 		       run->mmio.len);
 	}
 
-	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
+	run->mmio.phys_addr = ta->raddr;
 	run->mmio.len = bytes;
 	run->mmio.is_write = 0;
 
@@ -775,11 +821,15 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 EXPORT_SYMBOL_GPL(kvmppc_handle_load);
 
 int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+			unsigned long ea, struct kvmppc_translated_address *ta,
 			u64 val, unsigned int bytes, int is_default_endian)
 {
 	void *data = run->mmio.data;
 	int idx, ret;
 	int is_bigendian;
+#ifdef CONFIG_PPC_BOOK3S
+	struct kvmppc_translated_address local_ta;
+#endif
 
 	if (kvmppc_need_byteswap(vcpu)) {
 		/* Default endianness is "little endian". */
@@ -794,12 +844,6 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		       run->mmio.len);
 	}
 
-	run->mmio.phys_addr = vcpu->arch.paddr_accessed;
-	run->mmio.len = bytes;
-	run->mmio.is_write = 1;
-	vcpu->mmio_needed = 1;
-	vcpu->mmio_is_write = 1;
-
 	/* Store the value at the lowest bytes in 'data'. */
 	if (is_bigendian) {
 		switch (bytes) {
@@ -817,6 +861,29 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		}
 	}
 
+#ifdef CONFIG_PPC_BOOK3S
+	if (!ta || ea != ta->eaddr || !ta->is_store) {
+		unsigned long addr;
+		int r;
+
+		addr = ea;
+		r = kvmppc_st(vcpu, &addr, bytes, data, true);
+		if (r != EMULATE_DO_MMIO)
+			return r;
+
+		local_ta.eaddr = ea;
+		local_ta.raddr = addr;
+		local_ta.is_store = true;
+		ta = &local_ta;
+	}
+#endif
+
+	run->mmio.phys_addr = ta->raddr;
+	run->mmio.len = bytes;
+	run->mmio.is_write = 1;
+	vcpu->mmio_needed = 1;
+	vcpu->mmio_is_write = 1;
+
 	idx = srcu_read_lock(&vcpu->kvm->srcu);
 
 	ret = kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr,
-- 
2.0.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 0/5] Improve PPC instruction emulation
  2014-07-19 10:14 ` Paul Mackerras
@ 2014-07-28 11:46   ` Alexander Graf
  -1 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 11:46 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> This series aims to increase the range of instructions that KVM on PPC
> can emulate and reduce code duplication by using the existing
> instruction emulation code from arch/powerpc/lib/sstep.c for KVM.
>
> The ultimate goal is to make PR KVM run faster on the kind of
> instruction sequences that we get in Linux's first-level interrupt
> handlers, where we have privileged instructions such as move to/from
> SPR, mtmsrd, rfid, etc., intermingled with ordinary unprivileged
> loads, stores, arithmetic instructions, etc.  If KVM could emulate
> those ordinary instructions as well as the privileged ones, we could
> emulate these code sequences without incurring the cost to exit and
> re-enter the guest for every single privileged instruction.  That
> would be a speedup provided the guest entry/exit cost was greater than
> the cost of emulating a few ordinary instructions.
>
> This series doesn't get to that ultimate goal but does lay the
> groundwork.  It splits the emulate_step() function into two parts,
> analyse_instr() and emulate_step(), and uses analyse_instr() in
> kvmppc_emulate_instruction().  This means that KVM needs to store its
> vcpu integer register state in a struct pt_regs like the rest of the
> kernel does.  We also need to make kvmppc_handle_load() and
> kvmppc_handle_store() handle loads and stores to ordinary guest memory
> as well as emulated MMIO.

Please take a look at my other patch set that implemented instruction 
emulation. There we split the code paths between MMIO emulation and 
normal instruction emulation.

I really think that approach is a prerequisite to doing full instruction 
emulation in longer code snippets. Obviously the generic load/store 
should then handle MMIO as well as generic memory operations.


Alex

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 0/5] Improve PPC instruction emulation
@ 2014-07-28 11:46   ` Alexander Graf
  0 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 11:46 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> This series aims to increase the range of instructions that KVM on PPC
> can emulate and reduce code duplication by using the existing
> instruction emulation code from arch/powerpc/lib/sstep.c for KVM.
>
> The ultimate goal is to make PR KVM run faster on the kind of
> instruction sequences that we get in Linux's first-level interrupt
> handlers, where we have privileged instructions such as move to/from
> SPR, mtmsrd, rfid, etc., intermingled with ordinary unprivileged
> loads, stores, arithmetic instructions, etc.  If KVM could emulate
> those ordinary instructions as well as the privileged ones, we could
> emulate these code sequences without incurring the cost to exit and
> re-enter the guest for every single privileged instruction.  That
> would be a speedup provided the guest entry/exit cost was greater than
> the cost of emulating a few ordinary instructions.
>
> This series doesn't get to that ultimate goal but does lay the
> groundwork.  It splits the emulate_step() function into two parts,
> analyse_instr() and emulate_step(), and uses analyse_instr() in
> kvmppc_emulate_instruction().  This means that KVM needs to store its
> vcpu integer register state in a struct pt_regs like the rest of the
> kernel does.  We also need to make kvmppc_handle_load() and
> kvmppc_handle_store() handle loads and stores to ordinary guest memory
> as well as emulated MMIO.

Please take a look at my other patch set that implemented instruction 
emulation. There we split the code paths between MMIO emulation and 
normal instruction emulation.

I really think that approach is a prerequisite to doing full instruction 
emulation in longer code snippets. Obviously the generic load/store 
should then handle MMIO as well as generic memory operations.


Alex


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 1/5] powerpc: Split out instruction analysis part of emulate_step()
  2014-07-19 10:14   ` Paul Mackerras
@ 2014-07-28 12:01     ` Alexander Graf
  -1 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 12:01 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> This splits out the instruction analysis part of emulate_step() into
> a separate analyse_instr() function, which decodes the instruction,
> but doesn't execute any load or store instructions.  It does execute
> integer instructions and branches which can be executed purely by
> updating register values in the pt_regs struct.  For other instructions,
> it returns the instruction type and other details in a new
> instruction_op struct.  emulate_step() then uses that information
> to execute loads, stores, cache operations, mfmsr, mtmsr[d], and
> (on 64-bit) sc instructions.
>
> Signed-off-by: Paul Mackerras <paulus@samba.org>

This should definitely get posted on the normal Linux PPC list.


Alex

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 1/5] powerpc: Split out instruction analysis part of emulate_step()
@ 2014-07-28 12:01     ` Alexander Graf
  0 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 12:01 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> This splits out the instruction analysis part of emulate_step() into
> a separate analyse_instr() function, which decodes the instruction,
> but doesn't execute any load or store instructions.  It does execute
> integer instructions and branches which can be executed purely by
> updating register values in the pt_regs struct.  For other instructions,
> it returns the instruction type and other details in a new
> instruction_op struct.  emulate_step() then uses that information
> to execute loads, stores, cache operations, mfmsr, mtmsr[d], and
> (on 64-bit) sc instructions.
>
> Signed-off-by: Paul Mackerras <paulus@samba.org>

This should definitely get posted on the normal Linux PPC list.


Alex


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 4/5] KVM: PPC: Use analyse_instr() in kvmppc_emulate_instruction()
  2014-07-19 10:14   ` Paul Mackerras
@ 2014-07-28 12:12     ` Alexander Graf
  -1 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 12:12 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> This changes kvmppc_emulate_instruction() to use the common instruction
> decoding code from arch/powerpc/lib/sstep.c.  This expands the set of
> instructions that we recognize to include all of the integer load and
> store instructions except for the string (lsw*, stsw*) and multiple
> (lmw, stmw) instructions and reduces the total amount of code.
>
> This removes kvmppc_handle_loads() and instead adds a 'sign_extend'
> parameter to kvmppc_handle_load().  (In fact kvmppc_handle_loads()
> could not have worked previously; it sets vcpu->arch.mmio_sign_extend
> to 1 before calling kvmppc_handle_load, which sets it back to 0.)
>
> The instruction emulation for specific CPU flavours is largely unchanged,
> except that emulation of mfmsr, eieio, and (for book 3S) mtmsr[d] has
> moved into the generic code, and tlbsync emulation into the CPU-specific
> code.
>
> At this point the code still assumes that the instruction caused the
> most recent guest exit, and that if the instruction is a load or store,
> it must have been an emulated MMIO access and vcpu->arch.paddr_accessed
> already contains the guest physical address being accessed.
>
> Signed-off-by: Paul Mackerras <paulus@samba.org>
> ---
>   arch/powerpc/include/asm/kvm_ppc.h       |   5 +-
>   arch/powerpc/kvm/book3s_emulate.c        |  22 +--
>   arch/powerpc/kvm/book3s_paired_singles.c |   6 +-
>   arch/powerpc/kvm/booke_emulate.c         |   8 +-
>   arch/powerpc/kvm/emulate.c               | 317 ++++++++++---------------------
>   arch/powerpc/kvm/powerpc.c               |  17 +-
>   6 files changed, 110 insertions(+), 265 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
> index 246fb9a..9318cf3 100644
> --- a/arch/powerpc/include/asm/kvm_ppc.h
> +++ b/arch/powerpc/include/asm/kvm_ppc.h
> @@ -54,10 +54,7 @@ extern void kvmppc_handler_highmem(void);
>   extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
>   extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
>                                 unsigned int rt, unsigned int bytes,
> -			      int is_default_endian);
> -extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
> -                               unsigned int rt, unsigned int bytes,
> -			       int is_default_endian);
> +			      int is_default_endian, int sign_extend);
>   extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			       u64 val, unsigned int bytes,
>   			       int is_default_endian);
> diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
> index 84fddcd..f74b8d5 100644
> --- a/arch/powerpc/kvm/book3s_emulate.c
> +++ b/arch/powerpc/kvm/book3s_emulate.c
> @@ -129,24 +129,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   		break;
>   	case 31:
>   		switch (get_xop(inst)) {
> -		case OP_31_XOP_MFMSR:
> -			kvmppc_set_gpr(vcpu, rt, kvmppc_get_msr(vcpu));
> -			break;
> -		case OP_31_XOP_MTMSRD:
> -		{
> -			ulong rs_val = kvmppc_get_gpr(vcpu, rs);
> -			if (inst & 0x10000) {
> -				ulong new_msr = kvmppc_get_msr(vcpu);
> -				new_msr &= ~(MSR_RI | MSR_EE);
> -				new_msr |= rs_val & (MSR_RI | MSR_EE);
> -				kvmppc_set_msr_fast(vcpu, new_msr);
> -			} else
> -				kvmppc_set_msr(vcpu, rs_val);
> -			break;
> -		}
> -		case OP_31_XOP_MTMSR:
> -			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
> -			break;
>   		case OP_31_XOP_MFSR:
>   		{
>   			int srnum;
> @@ -189,6 +171,8 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			vcpu->arch.mmu.tlbie(vcpu, addr, large);
>   			break;
>   		}
> +		case OP_31_XOP_TLBSYNC:
> +			break;
>   #ifdef CONFIG_PPC_BOOK3S_64
>   		case OP_31_XOP_FAKE_SC1:
>   		{
> @@ -217,8 +201,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			break;
>   		}
>   #endif
> -		case OP_31_XOP_EIOIO:
> -			break;
>   		case OP_31_XOP_SLBMTE:
>   			if (!vcpu->arch.mmu.slbmte)
>   				return EMULATE_FAIL;
> diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
> index 6c8011f..a5bde19 100644
> --- a/arch/powerpc/kvm/book3s_paired_singles.c
> +++ b/arch/powerpc/kvm/book3s_paired_singles.c
> @@ -200,7 +200,7 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   		goto done_load;
>   	} else if (r == EMULATE_DO_MMIO) {
>   		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
> -					      len, 1);
> +					      len, 1, 0);
>   		goto done_load;
>   	}
>   
> @@ -291,12 +291,12 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   		goto done_load;
>   	} else if ((r == EMULATE_DO_MMIO) && w) {
>   		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
> -					      4, 1);
> +					      4, 1, 0);
>   		vcpu->arch.qpr[rs] = tmp[1];
>   		goto done_load;
>   	} else if (r == EMULATE_DO_MMIO) {
>   		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
> -					      8, 1);
> +					      8, 1, 0);
>   		goto done_load;
>   	}
>   
> diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
> index 6bef2c7..81519b3 100644
> --- a/arch/powerpc/kvm/booke_emulate.c
> +++ b/arch/powerpc/kvm/booke_emulate.c
> @@ -74,11 +74,6 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   	case 31:
>   		switch (get_xop(inst)) {
>   
> -		case OP_31_XOP_MFMSR:
> -			kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr);
> -			kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
> -			break;
> -
>   		case OP_31_XOP_MTMSR:
>   			kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
>   			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
> @@ -96,6 +91,9 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
>   			break;
>   
> +		case OP_31_XOP_TLBSYNC:
> +			break;
> +
>   		default:
>   			emulated = EMULATE_FAIL;
>   		}
> diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
> index da86d9b..0e66230 100644
> --- a/arch/powerpc/kvm/emulate.c
> +++ b/arch/powerpc/kvm/emulate.c
> @@ -31,6 +31,7 @@

[...]

> -	case OP_LHAU:
> -		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
> -		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
> +	case MFMSR:
> +		kvmppc_set_gpr(vcpu, op.reg, kvmppc_get_msr(vcpu));
> +		kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
>   		break;
>   
> -	case OP_STH:
> -		emulated = kvmppc_handle_store(run, vcpu,
> -					       kvmppc_get_gpr(vcpu, rs),
> -		                               2, 1);
> +#ifdef CONFIG_PPC_BOOK3S

Why can't we handle this in the book3s emulation file? We could just 
pass op into it, no?


Alex

> +	case MTMSR:
> +		val = kvmppc_get_gpr(vcpu, op.reg);
> +		val = (val & op.val) | (kvmppc_get_msr(vcpu) & ~op.val);
> +		kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
> +		kvmppc_set_msr(vcpu, val);
>   		break;
> +#endif
>   


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 4/5] KVM: PPC: Use analyse_instr() in kvmppc_emulate_instruction()
@ 2014-07-28 12:12     ` Alexander Graf
  0 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 12:12 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> This changes kvmppc_emulate_instruction() to use the common instruction
> decoding code from arch/powerpc/lib/sstep.c.  This expands the set of
> instructions that we recognize to include all of the integer load and
> store instructions except for the string (lsw*, stsw*) and multiple
> (lmw, stmw) instructions and reduces the total amount of code.
>
> This removes kvmppc_handle_loads() and instead adds a 'sign_extend'
> parameter to kvmppc_handle_load().  (In fact kvmppc_handle_loads()
> could not have worked previously; it sets vcpu->arch.mmio_sign_extend
> to 1 before calling kvmppc_handle_load, which sets it back to 0.)
>
> The instruction emulation for specific CPU flavours is largely unchanged,
> except that emulation of mfmsr, eieio, and (for book 3S) mtmsr[d] has
> moved into the generic code, and tlbsync emulation into the CPU-specific
> code.
>
> At this point the code still assumes that the instruction caused the
> most recent guest exit, and that if the instruction is a load or store,
> it must have been an emulated MMIO access and vcpu->arch.paddr_accessed
> already contains the guest physical address being accessed.
>
> Signed-off-by: Paul Mackerras <paulus@samba.org>
> ---
>   arch/powerpc/include/asm/kvm_ppc.h       |   5 +-
>   arch/powerpc/kvm/book3s_emulate.c        |  22 +--
>   arch/powerpc/kvm/book3s_paired_singles.c |   6 +-
>   arch/powerpc/kvm/booke_emulate.c         |   8 +-
>   arch/powerpc/kvm/emulate.c               | 317 ++++++++++---------------------
>   arch/powerpc/kvm/powerpc.c               |  17 +-
>   6 files changed, 110 insertions(+), 265 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
> index 246fb9a..9318cf3 100644
> --- a/arch/powerpc/include/asm/kvm_ppc.h
> +++ b/arch/powerpc/include/asm/kvm_ppc.h
> @@ -54,10 +54,7 @@ extern void kvmppc_handler_highmem(void);
>   extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
>   extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
>                                 unsigned int rt, unsigned int bytes,
> -			      int is_default_endian);
> -extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
> -                               unsigned int rt, unsigned int bytes,
> -			       int is_default_endian);
> +			      int is_default_endian, int sign_extend);
>   extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			       u64 val, unsigned int bytes,
>   			       int is_default_endian);
> diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
> index 84fddcd..f74b8d5 100644
> --- a/arch/powerpc/kvm/book3s_emulate.c
> +++ b/arch/powerpc/kvm/book3s_emulate.c
> @@ -129,24 +129,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   		break;
>   	case 31:
>   		switch (get_xop(inst)) {
> -		case OP_31_XOP_MFMSR:
> -			kvmppc_set_gpr(vcpu, rt, kvmppc_get_msr(vcpu));
> -			break;
> -		case OP_31_XOP_MTMSRD:
> -		{
> -			ulong rs_val = kvmppc_get_gpr(vcpu, rs);
> -			if (inst & 0x10000) {
> -				ulong new_msr = kvmppc_get_msr(vcpu);
> -				new_msr &= ~(MSR_RI | MSR_EE);
> -				new_msr |= rs_val & (MSR_RI | MSR_EE);
> -				kvmppc_set_msr_fast(vcpu, new_msr);
> -			} else
> -				kvmppc_set_msr(vcpu, rs_val);
> -			break;
> -		}
> -		case OP_31_XOP_MTMSR:
> -			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
> -			break;
>   		case OP_31_XOP_MFSR:
>   		{
>   			int srnum;
> @@ -189,6 +171,8 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			vcpu->arch.mmu.tlbie(vcpu, addr, large);
>   			break;
>   		}
> +		case OP_31_XOP_TLBSYNC:
> +			break;
>   #ifdef CONFIG_PPC_BOOK3S_64
>   		case OP_31_XOP_FAKE_SC1:
>   		{
> @@ -217,8 +201,6 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			break;
>   		}
>   #endif
> -		case OP_31_XOP_EIOIO:
> -			break;
>   		case OP_31_XOP_SLBMTE:
>   			if (!vcpu->arch.mmu.slbmte)
>   				return EMULATE_FAIL;
> diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
> index 6c8011f..a5bde19 100644
> --- a/arch/powerpc/kvm/book3s_paired_singles.c
> +++ b/arch/powerpc/kvm/book3s_paired_singles.c
> @@ -200,7 +200,7 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   		goto done_load;
>   	} else if (r = EMULATE_DO_MMIO) {
>   		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
> -					      len, 1);
> +					      len, 1, 0);
>   		goto done_load;
>   	}
>   
> @@ -291,12 +291,12 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   		goto done_load;
>   	} else if ((r = EMULATE_DO_MMIO) && w) {
>   		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
> -					      4, 1);
> +					      4, 1, 0);
>   		vcpu->arch.qpr[rs] = tmp[1];
>   		goto done_load;
>   	} else if (r = EMULATE_DO_MMIO) {
>   		emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
> -					      8, 1);
> +					      8, 1, 0);
>   		goto done_load;
>   	}
>   
> diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
> index 6bef2c7..81519b3 100644
> --- a/arch/powerpc/kvm/booke_emulate.c
> +++ b/arch/powerpc/kvm/booke_emulate.c
> @@ -74,11 +74,6 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   	case 31:
>   		switch (get_xop(inst)) {
>   
> -		case OP_31_XOP_MFMSR:
> -			kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr);
> -			kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
> -			break;
> -
>   		case OP_31_XOP_MTMSR:
>   			kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
>   			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs));
> @@ -96,6 +91,9 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
>   			kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
>   			break;
>   
> +		case OP_31_XOP_TLBSYNC:
> +			break;
> +
>   		default:
>   			emulated = EMULATE_FAIL;
>   		}
> diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
> index da86d9b..0e66230 100644
> --- a/arch/powerpc/kvm/emulate.c
> +++ b/arch/powerpc/kvm/emulate.c
> @@ -31,6 +31,7 @@

[...]

> -	case OP_LHAU:
> -		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
> -		kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
> +	case MFMSR:
> +		kvmppc_set_gpr(vcpu, op.reg, kvmppc_get_msr(vcpu));
> +		kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
>   		break;
>   
> -	case OP_STH:
> -		emulated = kvmppc_handle_store(run, vcpu,
> -					       kvmppc_get_gpr(vcpu, rs),
> -		                               2, 1);
> +#ifdef CONFIG_PPC_BOOK3S

Why can't we handle this in the book3s emulation file? We could just 
pass op into it, no?


Alex

> +	case MTMSR:
> +		val = kvmppc_get_gpr(vcpu, op.reg);
> +		val = (val & op.val) | (kvmppc_get_msr(vcpu) & ~op.val);
> +		kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS);
> +		kvmppc_set_msr(vcpu, val);
>   		break;
> +#endif
>   


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 5/5] KVM: PPC: Book3S: Make kvmppc_handle_load/store handle any load or store
  2014-07-19 10:14   ` Paul Mackerras
@ 2014-07-28 12:14     ` Alexander Graf
  -1 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 12:14 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> At present, kvmppc_handle_load and kvmppc_handle_store only handle
> emulated MMIO loads and stores.  This extends them to be able to handle
> loads and stores to guest memory as well.  This is so that
> kvmppc_emulate_instruction can be used to emulate loads and stores
> in cases other than when an attempt to execute the instruction by the
> CPU has resulted in an interrupt.
>
> To avoid having to look up the translation for the effective address
> again in kvmppc_handle_load/store when the caller of kvmppc_emulate_mmio
> has already done it, we arrange to pass down the translation in a new
> struct kvmppc_translated_address, which is a new argument to
> kvmppc_emulate_mmio() and kvmppc_emulate_instruction().  This also
> enables us to check that the guest hasn't replaced a load with a store
> instruction.
>
> This also makes the register updates for the paired-single FPU registers
> match for emulated MMIO accesses what is done for accesses to normal
> memory.
>
> The new code for accessing normal guest memory uses kvmppc_ld and kvmppc_st,
> which call kvmppc_xlate, which is only defined for Book 3S.  For Book E,
> kvmppc_handle_load/store still only work for emulated MMIO.
>
> Signed-off-by: Paul Mackerras <paulus@samba.org>

Please check out my other patch set where I made kvmppc_ld/st available 
for BookE and also split the MMIO path off completely. Since we do want 
to take the shortcut through paddr that we only know for memory traps, I 
really think we're better off treating that whole optimized code path as 
a separate piece.


Alex

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC PATCH 5/5] KVM: PPC: Book3S: Make kvmppc_handle_load/store handle any load or store
@ 2014-07-28 12:14     ` Alexander Graf
  0 siblings, 0 replies; 20+ messages in thread
From: Alexander Graf @ 2014-07-28 12:14 UTC (permalink / raw)
  To: Paul Mackerras, kvm-ppc; +Cc: kvm


On 19.07.14 12:14, Paul Mackerras wrote:
> At present, kvmppc_handle_load and kvmppc_handle_store only handle
> emulated MMIO loads and stores.  This extends them to be able to handle
> loads and stores to guest memory as well.  This is so that
> kvmppc_emulate_instruction can be used to emulate loads and stores
> in cases other than when an attempt to execute the instruction by the
> CPU has resulted in an interrupt.
>
> To avoid having to look up the translation for the effective address
> again in kvmppc_handle_load/store when the caller of kvmppc_emulate_mmio
> has already done it, we arrange to pass down the translation in a new
> struct kvmppc_translated_address, which is a new argument to
> kvmppc_emulate_mmio() and kvmppc_emulate_instruction().  This also
> enables us to check that the guest hasn't replaced a load with a store
> instruction.
>
> This also makes the register updates for the paired-single FPU registers
> match for emulated MMIO accesses what is done for accesses to normal
> memory.
>
> The new code for accessing normal guest memory uses kvmppc_ld and kvmppc_st,
> which call kvmppc_xlate, which is only defined for Book 3S.  For Book E,
> kvmppc_handle_load/store still only work for emulated MMIO.
>
> Signed-off-by: Paul Mackerras <paulus@samba.org>

Please check out my other patch set where I made kvmppc_ld/st available 
for BookE and also split the MMIO path off completely. Since we do want 
to take the shortcut through paddr that we only know for memory traps, I 
really think we're better off treating that whole optimized code path as 
a separate piece.


Alex


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2014-07-28 12:14 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-19 10:14 [RFC PATCH 0/5] Improve PPC instruction emulation Paul Mackerras
2014-07-19 10:14 ` Paul Mackerras
2014-07-19 10:14 ` [RFC PATCH 1/5] powerpc: Split out instruction analysis part of emulate_step() Paul Mackerras
2014-07-19 10:14   ` Paul Mackerras
2014-07-28 12:01   ` Alexander Graf
2014-07-28 12:01     ` Alexander Graf
2014-07-19 10:14 ` [RFC PATCH 2/5] powerpc: Implement emulation of string loads and stores Paul Mackerras
2014-07-19 10:14   ` Paul Mackerras
2014-07-19 10:14 ` [RFC PATCH 3/5] KVM: PPC: Use pt_regs struct for integer registers in struct vcpu_arch Paul Mackerras
2014-07-19 10:14   ` Paul Mackerras
2014-07-19 10:14 ` [RFC PATCH 4/5] KVM: PPC: Use analyse_instr() in kvmppc_emulate_instruction() Paul Mackerras
2014-07-19 10:14   ` Paul Mackerras
2014-07-28 12:12   ` Alexander Graf
2014-07-28 12:12     ` Alexander Graf
2014-07-19 10:14 ` [RFC PATCH 5/5] KVM: PPC: Book3S: Make kvmppc_handle_load/store handle any load or store Paul Mackerras
2014-07-19 10:14   ` Paul Mackerras
2014-07-28 12:14   ` Alexander Graf
2014-07-28 12:14     ` Alexander Graf
2014-07-28 11:46 ` [RFC PATCH 0/5] Improve PPC instruction emulation Alexander Graf
2014-07-28 11:46   ` Alexander Graf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.