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@xxxxxxxxx> > --- > 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-ppc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html