diff mbox

[06/11] KVM: PPC: Book3S HV: Support POWER6 compatibility mode on POWER7

Message ID 20130906032250.GG29710@iris.ozlabs.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Paul Mackerras Sept. 6, 2013, 3:22 a.m. UTC
This enables us to use the Processor Compatibility Register (PCR) on
POWER7 to put the processor into architecture 2.05 compatibility mode
when running a guest.  In this mode the new instructions and registers
that were introduced on POWER7 are disabled in user mode.  This
includes all the VSX facilities plus several other instructions such
as ldbrx, stdbrx, popcntw, popcntd, etc.

To select this mode, we have a new register accessible through the
set/get_one_reg interface, called KVM_REG_PPC_ARCH_COMPAT.  Setting
this to zero gives the full set of capabilities of the processor.
Setting it to one of the "logical" PVR values defined in PAPR puts
the vcpu into the compatibility mode for the corresponding
architecture level.  The supported values are:

0x0f000002	Architecture 2.05 (POWER6)
0x0f000003	Architecture 2.06 (POWER7)
0x0f100003	Architecture 2.06+ (POWER7+)

Since the PCR is per-core, the architecture compatibility level and
the corresponding PCR value are stored in the struct kvmppc_vcore, and
are therefore shared between all vcpus in a virtual core.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 Documentation/virtual/kvm/api.txt       |  1 +
 arch/powerpc/include/asm/kvm_host.h     |  2 ++
 arch/powerpc/include/asm/reg.h          | 11 +++++++++++
 arch/powerpc/include/uapi/asm/kvm.h     |  3 +++
 arch/powerpc/kernel/asm-offsets.c       |  1 +
 arch/powerpc/kvm/book3s_hv.c            | 35 +++++++++++++++++++++++++++++++++
 arch/powerpc/kvm/book3s_hv_rmhandlers.S | 11 +++++++++--
 7 files changed, 62 insertions(+), 2 deletions(-)

Comments

Aneesh Kumar K.V Sept. 6, 2013, 5:28 a.m. UTC | #1
Paul Mackerras <paulus@samba.org> writes:

> This enables us to use the Processor Compatibility Register (PCR) on
> POWER7 to put the processor into architecture 2.05 compatibility mode
> when running a guest.  In this mode the new instructions and registers
> that were introduced on POWER7 are disabled in user mode.  This
> includes all the VSX facilities plus several other instructions such
> as ldbrx, stdbrx, popcntw, popcntd, etc.
>
> To select this mode, we have a new register accessible through the
> set/get_one_reg interface, called KVM_REG_PPC_ARCH_COMPAT.  Setting
> this to zero gives the full set of capabilities of the processor.
> Setting it to one of the "logical" PVR values defined in PAPR puts
> the vcpu into the compatibility mode for the corresponding
> architecture level.  The supported values are:
>
> 0x0f000002	Architecture 2.05 (POWER6)
> 0x0f000003	Architecture 2.06 (POWER7)
> 0x0f100003	Architecture 2.06+ (POWER7+)
>
> Since the PCR is per-core, the architecture compatibility level and
> the corresponding PCR value are stored in the struct kvmppc_vcore, and
> are therefore shared between all vcpus in a virtual core.

We already have KVM_SET_SREGS taking pvr as argument. Can't we do
this kvmppc_set_pvr ?. Can you also share the qemu changes ? There I
guess we need to do update the "cpu-version" in the device tree so
that /proc/cpuinfo shows the right information in the guest 


-aneesh

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paul Mackerras Sept. 6, 2013, 6:38 a.m. UTC | #2
On Fri, Sep 06, 2013 at 10:58:16AM +0530, Aneesh Kumar K.V wrote:
> Paul Mackerras <paulus@samba.org> writes:
> 
> > This enables us to use the Processor Compatibility Register (PCR) on
> > POWER7 to put the processor into architecture 2.05 compatibility mode
> > when running a guest.  In this mode the new instructions and registers
> > that were introduced on POWER7 are disabled in user mode.  This
> > includes all the VSX facilities plus several other instructions such
> > as ldbrx, stdbrx, popcntw, popcntd, etc.
> >
> > To select this mode, we have a new register accessible through the
> > set/get_one_reg interface, called KVM_REG_PPC_ARCH_COMPAT.  Setting
> > this to zero gives the full set of capabilities of the processor.
> > Setting it to one of the "logical" PVR values defined in PAPR puts
> > the vcpu into the compatibility mode for the corresponding
> > architecture level.  The supported values are:
> >
> > 0x0f000002	Architecture 2.05 (POWER6)
> > 0x0f000003	Architecture 2.06 (POWER7)
> > 0x0f100003	Architecture 2.06+ (POWER7+)
> >
> > Since the PCR is per-core, the architecture compatibility level and
> > the corresponding PCR value are stored in the struct kvmppc_vcore, and
> > are therefore shared between all vcpus in a virtual core.
> 
> We already have KVM_SET_SREGS taking pvr as argument. Can't we do
> this kvmppc_set_pvr ?. Can you also share the qemu changes ? There I
> guess we need to do update the "cpu-version" in the device tree so
> that /proc/cpuinfo shows the right information in the guest 

The discussion on the qemu mailing list pointed out that we aren't
really changing the PVR; the guest still sees the real PVR, and what
we're doing is setting a mode of the CPU rather than changing it into
an older CPU.  So, it seemed better to use something separate from the
PVR.  Also, if we used the pvr setting to convey this information,
then apparently under TCG the guest would see the logical PVR value if
it read the (apparently) real PVR.

Alexey is working on the relevant QEMU patches.

Paul.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexander Graf Sept. 13, 2013, 7:58 p.m. UTC | #3
On 05.09.2013, at 22:22, Paul Mackerras wrote:

> This enables us to use the Processor Compatibility Register (PCR) on
> POWER7 to put the processor into architecture 2.05 compatibility mode
> when running a guest.  In this mode the new instructions and registers
> that were introduced on POWER7 are disabled in user mode.  This
> includes all the VSX facilities plus several other instructions such
> as ldbrx, stdbrx, popcntw, popcntd, etc.
> 
> To select this mode, we have a new register accessible through the
> set/get_one_reg interface, called KVM_REG_PPC_ARCH_COMPAT.  Setting
> this to zero gives the full set of capabilities of the processor.
> Setting it to one of the "logical" PVR values defined in PAPR puts
> the vcpu into the compatibility mode for the corresponding
> architecture level.  The supported values are:
> 
> 0x0f000002	Architecture 2.05 (POWER6)
> 0x0f000003	Architecture 2.06 (POWER7)
> 0x0f100003	Architecture 2.06+ (POWER7+)
> 
> Since the PCR is per-core, the architecture compatibility level and
> the corresponding PCR value are stored in the struct kvmppc_vcore, and
> are therefore shared between all vcpus in a virtual core.
> 
> Signed-off-by: Paul Mackerras <paulus@samba.org>
> ---
> Documentation/virtual/kvm/api.txt       |  1 +
> arch/powerpc/include/asm/kvm_host.h     |  2 ++
> arch/powerpc/include/asm/reg.h          | 11 +++++++++++
> arch/powerpc/include/uapi/asm/kvm.h     |  3 +++
> arch/powerpc/kernel/asm-offsets.c       |  1 +
> arch/powerpc/kvm/book3s_hv.c            | 35 +++++++++++++++++++++++++++++++++
> arch/powerpc/kvm/book3s_hv_rmhandlers.S | 11 +++++++++--
> 7 files changed, 62 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 34a32b6..f1f300f 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -1837,6 +1837,7 @@ registers, find a list below:
>   PPC   | KVM_REG_PPC_VRSAVE	| 32
>   PPC   | KVM_REG_PPC_LPCR	| 64
>   PPC   | KVM_REG_PPC_PPR	| 64
> +  PPC   | KVM_REG_PPC_ARCH_COMPAT | 32
>   PPC   | KVM_REG_PPC_TM_GPR0	| 64
>           ...
>   PPC   | KVM_REG_PPC_TM_GPR31	| 64
> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
> index b0dcd18..5a40270 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -295,6 +295,8 @@ struct kvmppc_vcore {
> 	u64 preempt_tb;
> 	struct kvm_vcpu *runner;
> 	u64 tb_offset;		/* guest timebase - host timebase */
> +	u32 arch_compat;
> +	ulong pcr;
> };
> 
> #define VCORE_ENTRY_COUNT(vc)	((vc)->entry_exit_count & 0xff)
> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
> index 3fc0d06..52ff962 100644
> --- a/arch/powerpc/include/asm/reg.h
> +++ b/arch/powerpc/include/asm/reg.h
> @@ -305,6 +305,10 @@
> #define   LPID_RSVD	0x3ff		/* Reserved LPID for partn switching */
> #define	SPRN_HMER	0x150	/* Hardware m? error recovery */
> #define	SPRN_HMEER	0x151	/* Hardware m? enable error recovery */
> +#define SPRN_PCR	0x152	/* Processor compatibility register */
> +#define   PCR_VEC_DIS	(1ul << (63-0))	/* Vec. disable (pre POWER8) */
> +#define   PCR_VSX_DIS	(1ul << (63-1))	/* VSX disable (pre POWER8) */
> +#define   PCR_ARCH_205	0x2		/* Architecture 2.05 */
> #define	SPRN_HEIR	0x153	/* Hypervisor Emulated Instruction Register */
> #define SPRN_TLBINDEXR	0x154	/* P7 TLB control register */
> #define SPRN_TLBVPNR	0x155	/* P7 TLB control register */
> @@ -1095,6 +1099,13 @@
> #define PVR_BE		0x0070
> #define PVR_PA6T	0x0090
> 
> +/* "Logical" PVR values defined in PAPR, representing architecture levels */
> +#define PVR_ARCH_204	0x0f000001
> +#define PVR_ARCH_205	0x0f000002
> +#define PVR_ARCH_206	0x0f000003
> +#define PVR_ARCH_206p	0x0f100003
> +#define PVR_ARCH_207	0x0f000004
> +
> /* Macros for setting and retrieving special purpose registers */
> #ifndef __ASSEMBLY__
> #define mfmsr()		({unsigned long rval; \
> diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
> index fab6bc1..e420d46 100644
> --- a/arch/powerpc/include/uapi/asm/kvm.h
> +++ b/arch/powerpc/include/uapi/asm/kvm.h
> @@ -536,6 +536,9 @@ struct kvm_get_htab_header {
> #define KVM_REG_PPC_LPCR	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
> #define KVM_REG_PPC_PPR		(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6)
> 
> +/* Architecture compatibility level */
> +#define KVM_REG_PPC_ARCH_COMPAT	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
> +
> /* Transactional Memory checkpointed state:
>  * This is all GPRs, all VSX regs and a subset of SPRs
>  */
> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
> index 5c6ea96..115dd64 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -522,6 +522,7 @@ int main(void)
> 	DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
> 	DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
> 	DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset));
> +	DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr));
> 	DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) -
> 			   offsetof(struct kvmppc_vcpu_book3s, vcpu));
> 	DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index eceff7e..1a10afa 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -166,6 +166,35 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
> 	vcpu->arch.pvr = pvr;
> }
> 
> +int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
> +{
> +	unsigned long pcr = 0;
> +	struct kvmppc_vcore *vc = vcpu->arch.vcore;
> +
> +	if (arch_compat) {
> +		if (!cpu_has_feature(CPU_FTR_ARCH_206))
> +			return -EINVAL;	/* 970 has no compat mode support */
> +
> +		switch (arch_compat) {
> +		case PVR_ARCH_205:
> +			pcr = PCR_ARCH_205;
> +			break;
> +		case PVR_ARCH_206:
> +		case PVR_ARCH_206p:
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +
> +	spin_lock(&vc->lock);
> +	vc->arch_compat = arch_compat;
> +	vc->pcr = pcr;
> +	spin_unlock(&vc->lock);
> +
> +	return 0;
> +}
> +
> void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
> {
> 	int r;
> @@ -817,6 +846,9 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
> 	case KVM_REG_PPC_PPR:
> 		*val = get_reg_val(id, vcpu->arch.ppr);
> 		break;
> +	case KVM_REG_PPC_ARCH_COMPAT:
> +		*val = get_reg_val(id, vcpu->arch.vcore->arch_compat);
> +		break;
> 	default:
> 		r = -EINVAL;
> 		break;
> @@ -927,6 +959,9 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
> 	case KVM_REG_PPC_PPR:
> 		vcpu->arch.ppr = set_reg_val(id, *val);
> 		break;
> +	case KVM_REG_PPC_ARCH_COMPAT:
> +		r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val));
> +		break;
> 	default:
> 		r = -EINVAL;
> 		break;
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index 88e7068..023d8600 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -358,7 +358,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
> 	addis	r8,r8,0x100	/* if so, increment upper 40 bits */
> 	mtspr	SPRN_TBU40,r8
> 
> -37:	li	r0,1
> +	/* Load guest PCR value to select appropriate compat mode */
> +37:	ld	r7, VCORE_PCR(r5)
> +	mtspr	SPRN_PCR, r7
> +
> +	li	r0,1
> 	stb	r0,VCORE_IN_GUEST(r5)	/* signal secondaries to continue */
> 	b	10f
> 
> @@ -984,8 +988,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
> 	addis	r8,r8,0x100		/* if so, increment upper 40 bits */
> 	mtspr	SPRN_TBU40,r8
> 
> -	/* Signal secondary CPUs to continue */
> +	/* Reset PCR */
> 17:	li	r0,0
> +	mtspr	SPRN_PCR,r0

How long does writing to PCR take? Is it faster than a load+branch to see whether we actually need it? I would assume the normal fast path is going to be guest cpu == host.


Alex

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paul Mackerras Sept. 14, 2013, 2:03 a.m. UTC | #4
On Fri, Sep 13, 2013 at 02:58:43PM -0500, Alexander Graf wrote:
> 
> How long does writing to PCR take? Is it faster than a load+branch to see whether we actually need it? I would assume the normal fast path is going to be guest cpu == host.

Seems to be about 30 cycles to write PCR, so a compare and branch is
faster.  I'll change it.

Paul.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 34a32b6..f1f300f 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1837,6 +1837,7 @@  registers, find a list below:
   PPC   | KVM_REG_PPC_VRSAVE	| 32
   PPC   | KVM_REG_PPC_LPCR	| 64
   PPC   | KVM_REG_PPC_PPR	| 64
+  PPC   | KVM_REG_PPC_ARCH_COMPAT | 32
   PPC   | KVM_REG_PPC_TM_GPR0	| 64
           ...
   PPC   | KVM_REG_PPC_TM_GPR31	| 64
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index b0dcd18..5a40270 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -295,6 +295,8 @@  struct kvmppc_vcore {
 	u64 preempt_tb;
 	struct kvm_vcpu *runner;
 	u64 tb_offset;		/* guest timebase - host timebase */
+	u32 arch_compat;
+	ulong pcr;
 };
 
 #define VCORE_ENTRY_COUNT(vc)	((vc)->entry_exit_count & 0xff)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 3fc0d06..52ff962 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -305,6 +305,10 @@ 
 #define   LPID_RSVD	0x3ff		/* Reserved LPID for partn switching */
 #define	SPRN_HMER	0x150	/* Hardware m? error recovery */
 #define	SPRN_HMEER	0x151	/* Hardware m? enable error recovery */
+#define SPRN_PCR	0x152	/* Processor compatibility register */
+#define   PCR_VEC_DIS	(1ul << (63-0))	/* Vec. disable (pre POWER8) */
+#define   PCR_VSX_DIS	(1ul << (63-1))	/* VSX disable (pre POWER8) */
+#define   PCR_ARCH_205	0x2		/* Architecture 2.05 */
 #define	SPRN_HEIR	0x153	/* Hypervisor Emulated Instruction Register */
 #define SPRN_TLBINDEXR	0x154	/* P7 TLB control register */
 #define SPRN_TLBVPNR	0x155	/* P7 TLB control register */
@@ -1095,6 +1099,13 @@ 
 #define PVR_BE		0x0070
 #define PVR_PA6T	0x0090
 
+/* "Logical" PVR values defined in PAPR, representing architecture levels */
+#define PVR_ARCH_204	0x0f000001
+#define PVR_ARCH_205	0x0f000002
+#define PVR_ARCH_206	0x0f000003
+#define PVR_ARCH_206p	0x0f100003
+#define PVR_ARCH_207	0x0f000004
+
 /* Macros for setting and retrieving special purpose registers */
 #ifndef __ASSEMBLY__
 #define mfmsr()		({unsigned long rval; \
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index fab6bc1..e420d46 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -536,6 +536,9 @@  struct kvm_get_htab_header {
 #define KVM_REG_PPC_LPCR	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
 #define KVM_REG_PPC_PPR		(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6)
 
+/* Architecture compatibility level */
+#define KVM_REG_PPC_ARCH_COMPAT	(KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
+
 /* Transactional Memory checkpointed state:
  * This is all GPRs, all VSX regs and a subset of SPRs
  */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 5c6ea96..115dd64 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -522,6 +522,7 @@  int main(void)
 	DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
 	DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
 	DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset));
+	DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr));
 	DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) -
 			   offsetof(struct kvmppc_vcpu_book3s, vcpu));
 	DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index eceff7e..1a10afa 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -166,6 +166,35 @@  void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
 	vcpu->arch.pvr = pvr;
 }
 
+int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
+{
+	unsigned long pcr = 0;
+	struct kvmppc_vcore *vc = vcpu->arch.vcore;
+
+	if (arch_compat) {
+		if (!cpu_has_feature(CPU_FTR_ARCH_206))
+			return -EINVAL;	/* 970 has no compat mode support */
+
+		switch (arch_compat) {
+		case PVR_ARCH_205:
+			pcr = PCR_ARCH_205;
+			break;
+		case PVR_ARCH_206:
+		case PVR_ARCH_206p:
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	spin_lock(&vc->lock);
+	vc->arch_compat = arch_compat;
+	vc->pcr = pcr;
+	spin_unlock(&vc->lock);
+
+	return 0;
+}
+
 void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
 {
 	int r;
@@ -817,6 +846,9 @@  int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
 	case KVM_REG_PPC_PPR:
 		*val = get_reg_val(id, vcpu->arch.ppr);
 		break;
+	case KVM_REG_PPC_ARCH_COMPAT:
+		*val = get_reg_val(id, vcpu->arch.vcore->arch_compat);
+		break;
 	default:
 		r = -EINVAL;
 		break;
@@ -927,6 +959,9 @@  int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
 	case KVM_REG_PPC_PPR:
 		vcpu->arch.ppr = set_reg_val(id, *val);
 		break;
+	case KVM_REG_PPC_ARCH_COMPAT:
+		r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val));
+		break;
 	default:
 		r = -EINVAL;
 		break;
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 88e7068..023d8600 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -358,7 +358,11 @@  END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
 	addis	r8,r8,0x100	/* if so, increment upper 40 bits */
 	mtspr	SPRN_TBU40,r8
 
-37:	li	r0,1
+	/* Load guest PCR value to select appropriate compat mode */
+37:	ld	r7, VCORE_PCR(r5)
+	mtspr	SPRN_PCR, r7
+
+	li	r0,1
 	stb	r0,VCORE_IN_GUEST(r5)	/* signal secondaries to continue */
 	b	10f
 
@@ -984,8 +988,11 @@  END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
 	addis	r8,r8,0x100		/* if so, increment upper 40 bits */
 	mtspr	SPRN_TBU40,r8
 
-	/* Signal secondary CPUs to continue */
+	/* Reset PCR */
 17:	li	r0,0
+	mtspr	SPRN_PCR,r0
+
+	/* Signal secondary CPUs to continue */
 	stb	r0,VCORE_IN_GUEST(r5)
 	lis	r8,0x7fff		/* MAX_INT@h */
 	mtspr	SPRN_HDEC,r8