Patchwork [1/2] KVM: PPC: Book3S HV: Get/set guest SPRs using the GET/SET_ONE_REG interface

login
register
mail settings
Submitter Paul Mackerras
Date Sept. 12, 2012, 12:18 a.m.
Message ID <20120912001810.GF32642@bloggs.ozlabs.ibm.com>
Download mbox | patch
Permalink /patch/183218/
State New
Headers show

Comments

Paul Mackerras - Sept. 12, 2012, 12:18 a.m.
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>
---
 arch/powerpc/include/asm/kvm.h |   21 ++++++++
 arch/powerpc/kvm/book3s_hv.c   |  106 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 127 insertions(+)
Alexander Graf - Sept. 13, 2012, 11:29 p.m.
On 12.09.2012, at 02:18, Paul Mackerras wrote:

> 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>
> ---
> arch/powerpc/include/asm/kvm.h |   21 ++++++++
> arch/powerpc/kvm/book3s_hv.c   |  106 ++++++++++++++++++++++++++++++++++++++++

Documentation/virtual/kvm/api.txt | +++++++++++

:)


Alex

> 2 files changed, 127 insertions(+)
> 
> 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 83e929e..7fe5c9a 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -538,11 +538,53 @@ 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:
> +	case KVM_REG_PPC_MMCR1:
> +	case 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:
> +	case KVM_REG_PPC_PMC2:
> +	case KVM_REG_PPC_PMC3:
> +	case KVM_REG_PPC_PMC4:
> +	case KVM_REG_PPC_PMC5:
> +	case KVM_REG_PPC_PMC6:
> +	case KVM_REG_PPC_PMC7:
> +	case 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;
> 	}
> @@ -553,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:
> @@ -564,6 +609,67 @@ 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:
> +	case KVM_REG_PPC_MMCR1:
> +	case 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:
> +	case KVM_REG_PPC_PMC2:
> +	case KVM_REG_PPC_PMC3:
> +	case KVM_REG_PPC_PMC4:
> +	case KVM_REG_PPC_PMC5:
> +	case KVM_REG_PPC_PMC6:
> +	case KVM_REG_PPC_PMC7:
> +	case 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
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

Patch

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 83e929e..7fe5c9a 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -538,11 +538,53 @@  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:
+	case KVM_REG_PPC_MMCR1:
+	case 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:
+	case KVM_REG_PPC_PMC2:
+	case KVM_REG_PPC_PMC3:
+	case KVM_REG_PPC_PMC4:
+	case KVM_REG_PPC_PMC5:
+	case KVM_REG_PPC_PMC6:
+	case KVM_REG_PPC_PMC7:
+	case 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;
 	}
@@ -553,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:
@@ -564,6 +609,67 @@  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:
+	case KVM_REG_PPC_MMCR1:
+	case 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:
+	case KVM_REG_PPC_PMC2:
+	case KVM_REG_PPC_PMC3:
+	case KVM_REG_PPC_PMC4:
+	case KVM_REG_PPC_PMC5:
+	case KVM_REG_PPC_PMC6:
+	case KVM_REG_PPC_PMC7:
+	case 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;
 	}