diff mbox

[3/3] KVM: PPC: Book3S HV: Add H_SET_MODE hcall handling

Message ID 1401106626-13130-4-git-send-email-paulus@samba.org
State New, archived
Headers show

Commit Message

Paul Mackerras May 26, 2014, 12:17 p.m. UTC
From: Michael Neuling <mikey@neuling.org>

This adds support for the H_SET_MODE hcall.  This hcall is a
multiplexer that has several functions, some of which are called
rarely, and some which are potentially called very frequently.
Here we add support for the functions that set the debug registers
CIABR (Completed Instruction Address Breakpoint Register) and
DAWR/DAWRX (Data Address Watchpoint Register and eXtension),
since they could be updated by the guest as often as every context
switch.

This also adds a kvmppc_power8_compatible() function to test to see
if a guest is compatible with POWER8 or not.  The CIABR and DAWR/X
only exist on POWER8.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/hvcall.h |  6 +++++
 arch/powerpc/kvm/book3s_hv.c      | 51 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 56 insertions(+), 1 deletion(-)

Comments

Alexander Graf May 28, 2014, 1:35 p.m. UTC | #1
On 26.05.14 14:17, Paul Mackerras wrote:
> From: Michael Neuling <mikey@neuling.org>
>
> This adds support for the H_SET_MODE hcall.  This hcall is a
> multiplexer that has several functions, some of which are called
> rarely, and some which are potentially called very frequently.
> Here we add support for the functions that set the debug registers
> CIABR (Completed Instruction Address Breakpoint Register) and
> DAWR/DAWRX (Data Address Watchpoint Register and eXtension),
> since they could be updated by the guest as often as every context
> switch.
>
> This also adds a kvmppc_power8_compatible() function to test to see
> if a guest is compatible with POWER8 or not.  The CIABR and DAWR/X
> only exist on POWER8.
>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
> Signed-off-by: Paul Mackerras <paulus@samba.org>
> ---
>   arch/powerpc/include/asm/hvcall.h |  6 +++++
>   arch/powerpc/kvm/book3s_hv.c      | 51 ++++++++++++++++++++++++++++++++++++++-
>   2 files changed, 56 insertions(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
> index 5dbbb29..85bc8c0 100644
> --- a/arch/powerpc/include/asm/hvcall.h
> +++ b/arch/powerpc/include/asm/hvcall.h
> @@ -279,6 +279,12 @@
>   #define H_GET_24X7_DATA		0xF07C
>   #define H_GET_PERF_COUNTER_INFO	0xF080
>   
> +/* Values for 2nd argument to H_SET_MODE */
> +#define H_SET_MODE_RESOURCE_SET_CIABR		1
> +#define H_SET_MODE_RESOURCE_SET_DAWR		2
> +#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE	3
> +#define H_SET_MODE_RESOURCE_LE			4
> +
>   #ifndef __ASSEMBLY__
>   
>   /**
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 1f91130..53e2b63 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -557,6 +557,47 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,
>   	vcpu->arch.dtl.dirty = true;
>   }
>   
> +static bool kvmppc_power8_compatible(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu->arch.vcore->arch_compat >= PVR_ARCH_207)
> +		return true;
> +	if ((!vcpu->arch.vcore->arch_compat) &&
> +	    cpu_has_feature(CPU_FTR_ARCH_207S))
> +		return true;
> +	return false;
> +}
> +
> +static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags,
> +			     unsigned long resource, unsigned long value1,
> +			     unsigned long value2)
> +{
> +	switch (resource) {
> +	case H_SET_MODE_RESOURCE_SET_CIABR:
> +		if (!kvmppc_power8_compatible(vcpu))
> +			return H_P2;
> +		if (value2)
> +			return H_P4;
> +		if (mflags)
> +			return H_UNSUPPORTED_FLAG_START;
> +		if ((value1 & 0x3) == 0x3)

What is this?

Alex

> +			return H_P3;
> +		vcpu->arch.ciabr  = value1;
> +		return H_SUCCESS;
> +	case H_SET_MODE_RESOURCE_SET_DAWR:
> +		if (!kvmppc_power8_compatible(vcpu))
> +			return H_P2;
> +		if (mflags)
> +			return H_UNSUPPORTED_FLAG_START;
> +		if (value2 & DABRX_HYP)
> +			return H_P4;
> +		vcpu->arch.dawr  = value1;
> +		vcpu->arch.dawrx = value2;
> +		return H_SUCCESS;
> +	default:
> +		return H_TOO_HARD;
> +	}
> +}
> +
>   int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
>   {
>   	unsigned long req = kvmppc_get_gpr(vcpu, 3);
> @@ -626,7 +667,14 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
>   
>   		/* Send the error out to userspace via KVM_RUN */
>   		return rc;
> -
> +	case H_SET_MODE:
> +		ret = kvmppc_h_set_mode(vcpu, kvmppc_get_gpr(vcpu, 4),
> +					kvmppc_get_gpr(vcpu, 5),
> +					kvmppc_get_gpr(vcpu, 6),
> +					kvmppc_get_gpr(vcpu, 7));
> +		if (ret == H_TOO_HARD)
> +			return RESUME_HOST;
> +		break;
>   	case H_XIRR:
>   	case H_CPPR:
>   	case H_EOI:
> @@ -652,6 +700,7 @@ static int kvmppc_hcall_impl_hv(struct kvm *kvm, unsigned long cmd)
>   	case H_PROD:
>   	case H_CONFER:
>   	case H_REGISTER_VPA:
> +	case H_SET_MODE:
>   #ifdef CONFIG_KVM_XICS
>   	case H_XIRR:
>   	case H_CPPR:

--
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
Michael Neuling May 29, 2014, 5:47 a.m. UTC | #2
Alex,

> > +static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags,
> > +			     unsigned long resource, unsigned long value1,
> > +			     unsigned long value2)
> > +{
> > +	switch (resource) {
> > +	case H_SET_MODE_RESOURCE_SET_CIABR:
> > +		if (!kvmppc_power8_compatible(vcpu))
> > +			return H_P2;
> > +		if (value2)
> > +			return H_P4;
> > +		if (mflags)
> > +			return H_UNSUPPORTED_FLAG_START;
> > +		if ((value1 & 0x3) == 0x3)
> 
> What is this?

It's what it says in PAPR (I wish that was public!!!).  Joking aside... 

If you refer to the 2.07 HW arch (not PAPR), the bottom two bits of the
CIABR tell you what mode to match in.  0x3 means match in hypervisor,
which we obviously don't want the guest to be able to do.

I'll add some #defines to make it a clearer and repost.

Mikey

--
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
diff mbox

Patch

diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 5dbbb29..85bc8c0 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -279,6 +279,12 @@ 
 #define H_GET_24X7_DATA		0xF07C
 #define H_GET_PERF_COUNTER_INFO	0xF080
 
+/* Values for 2nd argument to H_SET_MODE */
+#define H_SET_MODE_RESOURCE_SET_CIABR		1
+#define H_SET_MODE_RESOURCE_SET_DAWR		2
+#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE	3
+#define H_SET_MODE_RESOURCE_LE			4
+
 #ifndef __ASSEMBLY__
 
 /**
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 1f91130..53e2b63 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -557,6 +557,47 @@  static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,
 	vcpu->arch.dtl.dirty = true;
 }
 
+static bool kvmppc_power8_compatible(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.vcore->arch_compat >= PVR_ARCH_207)
+		return true;
+	if ((!vcpu->arch.vcore->arch_compat) &&
+	    cpu_has_feature(CPU_FTR_ARCH_207S))
+		return true;
+	return false;
+}
+
+static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags,
+			     unsigned long resource, unsigned long value1,
+			     unsigned long value2)
+{
+	switch (resource) {
+	case H_SET_MODE_RESOURCE_SET_CIABR:
+		if (!kvmppc_power8_compatible(vcpu))
+			return H_P2;
+		if (value2)
+			return H_P4;
+		if (mflags)
+			return H_UNSUPPORTED_FLAG_START;
+		if ((value1 & 0x3) == 0x3)
+			return H_P3;
+		vcpu->arch.ciabr  = value1;
+		return H_SUCCESS;
+	case H_SET_MODE_RESOURCE_SET_DAWR:
+		if (!kvmppc_power8_compatible(vcpu))
+			return H_P2;
+		if (mflags)
+			return H_UNSUPPORTED_FLAG_START;
+		if (value2 & DABRX_HYP)
+			return H_P4;
+		vcpu->arch.dawr  = value1;
+		vcpu->arch.dawrx = value2;
+		return H_SUCCESS;
+	default:
+		return H_TOO_HARD;
+	}
+}
+
 int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
 {
 	unsigned long req = kvmppc_get_gpr(vcpu, 3);
@@ -626,7 +667,14 @@  int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
 
 		/* Send the error out to userspace via KVM_RUN */
 		return rc;
-
+	case H_SET_MODE:
+		ret = kvmppc_h_set_mode(vcpu, kvmppc_get_gpr(vcpu, 4),
+					kvmppc_get_gpr(vcpu, 5),
+					kvmppc_get_gpr(vcpu, 6),
+					kvmppc_get_gpr(vcpu, 7));
+		if (ret == H_TOO_HARD)
+			return RESUME_HOST;
+		break;
 	case H_XIRR:
 	case H_CPPR:
 	case H_EOI:
@@ -652,6 +700,7 @@  static int kvmppc_hcall_impl_hv(struct kvm *kvm, unsigned long cmd)
 	case H_PROD:
 	case H_CONFER:
 	case H_REGISTER_VPA:
+	case H_SET_MODE:
 #ifdef CONFIG_KVM_XICS
 	case H_XIRR:
 	case H_CPPR: