* [PATCH v2 1/2] KVM: PPC: Book3S HV: Get/set guest SPRs using the GET/SET_ONE_REG interface
2012-09-18 7:13 [PATCH v2 0/2] KVM: PPC: Save/restore complete Book3S HV guest register state Paul Mackerras
@ 2012-09-18 7:14 ` Paul Mackerras
2012-09-18 14:06 ` Alexander Graf
2012-09-18 7:14 ` [PATCH v2 2/2] KVM: PPC: Book3S HV: Get/set guest FP regs " Paul Mackerras
1 sibling, 1 reply; 8+ messages in thread
From: Paul Mackerras @ 2012-09-18 7:14 UTC (permalink / raw)
To: Alexander Graf; +Cc: kvm-ppc, kvm
This enables userspace to get and set various SPRs (special-purpose
registers) using the KVM_[GS]ET_ONE_REG ioctls. With this, userspace
can get and set all the SPRs that are part of the guest state, either
through the KVM_[GS]ET_REGS ioctls, the KVM_[GS]ET_SREGS ioctls, or
the KVM_[GS]ET_ONE_REG ioctls.
The SPRs that are added here are:
- DABR: Data address breakpoint register
- DSCR: Data stream control register
- PURR: Processor utilization of resources register
- SPURR: Scaled PURR
- DAR: Data address register
- DSISR: Data storage interrupt status register
- AMR: Authority mask register
- UAMOR: User authority mask override register
- MMCR0, MMCR1, MMCRA: Performance monitor unit control registers
- PMC1..PMC8: Performance monitor unit counter registers
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
v2: use case a...b: notation for MMCR0/1/A and PMCs
Documentation/virtual/kvm/api.txt | 19 ++++++++
arch/powerpc/include/asm/kvm.h | 21 +++++++++
arch/powerpc/kvm/book3s_hv.c | 88 +++++++++++++++++++++++++++++++++++++
3 files changed, 128 insertions(+)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index a12f4e4..407556f 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1740,6 +1740,25 @@ registers, find a list below:
PPC | KVM_REG_PPC_IAC4 | 64
PPC | KVM_REG_PPC_DAC1 | 64
PPC | KVM_REG_PPC_DAC2 | 64
+ PPC | KVM_REG_PPC_DABR | 64
+ PPC | KVM_REG_PPC_DSCR | 64
+ PPC | KVM_REG_PPC_PURR | 64
+ PPC | KVM_REG_PPC_SPURR | 64
+ PPC | KVM_REG_PPC_DAR | 64
+ PPC | KVM_REG_PPC_DSISR | 32
+ PPC | KVM_REG_PPC_AMR | 64
+ PPC | KVM_REG_PPC_UAMOR | 64
+ PPC | KVM_REG_PPC_MMCR0 | 64
+ PPC | KVM_REG_PPC_MMCR1 | 64
+ PPC | KVM_REG_PPC_MMCRA | 64
+ PPC | KVM_REG_PPC_PMC1 | 32
+ PPC | KVM_REG_PPC_PMC2 | 32
+ PPC | KVM_REG_PPC_PMC3 | 32
+ PPC | KVM_REG_PPC_PMC4 | 32
+ PPC | KVM_REG_PPC_PMC5 | 32
+ PPC | KVM_REG_PPC_PMC6 | 32
+ PPC | KVM_REG_PPC_PMC7 | 32
+ PPC | KVM_REG_PPC_PMC8 | 32
4.69 KVM_GET_ONE_REG
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index 3c14202..9557576 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -338,5 +338,26 @@ struct kvm_book3e_206_tlb_params {
#define KVM_REG_PPC_IAC4 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5)
#define KVM_REG_PPC_DAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6)
#define KVM_REG_PPC_DAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7)
+#define KVM_REG_PPC_DABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8)
+#define KVM_REG_PPC_DSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9)
+#define KVM_REG_PPC_PURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa)
+#define KVM_REG_PPC_SPURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb)
+#define KVM_REG_PPC_DAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc)
+#define KVM_REG_PPC_DSISR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd)
+#define KVM_REG_PPC_AMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xe)
+#define KVM_REG_PPC_UAMOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xf)
+
+#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10)
+#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11)
+#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12)
+
+#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18)
+#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19)
+#define KVM_REG_PPC_PMC3 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1a)
+#define KVM_REG_PPC_PMC4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1b)
+#define KVM_REG_PPC_PMC5 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1c)
+#define KVM_REG_PPC_PMC6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1d)
+#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e)
+#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f)
#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 38c7f1b..c4b5636 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -547,11 +547,44 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
{
int r = -EINVAL;
+ long int i;
switch (reg->id) {
case KVM_REG_PPC_HIOR:
r = put_user(0, (u64 __user *)reg->addr);
break;
+ case KVM_REG_PPC_DABR:
+ r = put_user(vcpu->arch.dabr, (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_DSCR:
+ r = put_user(vcpu->arch.dscr, (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_PURR:
+ r = put_user(vcpu->arch.purr, (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_SPURR:
+ r = put_user(vcpu->arch.spurr, (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_DAR:
+ r = put_user(vcpu->arch.shregs.dar, (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_DSISR:
+ r = put_user(vcpu->arch.shregs.dsisr, (u32 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_AMR:
+ r = put_user(vcpu->arch.amr, (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_UAMOR:
+ r = put_user(vcpu->arch.uamor, (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA:
+ i = reg->id - KVM_REG_PPC_MMCR0;
+ r = put_user(vcpu->arch.mmcr[i], (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8:
+ i = reg->id - KVM_REG_PPC_PMC1;
+ r = put_user(vcpu->arch.pmc[i], (u32 __user *)reg->addr);
+ break;
default:
break;
}
@@ -562,6 +595,9 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
{
int r = -EINVAL;
+ u64 val;
+ u32 wval;
+ long int i;
switch (reg->id) {
case KVM_REG_PPC_HIOR:
@@ -573,6 +609,58 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
r = -EINVAL;
break;
}
+ case KVM_REG_PPC_DABR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.dabr = val;
+ break;
+ case KVM_REG_PPC_DSCR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.dscr = val;
+ break;
+ case KVM_REG_PPC_PURR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.purr = val;
+ break;
+ case KVM_REG_PPC_SPURR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.spurr = val;
+ break;
+ case KVM_REG_PPC_DAR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.shregs.dar = val;
+ break;
+ case KVM_REG_PPC_DSISR:
+ r = get_user(wval, (u32 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.shregs.dsisr = wval;
+ break;
+ case KVM_REG_PPC_AMR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.amr = val;
+ break;
+ case KVM_REG_PPC_UAMOR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.uamor = val;
+ break;
+ case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA:
+ i = reg->id - KVM_REG_PPC_MMCR0;
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.mmcr[i] = val;
+ break;
+ case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8:
+ i = reg->id - KVM_REG_PPC_PMC1;
+ r = get_user(wval, (u32 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.pmc[i] = wval;
+ break;
default:
break;
}
--
1.7.10.rc3.219.g53414
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 2/2] KVM: PPC: Book3S HV: Get/set guest FP regs using the GET/SET_ONE_REG interface
2012-09-18 7:13 [PATCH v2 0/2] KVM: PPC: Save/restore complete Book3S HV guest register state Paul Mackerras
2012-09-18 7:14 ` [PATCH v2 1/2] KVM: PPC: Book3S HV: Get/set guest SPRs using the GET/SET_ONE_REG interface Paul Mackerras
@ 2012-09-18 7:14 ` Paul Mackerras
1 sibling, 0 replies; 8+ messages in thread
From: Paul Mackerras @ 2012-09-18 7:14 UTC (permalink / raw)
To: Alexander Graf; +Cc: kvm-ppc, kvm
This enables userspace to get and set all the guest floating-point
state using the KVM_[GS]ET_ONE_REG ioctls. The floating-point state
includes all of the traditional floating-point registers and the
FPSCR (floating point status/control register), all the VMX/Altivec
vector registers and the VSCR (vector status/control register), and
on POWER7, the vector-scalar registers (note that each FP register
is the high-order half of the corresponding VSR).
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
Documentation/virtual/kvm/api.txt | 11 ++++
arch/powerpc/include/asm/kvm.h | 20 +++++++
arch/powerpc/kvm/book3s_hv.c | 112 +++++++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 407556f..a02f0de 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1759,6 +1759,17 @@ registers, find a list below:
PPC | KVM_REG_PPC_PMC6 | 32
PPC | KVM_REG_PPC_PMC7 | 32
PPC | KVM_REG_PPC_PMC8 | 32
+ PPC | KVM_REG_PPC_FPR0 | 64
+ ...
+ PPC | KVM_REG_PPC_FPR31 | 64
+ PPC | KVM_REG_PPC_VR0 | 128
+ ...
+ PPC | KVM_REG_PPC_VR31 | 128
+ PPC | KVM_REG_PPC_VSR0 | 128
+ ...
+ PPC | KVM_REG_PPC_VSR31 | 128
+ PPC | KVM_REG_PPC_FPSCR | 64
+ PPC | KVM_REG_PPC_VSCR | 32
4.69 KVM_GET_ONE_REG
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index 9557576..1466975 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -360,4 +360,24 @@ struct kvm_book3e_206_tlb_params {
#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e)
#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f)
+/* 32 floating-point registers */
+#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20)
+#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n))
+#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f)
+
+/* 32 VMX/Altivec vector registers */
+#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40)
+#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n))
+#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f)
+
+/* 32 double-width FP registers for VSX */
+/* High-order halves overlap with FP regs */
+#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60)
+#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n))
+#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f)
+
+/* FP and vector status/control registers */
+#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80)
+#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81)
+
#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index c4b5636..32defa0 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -585,6 +585,54 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
i = reg->id - KVM_REG_PPC_PMC1;
r = put_user(vcpu->arch.pmc[i], (u32 __user *)reg->addr);
break;
+
+ case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+ i = reg->id - KVM_REG_PPC_FPR0;
+#ifdef CONFIG_VSX
+ if (cpu_has_feature(CPU_FTR_VSX)) {
+ /* VSX => FP reg i is stored in arch.vsr[2*i] */
+ r = put_user(vcpu->arch.vsr[2 * i],
+ (u64 __user *)reg->addr);
+ break;
+ }
+#endif
+ r = put_user(vcpu->arch.fpr[i], (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_PPC_FPSCR:
+ r = put_user(vcpu->arch.fpscr, (u64 __user *)reg->addr);
+ break;
+
+#ifdef CONFIG_ALTIVEC
+ case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
+ r = -ENXIO;
+ if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+ break;
+ i = reg->id - KVM_REG_PPC_VR0;
+ r = -EFAULT;
+ if (!copy_to_user((char __user *)reg->addr,
+ &vcpu->arch.vr[i], sizeof(vector128)))
+ r = 0;
+ break;
+ case KVM_REG_PPC_VSCR:
+ r = -ENXIO;
+ if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+ break;
+ r = put_user(vcpu->arch.vscr.u[3], (u32 __user *)reg->addr);
+ break;
+#endif
+
+#ifdef CONFIG_VSX
+ case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
+ r = -ENXIO;
+ if (!cpu_has_feature(CPU_FTR_VSX))
+ break;
+ i = (reg->id - KVM_REG_PPC_VR0) * 2;
+ r = -EFAULT;
+ if (!copy_to_user((char __user *)reg->addr,
+ &vcpu->arch.vsr[i], 2 * sizeof(u64)))
+ r = 0;
+ break;
+#endif
default:
break;
}
@@ -661,6 +709,70 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
if (!r)
vcpu->arch.pmc[i] = wval;
break;
+
+ case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+ i = reg->id - KVM_REG_PPC_FPR0;
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (r)
+ break;
+#ifdef CONFIG_VSX
+ if (cpu_has_feature(CPU_FTR_VSX)) {
+ /* VSX => FP reg i is stored in arch.vsr[2*i] */
+ vcpu->arch.vsr[2 * i] = val;
+ break;
+ }
+#endif
+ vcpu->arch.fpr[i] = r;
+ break;
+ case KVM_REG_PPC_FPSCR:
+ r = get_user(val, (u64 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.fpscr = val;
+ break;
+
+#ifdef CONFIG_ALTIVEC
+ case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: {
+ vector128 tmp;
+
+ r = -ENXIO;
+ if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+ break;
+ i = reg->id - KVM_REG_PPC_VR0;
+ r = -EFAULT;
+ if (copy_from_user(&tmp, (char __user *)reg->addr,
+ sizeof(vector128)))
+ break;
+ r = 0;
+ vcpu->arch.vr[i] = tmp;
+ break;
+ }
+ case KVM_REG_PPC_VSCR:
+ r = -ENXIO;
+ if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+ break;
+ r = get_user(wval, (u32 __user *)reg->addr);
+ if (!r)
+ vcpu->arch.vscr.u[3] = wval;
+ break;
+#endif
+#ifdef CONFIG_VSX
+ case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: {
+ u64 tmp[2];
+
+ r = -ENXIO;
+ if (!cpu_has_feature(CPU_FTR_VSX))
+ break;
+ i = (reg->id - KVM_REG_PPC_VSR0) * 2;
+ r = -EFAULT;
+ if (copy_from_user(tmp, (char __user *)reg->addr,
+ 2 * sizeof(u64)))
+ break;
+ r = 0;
+ vcpu->arch.vsr[i] = tmp[0];
+ vcpu->arch.vsr[i + 1] = tmp[1];
+ break;
+ }
+#endif
default:
break;
}
--
1.7.10.rc3.219.g53414
^ permalink raw reply related [flat|nested] 8+ messages in thread