Re: [PATCH v8 09/20] KVM: ARM64: Add access handler for event counter register

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:08, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
> is mapped to PMEVCNTRn.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When reading these registers, return the sum of register value and the
> value perf event counts.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 138 
> --
>  1 file changed, 134 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index ed2939b..1818947 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -569,6 +569,57 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
> +   struct sys_reg_params *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 idx, reg, val;
> +
> + if (!p->is_aarch32) {
> + if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
> + /* PMXEVCNTR_EL0 */
> + reg = 0;
> + else
> + /* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
> + reg = r->reg;
> + } else {
> + if (r->CRn == 9 && r->CRm == 13) {
> + reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
> + } else {
> + reg = ((r->CRm & 3) << 3) | (r->Op2 & 7);
> + reg += PMEVCNTR0_EL0;
> + }
> + }

Same remark about the use of 0 instead of PMSELR_EL0.

> +
> + switch (reg) {
> + case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
> + idx = reg - PMEVCNTR0_EL0;
> + if (!pmu_counter_idx_valid(vcpu, idx))
> + return true;
> + break;
> + case PMCCNTR_EL0:
> + idx = ARMV8_CYCLE_IDX;
> + break;
> + default:
> + /* PMXEVCNTR_EL0 */
> + idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
> + if (!pmu_counter_idx_valid(vcpu, idx))
> + return true;
> +
> + reg = (idx == ARMV8_CYCLE_IDX) ? PMCCNTR_EL0
> +  : PMEVCNTR0_EL0 + idx;
> + break;
> + }
> +
> + val = kvm_pmu_get_counter_value(vcpu, idx);
> + if (p->is_write)
> + vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
> + else
> + p->regval = val;
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -584,6 +635,13 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b111), \
> trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
>  
> +/* Macro to expand the PMEVCNTRn_EL0 register */
> +#define PMU_PMEVCNTR_EL0(n)  \
> + /* PMEVCNTRn_EL0 */ \
> + { Op0(0b11), Op1(0b011), CRn(0b1110),   \
> +   CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
> +   access_pmu_evcntr, reset_unknown, (PMEVCNTR0_EL0 + n), }
> +
>  /* Macro to expand the PMEVTYPERn_EL0 register */
>  #define PMU_PMEVTYPER_EL0(n) \
>   /* PMEVTYPERn_EL0 */\
> @@ -784,13 +842,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmceid },
>   /* PMCCNTR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
> -   trap_raz_wi },
> +   access_pmu_evcntr, reset_unknown, PMCCNTR_EL0 },
>   /* PMXEVTYPER_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
> access_pmu_evtyper },
>   /* PMXEVCNTR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
> -   trap_raz_wi },
> +   access_pmu_evcntr },
>   /* PMUSERENR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
> trap_raz_wi },
> @@ -805,6 +863,38 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>   { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b011),
> NULL, reset_unknown, TPIDRRO_EL0 },
>  
> + /* PMEVCNTRn_EL0 */
> + PMU_PMEVCNTR_EL0(0),
> + PMU_PMEVCNTR_EL0(1),
> + PMU_PMEVCNTR_EL0(2),
> + PMU_PMEVCNTR_EL0(3),
> + PMU_PMEVCNTR_EL0(4),
> + PMU_PMEVCNTR_EL0(5),
> + PMU_PMEVCNTR_EL0(6),
> + PMU_PMEVCNTR_EL0(7),
> 

[PATCH] arm64: KVM: Fix AArch64 guest userspace exception injection

2016-01-07 Thread Marc Zyngier
At the moment, our fault injection is pretty limited. We always
generate a SYNC exception into EL1, as if the fault was actually
from EL1h, no matter how it was generated.

This is obviously wrong, as EL0 can generate faults of its own
(not to mention the pretty-much unused EL1t mode).

This patch fixes it by implementing section D1.10.2 of the ARMv8 ARM,
and in particular table D1-7 ("Vector offsets from vector table base
address"), which describes which vector to use depending on the source
exception level and type (synchronous, IRQ, FIQ or SError).

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/inject_fault.c | 38 +++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 648112e..4d1ac81 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -27,7 +27,11 @@
 
 #define PSTATE_FAULT_BITS_64   (PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
 PSR_I_BIT | PSR_D_BIT)
-#define EL1_EXCEPT_SYNC_OFFSET 0x200
+
+#define CURRENT_EL_SP_EL0_VECTOR   0x0
+#define CURRENT_EL_SP_ELx_VECTOR   0x200
+#define LOWER_EL_AArch64_VECTOR0x400
+#define LOWER_EL_AArch32_VECTOR0x600
 
 static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
 {
@@ -97,6 +101,34 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool 
is_pabt,
*fsr = 0x14;
 }
 
+enum exception_type {
+   except_type_sync= 0,
+   except_type_irq = 0x80,
+   except_type_fiq = 0x100,
+   except_type_serror  = 0x180,
+};
+
+static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
+{
+   u64 exc_offset;
+
+   switch (*vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT)) {
+   case PSR_MODE_EL1t:
+   exc_offset = CURRENT_EL_SP_EL0_VECTOR;
+   break;
+   case PSR_MODE_EL1h:
+   exc_offset = CURRENT_EL_SP_ELx_VECTOR;
+   break;
+   case PSR_MODE_EL0t:
+   exc_offset = LOWER_EL_AArch64_VECTOR;
+   break;
+   default:
+   exc_offset = LOWER_EL_AArch32_VECTOR;
+   }
+
+   return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
+}
+
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long 
addr)
 {
unsigned long cpsr = *vcpu_cpsr(vcpu);
@@ -108,8 +140,8 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool 
is_iabt, unsigned long addr
*vcpu_spsr(vcpu) = cpsr;
*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
 
+   *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-   *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
 
vcpu_sys_reg(vcpu, FAR_EL1) = addr;
 
@@ -143,8 +175,8 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
*vcpu_spsr(vcpu) = cpsr;
*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
 
+   *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-   *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
 
/*
 * Build an unknown exception, depending on the instruction
-- 
2.1.4

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


Re: [PATCH v8 04/20] KVM: ARM64: Add access handler for PMCR register

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:07, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add reset handler which gets host value of PMCR_EL0 and make writable
> bits architecturally UNKNOWN except PMCR.E which is zero. Add an access
> handler for PMCR.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 39 +--
>  1 file changed, 37 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e8bf374..c60047e 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -34,6 +34,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  
> @@ -439,6 +440,40 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const 
> struct sys_reg_desc *r)
>   vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
>  }
>  
> +static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> +{
> + u64 pmcr, val;
> +
> + asm volatile("mrs %0, pmcr_el0\n" : "=r" (pmcr));
> + /* Writable bits of PMCR_EL0 (ARMV8_PMCR_MASK) is reset to UNKNOWN
> +  * except PMCR.E resetting to zero.
> +  */
> + val = ((pmcr & ~ARMV8_PMCR_MASK) | (ARMV8_PMCR_MASK & 0xdecafbad))
> +   & (~ARMV8_PMCR_E);
> + vcpu_sys_reg(vcpu, r->reg) = val;
> +}
> +
> +static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> + const struct sys_reg_desc *r)
> +{
> + u64 val;
> +
> + if (p->is_write) {
> + /* Only update writeable bits of PMCR */
> + val = vcpu_sys_reg(vcpu, r->reg);
> + val &= ~ARMV8_PMCR_MASK;
> + val |= p->regval & ARMV8_PMCR_MASK;
> + vcpu_sys_reg(vcpu, r->reg) = val;
> + } else {
> + /* PMCR.P & PMCR.C are RAZ */
> + val = vcpu_sys_reg(vcpu, r->reg)
> +   & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
> + p->regval = val;
> + }

How can that work for 32bit, where r->reg is not populated from the trap
table? You *know* that you are accessing PMCR, so just use PMCR_EL0 as
an index into vcpu_sys_reg() in all cases. You can then drop PMCR_EL0
from the 64bit trap table entry.

> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -623,7 +658,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  
>   /* PMCR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
> -   trap_raz_wi },
> +   access_pmcr, reset_pmcr, PMCR_EL0, },
>   /* PMCNTENSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
> trap_raz_wi },
> @@ -885,7 +920,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
>  
>   /* PMU */
> - { Op1( 0), CRn( 9), CRm(12), Op2( 0), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
> 

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 11/20] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:08, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMINTENSET or PMINTENCLR register.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 27 +++
>  1 file changed, 23 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 3416881..24ce4fe 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -644,6 +644,25 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +const struct sys_reg_desc *r)
> +{
> + u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> + if (p->is_write) {
> + if (r->Op2 & 0x1)
> + /* accessing PMINTENSET_EL1 */
> + vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
> + else
> + /* accessing PMINTENCLR_EL1 */
> + vcpu_sys_reg(vcpu, r->reg) &= ~(p->regval & mask);
> + } else {
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> + }
> +
> + return true;
> +}
> +

Same bug again.

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 01/20] ARM64: Move PMU register related defines to asm/pmu.h

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:07, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.z...@linaro.org>
> 
> To use the ARMv8 PMU related register defines from the KVM code,
> we move the relevant definitions to asm/pmu.h header file.
> 
> Signed-off-by: Anup Patel <anup.pa...@linaro.org>
> Signed-off-by: Shannon Zhao <shannon.z...@linaro.org>

Acked-by: Marc Zyngier <marc.zyng...@arm.com>

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 06/20] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:08, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add access handler which gets host value of PMCEID0 or PMCEID1 when
> guest access these registers. Writing action to PMCEID0 or PMCEID1 is
> UNDEFINED.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 27 +++
>  1 file changed, 23 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f9985fc..2552db1 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -486,6 +486,25 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 pmceid;
> +
> + if (p->is_write) {
> + kvm_inject_undefined(vcpu);

Just "return false", which will do the right thing.

> + } else {
> + if (!(p->Op2 & 1))
> + asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
> + else
> + asm volatile("mrs %0, pmceid1_el0\n" : "=r" (pmceid));
> +
> + p->regval = pmceid;
> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -688,10 +707,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmselr, reset_unknown, PMSELR_EL0 },
>   /* PMCEID0_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
> -   trap_raz_wi },
> +   access_pmceid },
>   /* PMCEID1_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
> -   trap_raz_wi },
> +   access_pmceid },
>   /* PMCCNTR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
> trap_raz_wi },
> @@ -937,8 +956,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
> 

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 05/20] KVM: ARM64: Add access handler for PMSELR register

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:08, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMSELR_EL0 is UNKNOWN, use reset_unknown for
> its reset handler. When reading PMSELR, return the PMSELR.SEL field to
> guest.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 16 ++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c60047e..f9985fc 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -474,6 +474,18 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +   const struct sys_reg_desc *r)
> +{
> + if (p->is_write)
> + vcpu_sys_reg(vcpu, r->reg) = p->regval;
> + else
> + /* return PMSELR.SEL field */
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;

Same 32bit bug again.

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 13/20] KVM: ARM64: Add access handler for PMSWINC register

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:08, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add access handler which emulates writing and reading PMSWINC
> register and add support for creating software increment event.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 18 +-
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c| 33 +
>  3 files changed, 52 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index d61f271dd..92021dc 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -682,6 +682,21 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +const struct sys_reg_desc *r)
> +{
> + u64 mask;
> +
> + if (p->is_write) {
> + mask = kvm_pmu_valid_counter_mask(vcpu);
> + kvm_pmu_software_increment(vcpu, p->regval & mask);
> + } else {
> + kvm_inject_undefined(vcpu);

"return false;" instead.

> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -892,7 +907,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmovs, NULL, PMOVSSET_EL0 },
>   /* PMSWINC_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> -   trap_raz_wi },
> +   access_pmswinc, reset_unknown, PMSWINC_EL0 },
>   /* PMSELR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
> access_pmselr, reset_unknown, PMSELR_EL0 },
> @@ -1231,6 +1246,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcnten },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcnten },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovs },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 244970b..67d168c 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -40,6 +40,7 @@ u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx);
>  #else
> @@ -57,6 +58,7 @@ u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index c23d57e..409f3c4 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -160,6 +160,35 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
>   kvm_vcpu_kick(vcpu);
>  }
>  
> +/**
> + * kvm_pmu_software_increment - do software increment
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMSWINC register
> + */
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
> +{
> + int i;
> + u64 type, enable, reg;
> +
> + if (val == 0)
> + return;
> +
> + for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
> + if (!(val & BIT(i)))
> + continue;
> + type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +& ARMV8_EVTYPE_EVENT;
> + enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> + if ((type == 0) && (enable & BIT(i))) {

nit: Should we have a ARMV8_EVTYPE_EVENT_SW_INCR instead of just
checking for zero?

> + reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> + reg = lower_32_bits(reg);
> + vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> + if (!reg)
> + kvm_pmu_overflow_set(vcpu, BIT(i));
> + }
> + }
> +}
> +
>  static inline bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu,
>

Re: [PATCH v8 16/20] KVM: ARM64: Add access handler for PMUSERENR register

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:08, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> This register resets as unknown in 64bit mode while it resets as zero
> in 32bit mode. Here we choose to reset it as zero for consistency.
> 
> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
> accessed from EL0. Add some check helpers to handle the access from EL0.
> 
> When these bits are zero, only reading PMUSERENR will trap to EL2 and
> writing PMUSERENR or reading/writing other PMU registers will trap to
> EL1 other than EL2 when HCR.TGE==0. To current KVM configuration
> (HCR.TGE==0) there is no way to get these traps. Here we write 0xf to
> physical PMUSERENR register on VM entry, so that it will trap PMU access
> from EL0 to EL2. Within the register access handler we check the real
> value of guest PMUSERENR register to decide whether this access is
> allowed. If not allowed, forward this trap to EL1.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/include/asm/pmu.h |   9 
>  arch/arm64/kvm/hyp/switch.c  |   3 ++
>  arch/arm64/kvm/sys_regs.c| 122 
> +--
>  3 files changed, 129 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
> index 2588f9c..1238ade 100644
> --- a/arch/arm64/include/asm/pmu.h
> +++ b/arch/arm64/include/asm/pmu.h
> @@ -67,4 +67,13 @@
>  #define  ARMV8_EXCLUDE_EL0   (1 << 30)
>  #define  ARMV8_INCLUDE_EL2   (1 << 27)
>  
> +/*
> + * PMUSERENR: user enable reg
> + */
> +#define ARMV8_USERENR_MASK   0xf /* Mask for writable bits */
> +#define ARMV8_USERENR_EN (1 << 0) /* PMU regs can be accessed at EL0 */
> +#define ARMV8_USERENR_SW (1 << 1) /* PMSWINC can be written at EL0 */
> +#define ARMV8_USERENR_CR (1 << 2) /* Cycle counter can be read at EL0 */
> +#define ARMV8_USERENR_ER (1 << 3) /* Event counter can be read at EL0 */
> +
>  #endif /* __ASM_PMU_H */
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index ca8f5a5..a85375f 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -37,6 +37,8 @@ static void __hyp_text __activate_traps(struct kvm_vcpu 
> *vcpu)
>   /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
>   write_sysreg(1 << 15, hstr_el2);
>   write_sysreg(CPTR_EL2_TTA | CPTR_EL2_TFP, cptr_el2);
> + /* Make sure we trap PMU access from EL0 to EL2 */
> + write_sysreg(15, pmuserenr_el0);

Please use the ARMV8_USERENR_* constants here instead of a magic number
(since you went through the hassle of defining them!).

>   write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
>  }
>  
> @@ -45,6 +47,7 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu 
> *vcpu)
>   write_sysreg(HCR_RW, hcr_el2);
>   write_sysreg(0, hstr_el2);
>   write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2);
> + write_sysreg(0, pmuserenr_el0);
>   write_sysreg(0, cptr_el2);
>  }
>  
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 04281f1..ac0cbf8 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -453,11 +453,47 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
> struct sys_reg_desc *r)
>   vcpu_sys_reg(vcpu, r->reg) = val;
>  }
>  
> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)

Please drop all the inline attributes. The compiler knows its stuff well
enough to do it automagically, and this is hardly a fast path...

> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & ARMV8_USERENR_EN) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & (ARMV8_USERENR_SW | ARMV8_USERENR_EN))
> +  || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu 
> *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & (ARMV8_USERENR_CR | ARMV8_USERENR_EN))
> +  || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu 
> *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & (ARMV8_USERENR_ER | ARMV8_USERENR_EN))
> +  || vcpu_mode_priv(vcpu));
> +}
> +
>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>   const struct sys_reg_desc *r)
>  {
>   u64 val;
>  
> + if (pmu_access_el0_disabled(vcpu)) {
> + kvm_forward_trap_to_el1(vcpu);
> + return true;
> + }

So with the patch I posted earlier
(http://www.spinics.net/lists/arm-kernel/msg472693.html), all the
instances similar to that code can be rewritten as

+   if (pmu_access_el0_disabled(vcpu))
+   return 

Re: [PATCH v8 03/20] KVM: ARM64: Add offset defines for PMU registers

2016-01-07 Thread Marc Zyngier
On 22/12/15 08:07, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.z...@linaro.org>
> 
> We are about to trap and emulate accesses to each PMU register
> individually. This adds the context offsets for the AArch64 PMU
> registers.
> 
> Signed-off-by: Shannon Zhao <shannon.z...@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyng...@arm.com>

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 08/20] KVM: ARM64: Add access handler for event typer register

2016-01-07 Thread Marc Zyngier
On 07/01/16 12:09, Shannon Zhao wrote:
> 
> 
> On 2015/12/22 16:08, Shannon Zhao wrote:
>> From: Shannon Zhao 
>>
>> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
>> which is mapped to PMEVTYPERn or PMCCFILTR.
>>
>> The access handler translates all aarch32 register offsets to aarch64
>> ones and uses vcpu_sys_reg() to access their values to avoid taking care
>> of big endian.
>>
>> When writing to these registers, create a perf_event for the selected
>> event type.
>>
>> Signed-off-by: Shannon Zhao 
>> ---
>>  arch/arm64/kvm/sys_regs.c | 156 
>> +-
>>  1 file changed, 154 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index 2552db1..ed2939b 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -505,6 +505,70 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct 
>> sys_reg_params *p,
>>  return true;
>>  }
>>  
>> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
>> +{
>> +u64 pmcr, val;
>> +
>> +pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
>> +val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
>> +if (idx >= val && idx != ARMV8_CYCLE_IDX)
>> +return false;
>> +
>> +return true;
>> +}
>> +
>> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params 
>> *p,
>> +   const struct sys_reg_desc *r)
>> +{
>> +u64 idx, reg;
>> +
>> +if (r->CRn == 9) {
>> +/* PMXEVTYPER_EL0 */
>> +reg = 0;
>> +} else {
>> +if (!p->is_aarch32) {
>> +/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
>> +reg = r->reg;
>> +} else {
>> +if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
>> +reg = PMCCFILTR_EL0;
>> +} else {
>> +reg = ((r->CRm & 3) << 3) | (r->Op2 & 7);
>> +reg += PMEVTYPER0_EL0;
>> +}
>> +}
>> +}
>> +
>> +switch (reg) {
>> +case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
>> +idx = reg - PMEVTYPER0_EL0;
>> +if (!pmu_counter_idx_valid(vcpu, idx))
>> +return true;
> Hi Marc,
> 
> Here should we return false to inject an UND since there is no
> PMEVTYPER(idx)_EL0? The ARMv8 spec says it should.

The spec says that the following behaviours are valid:
- Accesses to the register are UNDEFINED .
- Accesses to the register behave as RAZ/WI.
- Accesses to the register execute as a NOP .

Same for the counters. So you can either return true (act as a NOP), or
return false (UNDEF), and even zero r->regval on read and return true
(RAZ/WI).

This is entirely up to you. My personal preference is indeed to UNDEF,
but your current implementation is valid.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 19/20] KVM: ARM64: Free perf event of PMU when destroying vcpu

2016-01-07 Thread Marc Zyngier
On Tue, 22 Dec 2015 16:08:14 +0800
Shannon Zhao <zhaoshengl...@huawei.com> wrote:

> From: Shannon Zhao <shannon.z...@linaro.org>
> 
> When KVM frees VCPU, it needs to free the perf_event of PMU.
> 
> Signed-off-by: Shannon Zhao <shannon.z...@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyng...@arm.com>

M.
-- 
Jazz is not dead. It just smells funny.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 07/20] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function

2016-01-07 Thread Marc Zyngier
On Tue, 22 Dec 2015 16:08:02 +0800
Shannon Zhao  wrote:

> From: Shannon Zhao 
> 
> When we use tools like perf on host, perf passes the event type and the
> id of this event type category to kernel, then kernel will map them to
> hardware event number and write this number to PMU PMEVTYPER_EL0
> register. When getting the event number in KVM, directly use raw event
> type to create a perf_event for it.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/include/asm/pmu.h |   3 ++
>  arch/arm64/kvm/Makefile  |   1 +
>  include/kvm/arm_pmu.h|  11 
>  virt/kvm/arm/pmu.c   | 122 
> +++
>  4 files changed, 137 insertions(+)
>  create mode 100644 virt/kvm/arm/pmu.c
> 
> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
> index 4406184..2588f9c 100644
> --- a/arch/arm64/include/asm/pmu.h
> +++ b/arch/arm64/include/asm/pmu.h
> @@ -21,6 +21,7 @@
>  
>  #define ARMV8_MAX_COUNTERS  32
>  #define ARMV8_COUNTER_MASK  (ARMV8_MAX_COUNTERS - 1)
> +#define ARMV8_CYCLE_IDX (ARMV8_MAX_COUNTERS - 1)
>  
>  /*
>   * Per-CPU PMCR: config reg
> @@ -31,6 +32,8 @@
>  #define ARMV8_PMCR_D (1 << 3) /* CCNT counts every 64th cpu cycle */
>  #define ARMV8_PMCR_X (1 << 4) /* Export to ETM */
>  #define ARMV8_PMCR_DP(1 << 5) /* Disable CCNT if 
> non-invasive debug*/
> +/* Determines which PMCCNTR_EL0 bit generates an overflow */
> +#define ARMV8_PMCR_LC(1 << 6)
>  #define  ARMV8_PMCR_N_SHIFT  11   /* Number of counters 
> supported */
>  #define  ARMV8_PMCR_N_MASK   0x1f
>  #define  ARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index caee9ee..122cff4 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -26,3 +26,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
> +kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index ddcb5b2..14bedb0 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -34,9 +34,20 @@ struct kvm_pmu {
>   int irq_num;
>   struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
>  };
> +
> +u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> + u64 select_idx);
>  #else
>  struct kvm_pmu {
>  };
> +
> +u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
> +{
> + return 0;
> +}
> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> + u64 select_idx) {}
>  #endif
>  
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> new file mode 100644
> index 000..9d27999
> --- /dev/null
> +++ b/virt/kvm/arm/pmu.c
> @@ -0,0 +1,122 @@
> +/*
> + * Copyright (C) 2015 Linaro Ltd.
> + * Author: Shannon Zhao 
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see .
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +/**
> + * kvm_pmu_get_counter_value - get PMU counter value
> + * @vcpu: The vcpu pointer
> + * @select_idx: The counter index
> + */
> +u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
> +{
> + u64 counter, reg, enabled, running;
> + struct kvm_pmu *pmu = >arch.pmu;
> + struct kvm_pmc *pmc = >pmc[select_idx];
> +
> + reg = (select_idx == ARMV8_CYCLE_IDX)
> +   ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> + counter = vcpu_sys_reg(vcpu, reg);
> +
> + /* The real counter value is equal to the value of counter register plus
> +  * the value perf event counts.
> +  */
> + if (pmc->perf_event)
> + counter += perf_event_read_value(pmc->perf_event, ,
> +  );
> +
> + return counter & pmc->bitmask;
> +}
> +
> +/**
> + * kvm_pmu_stop_counter - stop PMU counter
> + * @pmc: The PMU counter pointer
> + *
> + * If this counter has been configured to monitor some event, release it 
> here.

Re: [PATCH v8 00/20] KVM: ARM64: Add guest PMU support

2016-01-07 Thread Marc Zyngier
On 07/01/16 14:12, Will Deacon wrote:
> On Thu, Jan 07, 2016 at 02:10:38PM +0000, Marc Zyngier wrote:
>> On 22/12/15 08:07, Shannon Zhao wrote:
>>> From: Shannon Zhao <shannon.z...@linaro.org>
>>>
>>> This patchset adds guest PMU support for KVM on ARM64. It takes
>>> trap-and-emulate approach. When guest wants to monitor one event, it
>>> will be trapped by KVM and KVM will call perf_event API to create a perf
>>> event and call relevant perf_event APIs to get the count value of event.
>>>
>>> Use perf to test this patchset in guest. When using "perf list", it
>>> shows the list of the hardware events and hardware cache events perf
>>> supports. Then use "perf stat -e EVENT" to monitor some event. For
>>> example, use "perf stat -e cycles" to count cpu cycles and
>>> "perf stat -e cache-misses" to count cache misses.
>>
>> I finally feel like we're pretty close to something we could merge. My
>> current concerns are:
> 
> The merge window opens on Monday and I'm not prepared to take further
> PMU changes at this point (unless they're bug fixes, of course).
> 
> This needs to wait until 4.6.

Fair enough. I guess I'll continue the review process and queue that
early in the next cycle.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 18/31] arm64: KVM: Add panic handling

2015-12-24 Thread Marc Zyngier
Add the panic handler, together with the small bits of assembly
code to call the kernel's panic implementation.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/hyp-entry.S | 11 ++-
 arch/arm64/kvm/hyp/hyp.h   |  1 +
 arch/arm64/kvm/hyp/switch.c| 30 ++
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 818731a..8e58a3b 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -155,7 +155,16 @@ el1_irq:
mov x1, #ARM_EXCEPTION_IRQ
b   __guest_exit
 
-.macro invalid_vector  label, target = __kvm_hyp_panic
+ENTRY(__hyp_do_panic)
+   mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
+ PSR_MODE_EL1h)
+   msr spsr_el2, lr
+   ldr lr, =panic
+   msr elr_el2, lr
+   eret
+ENDPROC(__hyp_do_panic)
+
+.macro invalid_vector  label, target = __hyp_panic
.align  2
 \label:
b \target
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index 70d4f69..fb27517 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -84,6 +84,7 @@ static inline bool __fpsimd_enabled(void)
 }
 
 u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
+void __noreturn __hyp_do_panic(unsigned long, ...);
 
 #endif /* __ARM64_KVM_HYP_H__ */
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 608155f..b012870 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -141,3 +141,33 @@ int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
 
return exit_code;
 }
+
+static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx 
ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
+
+void __hyp_text __noreturn __hyp_panic(void)
+{
+   unsigned long str_va = (unsigned long)__hyp_panic_string;
+   u64 spsr = read_sysreg(spsr_el2);
+   u64 elr = read_sysreg(elr_el2);
+   u64 par = read_sysreg(par_el1);
+
+   if (read_sysreg(vttbr_el2)) {
+   struct kvm_vcpu *vcpu;
+   struct kvm_cpu_context *host_ctxt;
+
+   vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2);
+   host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+   __deactivate_traps(vcpu);
+   __deactivate_vm(vcpu);
+   __sysreg_restore_state(host_ctxt);
+   }
+
+   /* Call panic for real */
+   __hyp_do_panic(hyp_kern_va(str_va),
+  spsr,  elr,
+  read_sysreg(esr_el2),   read_sysreg(far_el2),
+  read_sysreg(hpfar_el2), par,
+  (void *)read_sysreg(tpidr_el2));
+
+   unreachable();
+}
-- 
2.1.4

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


[PATCH 17/31] arm64: KVM: HYP mode entry points

2015-12-24 Thread Marc Zyngier
Add the entry points for HYP mode (both for hypercalls and
exception handling).

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/Makefile|   1 +
 arch/arm64/kvm/hyp/hyp-entry.S | 203 +
 2 files changed, 204 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/hyp-entry.S

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index 1a529f5..826032b 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += switch.o
 obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
 obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
+obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
new file mode 100644
index 000..818731a
--- /dev/null
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+   .text
+   .pushsection.hyp.text, "ax"
+
+.macro save_x0_to_x3
+   stp x0, x1, [sp, #-16]!
+   stp x2, x3, [sp, #-16]!
+.endm
+
+.macro restore_x0_to_x3
+   ldp x2, x3, [sp], #16
+   ldp x0, x1, [sp], #16
+.endm
+
+el1_sync:  // Guest trapped into EL2
+   save_x0_to_x3
+
+   mrs x1, esr_el2
+   lsr x2, x1, #ESR_ELx_EC_SHIFT
+
+   cmp x2, #ESR_ELx_EC_HVC64
+   b.neel1_trap
+
+   mrs x3, vttbr_el2   // If vttbr is valid, the 64bit guest
+   cbnzx3, el1_trap// called HVC
+
+   /* Here, we're pretty sure the host called HVC. */
+   restore_x0_to_x3
+
+   /* Check for __hyp_get_vectors */
+   cbnzx0, 1f
+   mrs x0, vbar_el2
+   b   2f
+
+1: stp lr, xzr, [sp, #-16]!
+
+   /*
+* Compute the function address in EL2, and shuffle the parameters.
+*/
+   kern_hyp_va x0
+   mov lr, x0
+   mov x0, x1
+   mov x1, x2
+   mov x2, x3
+   blr lr
+
+   ldp lr, xzr, [sp], #16
+2: eret
+
+el1_trap:
+   /*
+* x1: ESR
+* x2: ESR_EC
+*/
+
+   /* Guest accessed VFP/SIMD registers, save host, restore Guest */
+   cmp x2, #ESR_ELx_EC_FP_ASIMD
+   b.eq__fpsimd_guest_restore
+
+   cmp x2, #ESR_ELx_EC_DABT_LOW
+   mov x0, #ESR_ELx_EC_IABT_LOW
+   ccmpx2, x0, #4, ne
+   b.ne1f  // Not an abort we care about
+
+   /* This is an abort. Check for permission fault */
+alternative_if_not ARM64_WORKAROUND_834220
+   and x2, x1, #ESR_ELx_FSC_TYPE
+   cmp x2, #FSC_PERM
+   b.ne1f  // Not a permission fault
+alternative_else
+   nop // Use the permission fault path to
+   nop // check for a valid S1 translation,
+   nop // regardless of the ESR value.
+alternative_endif
+
+   /*
+* Check for Stage-1 page table walk, which is guaranteed
+* to give a valid HPFAR_EL2.
+*/
+   tbnzx1, #7, 1f  // S1PTW is set
+
+   /* Preserve PAR_EL1 */
+   mrs x3, par_el1
+   stp x3, xzr, [sp, #-16]!
+
+   /*
+* Permission fault, HPFAR_EL2 is invalid.
+* Resolve the IPA the hard way using the guest VA.
+* Stage-1 translation already validated the memory access rights.
+* As such, we can use the EL1 translation regime, and don't have
+* to distinguish between EL0 and EL1 access.
+*/
+   mrs x2, far_el2
+   at  s1e1r, x2
+   isb
+
+   /* Read result */
+   mrs x3, par_el1
+   ldp x0, xzr, [sp], #16  // Restore PAR_EL1 from the stack
+   msr par_el1, x0
+   tbnzx3, #0, 3f  // Bail out if we failed the translation
+   ubfxx3, x3, #12, #36// Extract IPA
+   lsl x3, x3, #4  // and present it like HPFAR
+   b   2f
+
+1: mrs x3, hpfar_el2
+   mrs x2, far_el2
+
+2: mrs x0, tpidr_el2
+   str w

[PATCH 25/31] ARM: KVM: Cleanup exception injection

2015-12-24 Thread Marc Zyngier
David Binderman reported that the exception injection code had a
couple of unused variables lingering around.

Upon examination, it looked like this code could do with an
anticipated spring cleaning, which amounts to deduplicating
the CPSR/SPSR update, and making it look a bit more like
the architecture spec.

The spurious variables are removed in the process.

Reported-by: David Binderman <dcb...@hotmail.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm/kvm/emulate.c | 74 ++
 1 file changed, 38 insertions(+), 36 deletions(-)

diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index d6c0052..dc99159 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -275,6 +275,40 @@ static u32 exc_vector_base(struct kvm_vcpu *vcpu)
return vbar;
 }
 
+/*
+ * Switch to an exception mode, updating both CPSR and SPSR. Follow
+ * the logic described in AArch32.EnterMode() from the ARMv8 ARM.
+ */
+static void kvm_update_psr(struct kvm_vcpu *vcpu, unsigned long mode)
+{
+   unsigned long cpsr = *vcpu_cpsr(vcpu);
+   u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
+
+   *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | mode;
+
+   switch (mode) {
+   case FIQ_MODE:
+   *vcpu_cpsr(vcpu) |= PSR_F_BIT;
+   /* Fall through */
+   case ABT_MODE:
+   case IRQ_MODE:
+   *vcpu_cpsr(vcpu) |= PSR_A_BIT;
+   /* Fall through */
+   default:
+   *vcpu_cpsr(vcpu) |= PSR_I_BIT;
+   }
+
+   *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
+
+   if (sctlr & SCTLR_TE)
+   *vcpu_cpsr(vcpu) |= PSR_T_BIT;
+   if (sctlr & SCTLR_EE)
+   *vcpu_cpsr(vcpu) |= PSR_E_BIT;
+
+   /* Note: These now point to the mode banked copies */
+   *vcpu_spsr(vcpu) = cpsr;
+}
+
 /**
  * kvm_inject_undefined - inject an undefined exception into the guest
  * @vcpu: The VCPU to receive the undefined exception
@@ -286,29 +320,13 @@ static u32 exc_vector_base(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 {
-   unsigned long new_lr_value;
-   unsigned long new_spsr_value;
unsigned long cpsr = *vcpu_cpsr(vcpu);
-   u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
bool is_thumb = (cpsr & PSR_T_BIT);
u32 vect_offset = 4;
u32 return_offset = (is_thumb) ? 2 : 4;
 
-   new_spsr_value = cpsr;
-   new_lr_value = *vcpu_pc(vcpu) - return_offset;
-
-   *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | UND_MODE;
-   *vcpu_cpsr(vcpu) |= PSR_I_BIT;
-   *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
-
-   if (sctlr & SCTLR_TE)
-   *vcpu_cpsr(vcpu) |= PSR_T_BIT;
-   if (sctlr & SCTLR_EE)
-   *vcpu_cpsr(vcpu) |= PSR_E_BIT;
-
-   /* Note: These now point to UND banked copies */
-   *vcpu_spsr(vcpu) = cpsr;
-   *vcpu_reg(vcpu, 14) = new_lr_value;
+   kvm_update_psr(vcpu, UND_MODE);
+   *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) - return_offset;
 
/* Branch to exception vector */
*vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
@@ -320,30 +338,14 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
  */
 static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
 {
-   unsigned long new_lr_value;
-   unsigned long new_spsr_value;
unsigned long cpsr = *vcpu_cpsr(vcpu);
-   u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
bool is_thumb = (cpsr & PSR_T_BIT);
u32 vect_offset;
u32 return_offset = (is_thumb) ? 4 : 0;
bool is_lpae;
 
-   new_spsr_value = cpsr;
-   new_lr_value = *vcpu_pc(vcpu) + return_offset;
-
-   *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | ABT_MODE;
-   *vcpu_cpsr(vcpu) |= PSR_I_BIT | PSR_A_BIT;
-   *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
-
-   if (sctlr & SCTLR_TE)
-   *vcpu_cpsr(vcpu) |= PSR_T_BIT;
-   if (sctlr & SCTLR_EE)
-   *vcpu_cpsr(vcpu) |= PSR_E_BIT;
-
-   /* Note: These now point to ABT banked copies */
-   *vcpu_spsr(vcpu) = cpsr;
-   *vcpu_reg(vcpu, 14) = new_lr_value;
+   kvm_update_psr(vcpu, ABT_MODE);
+   *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
 
if (is_pabt)
vect_offset = 12;
-- 
2.1.4

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


[PATCH 22/31] arm64: KVM: Turn system register numbers to an enum

2015-12-24 Thread Marc Zyngier
Having the system register numbers as #defines has been a pain
since day one, as the ordering is pretty fragile, and moving
things around leads to renumbering and epic conflict resolutions.

Now that we're mostly acessing the sysreg file in C, an enum is
a much better type to use, and we can clean things up a bit.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/include/asm/kvm_asm.h | 76 -
 arch/arm64/include/asm/kvm_emulate.h |  1 -
 arch/arm64/include/asm/kvm_host.h| 81 +++-
 arch/arm64/include/asm/kvm_mmio.h|  1 -
 arch/arm64/kernel/asm-offsets.c  |  1 +
 arch/arm64/kvm/guest.c   |  1 -
 arch/arm64/kvm/handle_exit.c |  1 +
 arch/arm64/kvm/hyp/debug-sr.c|  1 +
 arch/arm64/kvm/hyp/entry.S   |  3 +-
 arch/arm64/kvm/hyp/sysreg-sr.c   |  1 +
 arch/arm64/kvm/sys_regs.c|  1 +
 virt/kvm/arm/vgic-v3.c   |  1 +
 12 files changed, 87 insertions(+), 82 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 5e37710..52b777b 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -20,82 +20,6 @@
 
 #include 
 
-/*
- * 0 is reserved as an invalid value.
- * Order *must* be kept in sync with the hyp switch code.
- */
-#defineMPIDR_EL1   1   /* MultiProcessor Affinity Register */
-#defineCSSELR_EL1  2   /* Cache Size Selection Register */
-#defineSCTLR_EL1   3   /* System Control Register */
-#defineACTLR_EL1   4   /* Auxiliary Control Register */
-#defineCPACR_EL1   5   /* Coprocessor Access Control */
-#defineTTBR0_EL1   6   /* Translation Table Base Register 0 */
-#defineTTBR1_EL1   7   /* Translation Table Base Register 1 */
-#defineTCR_EL1 8   /* Translation Control Register */
-#defineESR_EL1 9   /* Exception Syndrome Register */
-#defineAFSR0_EL1   10  /* Auxilary Fault Status Register 0 */
-#defineAFSR1_EL1   11  /* Auxilary Fault Status Register 1 */
-#defineFAR_EL1 12  /* Fault Address Register */
-#defineMAIR_EL113  /* Memory Attribute Indirection 
Register */
-#defineVBAR_EL114  /* Vector Base Address Register */
-#defineCONTEXTIDR_EL1  15  /* Context ID Register */
-#defineTPIDR_EL0   16  /* Thread ID, User R/W */
-#defineTPIDRRO_EL0 17  /* Thread ID, User R/O */
-#defineTPIDR_EL1   18  /* Thread ID, Privileged */
-#defineAMAIR_EL1   19  /* Aux Memory Attribute Indirection 
Register */
-#defineCNTKCTL_EL1 20  /* Timer Control Register (EL1) */
-#definePAR_EL1 21  /* Physical Address Register */
-#define MDSCR_EL1  22  /* Monitor Debug System Control Register */
-#define MDCCINT_EL123  /* Monitor Debug Comms Channel Interrupt Enable 
Reg */
-
-/* 32bit specific registers. Keep them at the end of the range */
-#defineDACR32_EL2  24  /* Domain Access Control Register */
-#defineIFSR32_EL2  25  /* Instruction Fault Status Register */
-#defineFPEXC32_EL2 26  /* Floating-Point Exception Control 
Register */
-#defineDBGVCR32_EL227  /* Debug Vector Catch Register */
-#defineNR_SYS_REGS 28
-
-/* 32bit mapping */
-#define c0_MPIDR   (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
-#define c0_CSSELR  (CSSELR_EL1 * 2)/* Cache Size Selection Register */
-#define c1_SCTLR   (SCTLR_EL1 * 2) /* System Control Register */
-#define c1_ACTLR   (ACTLR_EL1 * 2) /* Auxiliary Control Register */
-#define c1_CPACR   (CPACR_EL1 * 2) /* Coprocessor Access Control */
-#define c2_TTBR0   (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
-#define c2_TTBR0_high  (c2_TTBR0 + 1)  /* TTBR0 top 32 bits */
-#define c2_TTBR1   (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
-#define c2_TTBR1_high  (c2_TTBR1 + 1)  /* TTBR1 top 32 bits */
-#define c2_TTBCR   (TCR_EL1 * 2)   /* Translation Table Base Control R. */
-#define c3_DACR(DACR32_EL2 * 2)/* Domain Access Control 
Register */
-#define c5_DFSR(ESR_EL1 * 2)   /* Data Fault Status Register */
-#define c5_IFSR(IFSR32_EL2 * 2)/* Instruction Fault Status 
Register */
-#define c5_ADFSR   (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
-#define c5_AIFSR   (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
-#define c6_DFAR(FAR_EL1 * 2)   /* Data Fault Address Register 
*/
-#define c6_IFAR(c6_DFAR + 1)   /* Instruction Fault Address 
Register */
-#define c7_PAR (PAR_EL1 * 2)   /* Physical Address Register

[PATCH 21/31] arm64: KVM: Move away from the assembly version of the world switch

2015-12-24 Thread Marc Zyngier
This is it. We remove all of the code that has now been rewritten.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/Makefile |2 -
 arch/arm64/kvm/hyp.S| 1081 +--
 arch/arm64/kvm/vgic-v2-switch.S |  134 -
 arch/arm64/kvm/vgic-v3-switch.S |  269 --
 4 files changed, 1 insertion(+), 1485 deletions(-)
 delete mode 100644 arch/arm64/kvm/vgic-v2-switch.S
 delete mode 100644 arch/arm64/kvm/vgic-v3-switch.S

diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d31e4e5..caee9ee 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -23,8 +23,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o 
sys_regs.o sys_regs_generi
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
-kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v2-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
-kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index 86c2898..0ccdcbb 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -17,910 +17,7 @@
 
 #include 
 
-#include 
-#include 
 #include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#define CPU_GP_REG_OFFSET(x)   (CPU_GP_REGS + x)
-#define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
-#define CPU_SPSR_OFFSET(x) CPU_GP_REG_OFFSET(CPU_SPSR + 8*x)
-#define CPU_SYSREG_OFFSET(x)   (CPU_SYSREGS + 8*x)
-
-   .text
-   .pushsection.hyp.text, "ax"
-   .align  PAGE_SHIFT
-
-.macro save_common_regs
-   // x2: base address for cpu context
-   // x3: tmp register
-
-   add x3, x2, #CPU_XREG_OFFSET(19)
-   stp x19, x20, [x3]
-   stp x21, x22, [x3, #16]
-   stp x23, x24, [x3, #32]
-   stp x25, x26, [x3, #48]
-   stp x27, x28, [x3, #64]
-   stp x29, lr, [x3, #80]
-
-   mrs x19, sp_el0
-   mrs x20, elr_el2// pc before entering el2
-   mrs x21, spsr_el2   // pstate before entering el2
-
-   stp x19, x20, [x3, #96]
-   str x21, [x3, #112]
-
-   mrs x22, sp_el1
-   mrs x23, elr_el1
-   mrs x24, spsr_el1
-
-   str x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
-   str x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
-   str x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
-.endm
-
-.macro restore_common_regs
-   // x2: base address for cpu context
-   // x3: tmp register
-
-   ldr x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
-   ldr x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
-   ldr x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
-
-   msr sp_el1, x22
-   msr elr_el1, x23
-   msr spsr_el1, x24
-
-   add x3, x2, #CPU_XREG_OFFSET(31)// SP_EL0
-   ldp x19, x20, [x3]
-   ldr x21, [x3, #16]
-
-   msr sp_el0, x19
-   msr elr_el2, x20// pc on return from el2
-   msr spsr_el2, x21   // pstate on return from el2
-
-   add x3, x2, #CPU_XREG_OFFSET(19)
-   ldp x19, x20, [x3]
-   ldp x21, x22, [x3, #16]
-   ldp x23, x24, [x3, #32]
-   ldp x25, x26, [x3, #48]
-   ldp x27, x28, [x3, #64]
-   ldp x29, lr, [x3, #80]
-.endm
-
-.macro save_host_regs
-   save_common_regs
-.endm
-
-.macro restore_host_regs
-   restore_common_regs
-.endm
-
-.macro save_fpsimd
-   // x2: cpu context address
-   // x3, x4: tmp regs
-   add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
-   fpsimd_save x3, 4
-.endm
-
-.macro restore_fpsimd
-   // x2: cpu context address
-   // x3, x4: tmp regs
-   add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
-   fpsimd_restore x3, 4
-.endm
-
-.macro save_guest_regs
-   // x0 is the vcpu address
-   // x1 is the return code, do not corrupt!
-   // x2 is the cpu context
-   // x3 is a tmp register
-   // Guest's x0-x3 are on the stack
-
-   // Compute base to save registers
-   add x3, x2, #CPU_XREG_OFFSET(4)
-   stp x4, x5, [x3]
-   stp x6, x7, [x3, #16]
-   stp x8, x9, [x3, #32]
-   stp x10, x11, [x3, #48]
-   stp x12, x13, [x3, #64]
-   stp x14, x15, [x3, #80]
-   stp x16, x17, [x3, #96]
-   str x18, [x3, #112]
-
-   pop x6, x7  // x2, x3
-   pop x4, x5  // x0, x1
-
-   add x3, x2, #CPU_XREG_OFFSET(0)
-   stp x4, x5, [x3]
-   stp x6, x7, [x3, #16]
-
-   save_common_regs
-.endm
-
-.macro restore_guest_regs
-  

[PATCH 09/31] arm64: KVM: Implement system register save/restore

2015-12-24 Thread Marc Zyngier
Implement the system register save/restore as a direct translation of
the assembly code version.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/Makefile|  1 +
 arch/arm64/kvm/hyp/hyp.h   |  3 ++
 arch/arm64/kvm/hyp/sysreg-sr.c | 90 ++
 3 files changed, 94 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/sysreg-sr.c

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index 455dc0a..ec94200 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index f213e46..778d56d 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -38,5 +38,8 @@ void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
 void __timer_save_state(struct kvm_vcpu *vcpu);
 void __timer_restore_state(struct kvm_vcpu *vcpu);
 
+void __sysreg_save_state(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
+
 #endif /* __ARM64_KVM_HYP_H__ */
 
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
new file mode 100644
index 000..add8fcb
--- /dev/null
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+
+#include 
+
+#include "hyp.h"
+
+/* ctxt is already in the HYP VA space */
+void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
+{
+   ctxt->sys_regs[MPIDR_EL1]   = read_sysreg(vmpidr_el2);
+   ctxt->sys_regs[CSSELR_EL1]  = read_sysreg(csselr_el1);
+   ctxt->sys_regs[SCTLR_EL1]   = read_sysreg(sctlr_el1);
+   ctxt->sys_regs[ACTLR_EL1]   = read_sysreg(actlr_el1);
+   ctxt->sys_regs[CPACR_EL1]   = read_sysreg(cpacr_el1);
+   ctxt->sys_regs[TTBR0_EL1]   = read_sysreg(ttbr0_el1);
+   ctxt->sys_regs[TTBR1_EL1]   = read_sysreg(ttbr1_el1);
+   ctxt->sys_regs[TCR_EL1] = read_sysreg(tcr_el1);
+   ctxt->sys_regs[ESR_EL1] = read_sysreg(esr_el1);
+   ctxt->sys_regs[AFSR0_EL1]   = read_sysreg(afsr0_el1);
+   ctxt->sys_regs[AFSR1_EL1]   = read_sysreg(afsr1_el1);
+   ctxt->sys_regs[FAR_EL1] = read_sysreg(far_el1);
+   ctxt->sys_regs[MAIR_EL1]= read_sysreg(mair_el1);
+   ctxt->sys_regs[VBAR_EL1]= read_sysreg(vbar_el1);
+   ctxt->sys_regs[CONTEXTIDR_EL1]  = read_sysreg(contextidr_el1);
+   ctxt->sys_regs[TPIDR_EL0]   = read_sysreg(tpidr_el0);
+   ctxt->sys_regs[TPIDRRO_EL0] = read_sysreg(tpidrro_el0);
+   ctxt->sys_regs[TPIDR_EL1]   = read_sysreg(tpidr_el1);
+   ctxt->sys_regs[AMAIR_EL1]   = read_sysreg(amair_el1);
+   ctxt->sys_regs[CNTKCTL_EL1] = read_sysreg(cntkctl_el1);
+   ctxt->sys_regs[PAR_EL1] = read_sysreg(par_el1);
+   ctxt->sys_regs[MDSCR_EL1]   = read_sysreg(mdscr_el1);
+
+   ctxt->gp_regs.regs.sp   = read_sysreg(sp_el0);
+   ctxt->gp_regs.regs.pc   = read_sysreg(elr_el2);
+   ctxt->gp_regs.regs.pstate   = read_sysreg(spsr_el2);
+   ctxt->gp_regs.sp_el1= read_sysreg(sp_el1);
+   ctxt->gp_regs.elr_el1   = read_sysreg(elr_el1);
+   ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg(spsr_el1);
+}
+
+void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
+{
+   write_sysreg(ctxt->sys_regs[MPIDR_EL1],   vmpidr_el2);
+   write_sysreg(ctxt->sys_regs[CSSELR_EL1],  csselr_el1);
+   write_sysreg(ctxt->sys_regs[SCTLR_EL1],   sctlr_el1);
+   write_sysreg(ctxt->sys_regs[ACTLR_EL1],   actlr_el1);
+   write_sysreg(ctxt->sys_regs[CPACR_EL1],   cpacr_el1);
+   write_sysreg(ctxt->sys_regs[TTBR0_EL1],   ttbr0_el1);
+   write_sysreg(ctxt->sys_regs[TTBR1_EL1],   ttbr1_el1);
+   write_sysreg(ctxt->sys_regs[TCR_EL1], tcr_el1);
+   write_sysreg(ctxt->sys_regs[ESR_EL1], esr_el1);
+   write_sysreg(c

[PATCH 07/31] arm64: KVM: Implement vgic-v3 save/restore

2015-12-24 Thread Marc Zyngier
Implement the vgic-v3 save restore as a direct translation of
the assembly code version.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/hyp/Makefile |   1 +
 arch/arm64/kvm/hyp/hyp.h|   3 +
 arch/arm64/kvm/hyp/vgic-v3-sr.c | 226 
 3 files changed, 230 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/vgic-v3-sr.c

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index d8d5968..d1e38ce 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index ac63553..5759f9f 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -32,5 +32,8 @@
 void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 
+void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+
 #endif /* __ARM64_KVM_HYP_H__ */
 
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
new file mode 100644
index 000..78d05f3
--- /dev/null
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+
+#include "hyp.h"
+
+#define vtr_to_max_lr_idx(v)   ((v) & 0xf)
+#define vtr_to_nr_pri_bits(v)  (((u32)(v) >> 29) + 1)
+
+#define read_gicreg(r) \
+   ({  \
+   u64 reg;\
+   asm volatile("mrs_s %0, " __stringify(r) : "=r" (reg)); \
+   reg;\
+   })
+
+#define write_gicreg(v,r)  \
+   do {\
+   u64 __val = (v);\
+   asm volatile("msr_s " __stringify(r) ", %0" : : "r" (__val));\
+   } while (0)
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
+{
+   struct vgic_v3_cpu_if *cpu_if = >arch.vgic_cpu.vgic_v3;
+   u64 val;
+   u32 max_lr_idx, nr_pri_bits;
+
+   /*
+* Make sure stores to the GIC via the memory mapped interface
+* are now visible to the system register interface.
+*/
+   dsb(st);
+
+   cpu_if->vgic_vmcr  = read_gicreg(ICH_VMCR_EL2);
+   cpu_if->vgic_misr  = read_gicreg(ICH_MISR_EL2);
+   cpu_if->vgic_eisr  = read_gicreg(ICH_EISR_EL2);
+   cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
+
+   write_gicreg(0, ICH_HCR_EL2);
+   val = read_gicreg(ICH_VTR_EL2);
+   max_lr_idx = vtr_to_max_lr_idx(val);
+   nr_pri_bits = vtr_to_nr_pri_bits(val);
+
+   switch (max_lr_idx) {
+   case 15:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)] = 
read_gicreg(ICH_LR15_EL2);
+   case 14:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(14)] = 
read_gicreg(ICH_LR14_EL2);
+   case 13:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(13)] = 
read_gicreg(ICH_LR13_EL2);
+   case 12:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(12)] = 
read_gicreg(ICH_LR12_EL2);
+   case 11:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(11)] = 
read_gicreg(ICH_LR11_EL2);
+   case 10:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(10)] = 
read_gicreg(ICH_LR10_EL2);
+   case 9:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(9)] = read_gicreg(ICH_LR9_EL2);
+   case 8:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(8)] = read_gicreg(ICH_LR8_EL2);
+   case 7:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(7)] = read_gicreg(ICH_LR7_EL2);
+   case 6:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(6)] = read_gicreg(ICH_LR6_EL2);
+   case 5:
+   cpu_if->vgic_lr[VGIC_V3_LR_INDEX(5)] = read_gicreg(ICH_LR5_EL2);
+   case 4:
+   cpu_if->vgic_lr[VGIC

[PATCH 19/31] arm64: KVM: Add compatibility aliases

2015-12-24 Thread Marc Zyngier
So far, we've implemented the new world switch with a completely
different namespace, so that we could have both implementation
compiled in.

Let's take things one step further by adding weak aliases that
have the same names as the original implementation. The weak
attributes allows the new implementation to be overriden by the
old one, and everything still work.

At a later point, we'll be able to simply drop the old code, and
everything will hopefully keep working, thanks to the aliases we
have just added. This also saves us repainting all the callers.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/debug-sr.c   | 3 +++
 arch/arm64/kvm/hyp/hyp-entry.S  | 3 +++
 arch/arm64/kvm/hyp/switch.c | 3 +++
 arch/arm64/kvm/hyp/tlb.c| 9 +
 arch/arm64/kvm/hyp/vgic-v3-sr.c | 3 +++
 5 files changed, 21 insertions(+)

diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index 7848322..d071f45 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -135,3 +135,6 @@ u32 __hyp_text __debug_read_mdcr_el2(void)
 {
return read_sysreg(mdcr_el2);
 }
+
+__alias(__debug_read_mdcr_el2)
+u32 __weak __kvm_get_mdcr_el2(void);
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 8e58a3b..10d6d2a 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -189,6 +189,8 @@ ENDPROC(\label)
 
.align 11
 
+   .weak   __kvm_hyp_vector
+ENTRY(__kvm_hyp_vector)
 ENTRY(__hyp_vector)
ventry  el2t_sync_invalid   // Synchronous EL2t
ventry  el2t_irq_invalid// IRQ EL2t
@@ -210,3 +212,4 @@ ENTRY(__hyp_vector)
ventry  el1_fiq_invalid // FIQ 32-bit EL1
ventry  el1_error_invalid   // Error 32-bit EL1
 ENDPROC(__hyp_vector)
+ENDPROC(__kvm_hyp_vector)
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index b012870..7457ae4 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -142,6 +142,9 @@ int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
return exit_code;
 }
 
+__alias(__guest_run)
+int __weak __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+
 static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx 
ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
 
 void __hyp_text __noreturn __hyp_panic(void)
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index 6fcb93a..5f815cf 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -48,6 +48,9 @@ void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, 
phys_addr_t ipa)
write_sysreg(0, vttbr_el2);
 }
 
+__alias(__tlb_flush_vmid_ipa)
+void __weak __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
+
 void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
 {
dsb(ishst);
@@ -64,6 +67,9 @@ void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
write_sysreg(0, vttbr_el2);
 }
 
+__alias(__tlb_flush_vmid)
+void __weak __kvm_tlb_flush_vmid(struct kvm *kvm);
+
 void __hyp_text __tlb_flush_vm_context(void)
 {
dsb(ishst);
@@ -71,3 +77,6 @@ void __hyp_text __tlb_flush_vm_context(void)
 "ic ialluis  ": : );
dsb(ish);
 }
+
+__alias(__tlb_flush_vm_context)
+void __weak __kvm_flush_vm_context(void);
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 78d05f3..a769458 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -224,3 +224,6 @@ u64 __hyp_text __vgic_v3_read_ich_vtr_el2(void)
 {
return read_gicreg(ICH_VTR_EL2);
 }
+
+__alias(__vgic_v3_read_ich_vtr_el2)
+u64 __weak __vgic_v3_get_ich_vtr_el2(void);
-- 
2.1.4

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


[PATCH 13/31] arm64: KVM: Add patchable function selector

2015-12-24 Thread Marc Zyngier
KVM so far relies on code patching, and is likely to use it more
in the future. The main issue is that our alternative system works
at the instruction level, while we'd like to have alternatives at
the function level.

In order to cope with this, add the "hyp_alternate_select" macro that
outputs a brief sequence of code that in turn can be patched, allowing
an alternative function to be selected.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/hyp/hyp.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index 0809653..73419a7 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -29,6 +29,30 @@
 #define hyp_kern_va(v) (typeof(v))((unsigned long)(v) - HYP_PAGE_OFFSET \
  + PAGE_OFFSET)
 
+/**
+ * hyp_alternate_select - Generates patchable code sequences that are
+ * used to switch between two implementations of a function, depending
+ * on the availability of a feature.
+ *
+ * @fname: a symbol name that will be defined as a function returning a
+ * function pointer whose type will match @orig and @alt
+ * @orig: A pointer to the default function, as returned by @fname when
+ * @cond doesn't hold
+ * @alt: A pointer to the alternate function, as returned by @fname
+ * when @cond holds
+ * @cond: a CPU feature (as described in asm/cpufeature.h)
+ */
+#define hyp_alternate_select(fname, orig, alt, cond)   \
+typeof(orig) * __hyp_text fname(void)  \
+{  \
+   typeof(alt) *val = orig;\
+   asm volatile(ALTERNATIVE("nop   \n",\
+"mov   %0, %1  \n",\
+cond)  \
+: "+r" (val) : "r" (alt)); \
+   return val; \
+}
+
 void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 
-- 
2.1.4

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


[PATCH 15/31] arm64: KVM: Implement fpsimd save/restore

2015-12-24 Thread Marc Zyngier
Implement the fpsimd save restore, keeping the lazy part in
assembler (as returning to C would be overkill).

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/Makefile|  1 +
 arch/arm64/kvm/hyp/entry.S | 32 +++-
 arch/arm64/kvm/hyp/fpsimd.S| 33 +
 arch/arm64/kvm/hyp/hyp.h   |  7 +++
 arch/arm64/kvm/hyp/switch.c|  8 
 arch/arm64/kvm/hyp/sysreg-sr.c |  2 +-
 6 files changed, 81 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/kvm/hyp/fpsimd.S

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index 9c11b0f..56238d0 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += switch.o
+obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index ff19695..90cbf0f 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -27,6 +27,7 @@
 
 #define CPU_GP_REG_OFFSET(x)   (CPU_GP_REGS + x)
 #define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
+#define CPU_SYSREG_OFFSET(x)   (CPU_SYSREGS + 8*x)
 
.text
.pushsection.hyp.text, "ax"
@@ -127,4 +128,33 @@ ENTRY(__guest_exit)
ret
 ENDPROC(__guest_exit)
 
-   /* Insert fault handling here */
+ENTRY(__fpsimd_guest_restore)
+   stp x4, lr, [sp, #-16]!
+
+   mrs x2, cptr_el2
+   bic x2, x2, #CPTR_EL2_TFP
+   msr cptr_el2, x2
+   isb
+
+   mrs x3, tpidr_el2
+
+   ldr x0, [x3, #VCPU_HOST_CONTEXT]
+   kern_hyp_va x0
+   add x0, x0, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+   bl  __fpsimd_save_state
+
+   add x2, x3, #VCPU_CONTEXT
+   add x0, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+   bl  __fpsimd_restore_state
+
+   mrs x1, hcr_el2
+   tbnzx1, #HCR_RW_SHIFT, 1f
+   ldr x4, [x2, #CPU_SYSREG_OFFSET(FPEXC32_EL2)]
+   msr fpexc32_el2, x4
+1:
+   ldp x4, lr, [sp], #16
+   ldp x2, x3, [sp], #16
+   ldp x0, x1, [sp], #16
+
+   eret
+ENDPROC(__fpsimd_guest_restore)
diff --git a/arch/arm64/kvm/hyp/fpsimd.S b/arch/arm64/kvm/hyp/fpsimd.S
new file mode 100644
index 000..da3f22c
--- /dev/null
+++ b/arch/arm64/kvm/hyp/fpsimd.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+
+#include 
+
+   .text
+   .pushsection.hyp.text, "ax"
+
+ENTRY(__fpsimd_save_state)
+   fpsimd_save x0, 1
+   ret
+ENDPROC(__fpsimd_save_state)
+
+ENTRY(__fpsimd_restore_state)
+   fpsimd_restore  x0, 1
+   ret
+ENDPROC(__fpsimd_restore_state)
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index 73419a7..70d4f69 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -76,6 +76,13 @@ void __debug_restore_state(struct kvm_vcpu *vcpu,
 void __debug_cond_save_host_state(struct kvm_vcpu *vcpu);
 void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu);
 
+void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
+void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
+static inline bool __fpsimd_enabled(void)
+{
+   return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
+}
+
 u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
 
 #endif /* __ARM64_KVM_HYP_H__ */
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 79f59c9..608155f 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -89,6 +89,7 @@ int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
 {
struct kvm_cpu_context *host_ctxt;
struct kvm_cpu_context *guest_ctxt;
+   bool fp_enabled;
u64 exit_code;
 
vcpu = kern_hyp_va(vcpu);
@@ -118,6 +119,8 @@ int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
exit_code = __guest_enter(vcpu, host_ctxt);
/* And we're baaack! */
 
+   fp_enabled = __fpsimd_enabled();
+
__sysreg_save_state(guest_ctxt);
__sysreg32_save_state(vcpu);
__timer_save_

[PATCH 12/31] arm64: KVM: Implement guest entry

2015-12-24 Thread Marc Zyngier
Contrary to the previous patch, the guest entry is fairly different
from its assembly counterpart, mostly because it is only concerned
with saving/restoring the GP registers, and nothing else.

Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/hyp/Makefile |   1 +
 arch/arm64/kvm/hyp/entry.S  | 130 
 arch/arm64/kvm/hyp/hyp.h|   2 +
 3 files changed, 133 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/entry.S

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index ec14cac..1e1ff06 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += entry.o
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
new file mode 100644
index 000..ff19695
--- /dev/null
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define CPU_GP_REG_OFFSET(x)   (CPU_GP_REGS + x)
+#define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
+
+   .text
+   .pushsection.hyp.text, "ax"
+
+.macro save_callee_saved_regs ctxt
+   stp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
+   stp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
+   stp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
+   stp x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
+   stp x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
+   stp x29, lr,  [\ctxt, #CPU_XREG_OFFSET(29)]
+.endm
+
+.macro restore_callee_saved_regs ctxt
+   ldp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
+   ldp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
+   ldp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
+   ldp x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
+   ldp x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
+   ldp x29, lr,  [\ctxt, #CPU_XREG_OFFSET(29)]
+.endm
+
+/*
+ * u64 __guest_enter(struct kvm_vcpu *vcpu,
+ *  struct kvm_cpu_context *host_ctxt);
+ */
+ENTRY(__guest_enter)
+   // x0: vcpu
+   // x1: host/guest context
+   // x2-x18: clobbered by macros
+
+   // Store the host regs
+   save_callee_saved_regs x1
+
+   // Preserve vcpu & host_ctxt for use at exit time
+   stp x0, x1, [sp, #-16]!
+
+   add x1, x0, #VCPU_CONTEXT
+
+   // Prepare x0-x1 for later restore by pushing them onto the stack
+   ldp x2, x3, [x1, #CPU_XREG_OFFSET(0)]
+   stp x2, x3, [sp, #-16]!
+
+   // x2-x18
+   ldp x2, x3,   [x1, #CPU_XREG_OFFSET(2)]
+   ldp x4, x5,   [x1, #CPU_XREG_OFFSET(4)]
+   ldp x6, x7,   [x1, #CPU_XREG_OFFSET(6)]
+   ldp x8, x9,   [x1, #CPU_XREG_OFFSET(8)]
+   ldp x10, x11, [x1, #CPU_XREG_OFFSET(10)]
+   ldp x12, x13, [x1, #CPU_XREG_OFFSET(12)]
+   ldp x14, x15, [x1, #CPU_XREG_OFFSET(14)]
+   ldp x16, x17, [x1, #CPU_XREG_OFFSET(16)]
+   ldr x18,  [x1, #CPU_XREG_OFFSET(18)]
+
+   // x19-x29, lr
+   restore_callee_saved_regs x1
+
+   // Last bits of the 64bit state
+   ldp x0, x1, [sp], #16
+
+   // Do not touch any register after this!
+   eret
+ENDPROC(__guest_enter)
+
+ENTRY(__guest_exit)
+   // x0: vcpu
+   // x1: return code
+   // x2-x3: free
+   // x4-x29,lr: vcpu regs
+   // vcpu x0-x3 on the stack
+
+   add x2, x0, #VCPU_CONTEXT
+
+   stp x4, x5,   [x2, #CPU_XREG_OFFSET(4)]
+   stp x6, x7,   [x2, #CPU_XREG_OFFSET(6)]
+   stp x8, x9,   [x2, #CPU_XREG_OFFSET(8)]
+   stp x10, x11, [x2, #CPU_XREG_OFFSET(10)]
+   stp x12, x13, [x2, #CPU_XREG_OFFSET(12)]
+   stp x14, x15, [x2, #CPU_XREG_OFFSET(14)]
+   stp x16, x17, [x2, #CPU_XREG_OFFSET(16)]
+   str x18,  [x2, #CPU_XREG_OFFSET(18)]
+
+   ldp x6, x7, [sp], #16   // x2, x3
+   ldp x4, x5, [sp], #16   // x0, x1
+
+   stp x4, x5, [x2, #CPU_XREG_OFFSET(0)]
+   s

[PATCH 10/31] arm64: KVM: Implement 32bit system register save/restore

2015-12-24 Thread Marc Zyngier
Implement the 32bit system register save/restore as a direct
translation of the assembly code version.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/hyp.h   |  2 ++
 arch/arm64/kvm/hyp/sysreg-sr.c | 47 ++
 2 files changed, 49 insertions(+)

diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index 778d56d..bffd308 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -40,6 +40,8 @@ void __timer_restore_state(struct kvm_vcpu *vcpu);
 
 void __sysreg_save_state(struct kvm_cpu_context *ctxt);
 void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
+void __sysreg32_save_state(struct kvm_vcpu *vcpu);
+void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
 
 #endif /* __ARM64_KVM_HYP_H__ */
 
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index add8fcb..eb05afb 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -88,3 +88,50 @@ void __hyp_text __sysreg_restore_state(struct 
kvm_cpu_context *ctxt)
write_sysreg(ctxt->gp_regs.elr_el1, elr_el1);
write_sysreg(ctxt->gp_regs.spsr[KVM_SPSR_EL1], spsr_el1);
 }
+
+void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
+{
+   u64 *spsr, *sysreg;
+
+   if (read_sysreg(hcr_el2) & HCR_RW)
+   return;
+
+   spsr = vcpu->arch.ctxt.gp_regs.spsr;
+   sysreg = vcpu->arch.ctxt.sys_regs;
+
+   spsr[KVM_SPSR_ABT] = read_sysreg(spsr_abt);
+   spsr[KVM_SPSR_UND] = read_sysreg(spsr_und);
+   spsr[KVM_SPSR_IRQ] = read_sysreg(spsr_irq);
+   spsr[KVM_SPSR_FIQ] = read_sysreg(spsr_fiq);
+
+   sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
+   sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
+
+   if (!(read_sysreg(cptr_el2) & CPTR_EL2_TFP))
+   sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
+
+   if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+   sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
+}
+
+void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
+{
+   u64 *spsr, *sysreg;
+
+   if (read_sysreg(hcr_el2) & HCR_RW)
+   return;
+
+   spsr = vcpu->arch.ctxt.gp_regs.spsr;
+   sysreg = vcpu->arch.ctxt.sys_regs;
+
+   write_sysreg(spsr[KVM_SPSR_ABT], spsr_abt);
+   write_sysreg(spsr[KVM_SPSR_UND], spsr_und);
+   write_sysreg(spsr[KVM_SPSR_IRQ], spsr_irq);
+   write_sysreg(spsr[KVM_SPSR_FIQ], spsr_fiq);
+
+   write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
+   write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
+
+   if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+   write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
+}
-- 
2.1.4

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


[PATCH 02/31] KVM: arm/arm64: Count guest exit due to various reasons

2015-12-24 Thread Marc Zyngier
From: Amit Tomar 

It would add guest exit statistics to debugfs, this can be helpful
while measuring KVM performance.

  [ Renamed some of the field names - Christoffer ]

Signed-off-by: Amit Singh Tomar 
Signed-off-by: Christoffer Dall 
---
 arch/arm/include/asm/kvm_host.h   | 6 ++
 arch/arm/kvm/arm.c| 1 +
 arch/arm/kvm/guest.c  | 6 ++
 arch/arm/kvm/handle_exit.c| 3 +++
 arch/arm/kvm/mmio.c   | 3 +++
 arch/arm64/include/asm/kvm_host.h | 6 ++
 arch/arm64/kvm/guest.c| 9 +
 arch/arm64/kvm/handle_exit.c  | 3 +++
 8 files changed, 37 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 6692982..f9f2779 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -150,6 +150,12 @@ struct kvm_vcpu_stat {
u32 halt_successful_poll;
u32 halt_attempted_poll;
u32 halt_wakeup;
+   u32 hvc_exit_stat;
+   u64 wfe_exit_stat;
+   u64 wfi_exit_stat;
+   u64 mmio_exit_user;
+   u64 mmio_exit_kernel;
+   u64 exits;
 };
 
 int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index e06fd29..8a79a57 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -603,6 +603,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
 
vcpu->mode = OUTSIDE_GUEST_MODE;
+   vcpu->stat.exits++;
/*
 * Back from guest
 */
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 96e935b..5fa69d7 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -33,6 +33,12 @@
 #define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
+   VCPU_STAT(hvc_exit_stat),
+   VCPU_STAT(wfe_exit_stat),
+   VCPU_STAT(wfi_exit_stat),
+   VCPU_STAT(mmio_exit_user),
+   VCPU_STAT(mmio_exit_kernel),
+   VCPU_STAT(exits),
{ NULL }
 };
 
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 95f12b2..3ede90d 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -42,6 +42,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run 
*run)
 
trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
  kvm_vcpu_hvc_get_imm(vcpu));
+   vcpu->stat.hvc_exit_stat++;
 
ret = kvm_psci_call(vcpu);
if (ret < 0) {
@@ -89,9 +90,11 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
 {
if (kvm_vcpu_get_hsr(vcpu) & HSR_WFI_IS_WFE) {
trace_kvm_wfx(*vcpu_pc(vcpu), true);
+   vcpu->stat.wfe_exit_stat++;
kvm_vcpu_on_spin(vcpu);
} else {
trace_kvm_wfx(*vcpu_pc(vcpu), false);
+   vcpu->stat.wfi_exit_stat++;
kvm_vcpu_block(vcpu);
}
 
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 3a10c9f..7f33b20 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -210,8 +210,11 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run 
*run,
 
if (!ret) {
/* We handled the access successfully in the kernel. */
+   vcpu->stat.mmio_exit_kernel++;
kvm_handle_mmio_return(vcpu, run);
return 1;
+   } else {
+   vcpu->stat.mmio_exit_user++;
}
 
run->exit_reason= KVM_EXIT_MMIO;
diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index a35ce72..19504aa 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -197,6 +197,12 @@ struct kvm_vcpu_stat {
u32 halt_successful_poll;
u32 halt_attempted_poll;
u32 halt_wakeup;
+   u32 hvc_exit_stat;
+   u64 wfe_exit_stat;
+   u64 wfi_exit_stat;
+   u64 mmio_exit_user;
+   u64 mmio_exit_kernel;
+   u64 exits;
 };
 
 int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index d250160..115522b 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -34,7 +34,16 @@
 
 #include "trace.h"
 
+#define VM_STAT(x) { #x, offsetof(struct kvm, stat.x), KVM_STAT_VM }
+#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
+
 struct kvm_stats_debugfs_item debugfs_entries[] = {
+   VCPU_STAT(hvc_exit_stat),
+   VCPU_STAT(wfe_exit_stat),
+   VCPU_STAT(wfi_exit_stat),
+   VCPU_STAT(mmio_exit_user),
+   VCPU_STAT(mmio_exit_kernel),
+   VCPU_STAT(exits),
{ NULL }
 };
 
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 

[PATCH 03/31] arm64: Add macros to read/write system registers

2015-12-24 Thread Marc Zyngier
From: Mark Rutland <mark.rutl...@arm.com>

Rather than crafting custom macros for reading/writing each system
register provide generics accessors, read_sysreg and write_sysreg, for
this purpose.

Signed-off-by: Mark Rutland <mark.rutl...@arm.com>
Acked-by: Catalin Marinas <catalin.mari...@arm.com>
Cc: Suzuki Poulose <suzuki.poul...@arm.com>
Cc: Will Deacon <will.dea...@arm.com>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/include/asm/sysreg.h | 21 +
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index d48ab5b..4aeebec 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -20,6 +20,8 @@
 #ifndef __ASM_SYSREG_H
 #define __ASM_SYSREG_H
 
+#include 
+
 #include 
 
 /*
@@ -208,6 +210,8 @@
 
 #else
 
+#include 
+
 asm(
 "  .irp
num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
 "  .equ__reg_num_x\\num, \\num\n"
@@ -232,6 +236,23 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
val |= set;
asm volatile("msr sctlr_el1, %0" : : "r" (val));
 }
+
+/*
+ * Unlike read_cpuid, calls to read_sysreg are never expected to be
+ * optimized away or replaced with synthetic values.
+ */
+#define read_sysreg(r) ({  \
+   u64 __val;  \
+   asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
+   __val;  \
+})
+
+#define write_sysreg(v, r) do {\
+   u64 __val = (u64)v; \
+   asm volatile("msr " __stringify(r) ", %0"   \
+: : "r" (__val));  \
+} while (0)
+
 #endif
 
 #endif /* __ASM_SYSREG_H */
-- 
2.1.4

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


[PATCH 05/31] arm64: KVM: Implement vgic-v2 save/restore

2015-12-24 Thread Marc Zyngier
Implement the vgic-v2 save restore (mostly) as a direct translation
of the assembly code version.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/Makefile |  1 +
 arch/arm64/kvm/hyp/Makefile |  5 +++
 arch/arm64/kvm/hyp/hyp.h|  3 ++
 arch/arm64/kvm/hyp/vgic-v2-sr.c | 84 +
 4 files changed, 93 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/Makefile
 create mode 100644 arch/arm64/kvm/hyp/vgic-v2-sr.c

diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 1949fe5..d31e4e5 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -10,6 +10,7 @@ KVM=../../../virt/kvm
 ARM=../../../arch/arm/kvm
 
 obj-$(CONFIG_KVM_ARM_HOST) += kvm.o
+obj-$(CONFIG_KVM_ARM_HOST) += hyp/
 
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o 
$(KVM)/eventfd.o $(KVM)/vfio.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
new file mode 100644
index 000..d8d5968
--- /dev/null
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for Kernel-based Virtual Machine module, HYP part
+#
+
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index 057f483..ac63553 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -29,5 +29,8 @@
 #define hyp_kern_va(v) (typeof(v))((unsigned long)(v) - HYP_PAGE_OFFSET \
  + PAGE_OFFSET)
 
+void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
+void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
+
 #endif /* __ARM64_KVM_HYP_H__ */
 
diff --git a/arch/arm64/kvm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
new file mode 100644
index 000..e717612
--- /dev/null
+++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+
+#include "hyp.h"
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
+{
+   struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+   struct vgic_v2_cpu_if *cpu_if = >arch.vgic_cpu.vgic_v2;
+   struct vgic_dist *vgic = >arch.vgic;
+   void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+   u32 eisr0, eisr1, elrsr0, elrsr1;
+   int i, nr_lr;
+
+   if (!base)
+   return;
+
+   nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+   cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
+   cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
+   eisr0  = readl_relaxed(base + GICH_EISR0);
+   elrsr0 = readl_relaxed(base + GICH_ELRSR0);
+   if (unlikely(nr_lr > 32)) {
+   eisr1  = readl_relaxed(base + GICH_EISR1);
+   elrsr1 = readl_relaxed(base + GICH_ELRSR1);
+   } else {
+   eisr1 = elrsr1 = 0;
+   }
+#ifdef CONFIG_CPU_BIG_ENDIAN
+   cpu_if->vgic_eisr  = ((u64)eisr0 << 32) | eisr1;
+   cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
+#else
+   cpu_if->vgic_eisr  = ((u64)eisr1 << 32) | eisr0;
+   cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
+#endif
+   cpu_if->vgic_apr= readl_relaxed(base + GICH_APR);
+
+   writel_relaxed(0, base + GICH_HCR);
+
+   for (i = 0; i < nr_lr; i++)
+   cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+}
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
+{
+   struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+   struct vgic_v2_cpu_if *cpu_if = >arch.vgic_cpu.vgic_v2;
+   struct vgic_dist *vgic = >arch.vgic;
+   void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+   int i, nr_lr;
+
+   if (!base)
+   return;
+
+   writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
+   writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
+   writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
+
+   nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+   for (i = 0; i < nr_lr; i++)
+   writel_relaxed(cpu_if->vgic_lr[i], base + GICH_LR0 + (i * 4));
+}
-- 
2.1.4

--
To unsubs

[PATCH 04/31] arm64: KVM: Add a HYP-specific header file

2015-12-24 Thread Marc Zyngier
In order to expose the various EL2 services that are private to
the hypervisor, add a new hyp.h file.

So far, it only contains mundane things such as section annotation
and VA manipulation.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/hyp/hyp.h | 33 +
 1 file changed, 33 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/hyp.h

diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
new file mode 100644
index 000..057f483
--- /dev/null
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_HYP_H__
+#define __ARM64_KVM_HYP_H__
+
+#include 
+#include 
+#include 
+#include 
+
+#define __hyp_text __section(.hyp.text) notrace
+
+#define kern_hyp_va(v) (typeof(v))((unsigned long)(v) & HYP_PAGE_OFFSET_MASK)
+#define hyp_kern_va(v) (typeof(v))((unsigned long)(v) - HYP_PAGE_OFFSET \
+ + PAGE_OFFSET)
+
+#endif /* __ARM64_KVM_HYP_H__ */
+
-- 
2.1.4

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


[PATCH 14/31] arm64: KVM: Implement the core world switch

2015-12-24 Thread Marc Zyngier
Implement the core of the world switch in C. Not everything is there
yet, and there is nothing to re-enter the world switch either.

But this already outlines the code structure well enough.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/Makefile |   1 +
 arch/arm64/kvm/hyp/switch.c | 135 
 2 files changed, 136 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/switch.c

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index 1e1ff06..9c11b0f 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += entry.o
+obj-$(CONFIG_KVM_ARM_HOST) += switch.o
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
new file mode 100644
index 000..79f59c9
--- /dev/null
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hyp.h"
+
+static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
+{
+   u64 val;
+
+   /*
+* We are about to set CPTR_EL2.TFP to trap all floating point
+* register accesses to EL2, however, the ARM ARM clearly states that
+* traps are only taken to EL2 if the operation would not otherwise
+* trap to EL1.  Therefore, always make sure that for 32-bit guests,
+* we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
+*/
+   val = vcpu->arch.hcr_el2;
+   if (!(val & HCR_RW)) {
+   write_sysreg(1 << 30, fpexc32_el2);
+   isb();
+   }
+   write_sysreg(val, hcr_el2);
+   /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
+   write_sysreg(1 << 15, hstr_el2);
+   write_sysreg(CPTR_EL2_TTA | CPTR_EL2_TFP, cptr_el2);
+   write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
+}
+
+static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
+{
+   write_sysreg(HCR_RW, hcr_el2);
+   write_sysreg(0, hstr_el2);
+   write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2);
+   write_sysreg(0, cptr_el2);
+}
+
+static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
+{
+   struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+   write_sysreg(kvm->arch.vttbr, vttbr_el2);
+}
+
+static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
+{
+   write_sysreg(0, vttbr_el2);
+}
+
+static hyp_alternate_select(__vgic_call_save_state,
+   __vgic_v2_save_state, __vgic_v3_save_state,
+   ARM64_HAS_SYSREG_GIC_CPUIF);
+
+static hyp_alternate_select(__vgic_call_restore_state,
+   __vgic_v2_restore_state, __vgic_v3_restore_state,
+   ARM64_HAS_SYSREG_GIC_CPUIF);
+
+static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
+{
+   __vgic_call_save_state()(vcpu);
+   write_sysreg(read_sysreg(hcr_el2) & ~HCR_INT_OVERRIDE, hcr_el2);
+}
+
+static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
+{
+   u64 val;
+
+   val = read_sysreg(hcr_el2);
+   val |=  HCR_INT_OVERRIDE;
+   val |= vcpu->arch.irq_lines;
+   write_sysreg(val, hcr_el2);
+
+   __vgic_call_restore_state()(vcpu);
+}
+
+int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
+{
+   struct kvm_cpu_context *host_ctxt;
+   struct kvm_cpu_context *guest_ctxt;
+   u64 exit_code;
+
+   vcpu = kern_hyp_va(vcpu);
+   write_sysreg(vcpu, tpidr_el2);
+
+   host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+   guest_ctxt = >arch.ctxt;
+
+   __sysreg_save_state(host_ctxt);
+   __debug_cond_save_host_state(vcpu);
+
+   __activate_traps(vcpu);
+   __activate_vm(vcpu);
+
+   __vgic_restore_state(vcpu);
+   __timer_restore_state(vcpu);
+
+   /*
+* We must restore the 32-bit state before the sysregs, thanks
+* to Cortex-A57 erratum #852523.
+*/
+   __sysreg32_restore_state(vcpu);
+   __sysreg_restore_state(guest_ctxt);
+   __debug_restore_state(vcpu, kern_hyp_va(vcpu->

[PATCH 16/31] arm64: KVM: Implement TLB handling

2015-12-24 Thread Marc Zyngier
Implement the TLB handling as a direct translation of the assembly
code version.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/Makefile |  1 +
 arch/arm64/kvm/hyp/entry.S  |  1 +
 arch/arm64/kvm/hyp/tlb.c| 73 +
 3 files changed, 75 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/tlb.c

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index 56238d0..1a529f5 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += switch.o
 obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
+obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index 90cbf0f..1050b2b 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -147,6 +147,7 @@ ENTRY(__fpsimd_guest_restore)
add x0, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
bl  __fpsimd_restore_state
 
+   // Skip restoring fpexc32 for AArch64 guests
mrs x1, hcr_el2
tbnzx1, #HCR_RW_SHIFT, 1f
ldr x4, [x2, #CPU_SYSREG_OFFSET(FPEXC32_EL2)]
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
new file mode 100644
index 000..6fcb93a
--- /dev/null
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hyp.h"
+
+void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
+{
+   dsb(ishst);
+
+   /* Switch to requested VMID */
+   kvm = kern_hyp_va(kvm);
+   write_sysreg(kvm->arch.vttbr, vttbr_el2);
+   isb();
+
+   /*
+* We could do so much better if we had the VA as well.
+* Instead, we invalidate Stage-2 for this IPA, and the
+* whole of Stage-1. Weep...
+*/
+   ipa >>= 12;
+   asm volatile("tlbi ipas2e1is, %0" : : "r" (ipa));
+
+   /*
+* We have to ensure completion of the invalidation at Stage-2,
+* since a table walk on another CPU could refill a TLB with a
+* complete (S1 + S2) walk based on the old Stage-2 mapping if
+* the Stage-1 invalidation happened first.
+*/
+   dsb(ish);
+   asm volatile("tlbi vmalle1is" : : );
+   dsb(ish);
+   isb();
+
+   write_sysreg(0, vttbr_el2);
+}
+
+void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
+{
+   dsb(ishst);
+
+   /* Switch to requested VMID */
+   kvm = kern_hyp_va(kvm);
+   write_sysreg(kvm->arch.vttbr, vttbr_el2);
+   isb();
+
+   asm volatile("tlbi vmalls12e1is" : : );
+   dsb(ish);
+   isb();
+
+   write_sysreg(0, vttbr_el2);
+}
+
+void __hyp_text __tlb_flush_vm_context(void)
+{
+   dsb(ishst);
+   asm volatile("tlbi alle1is  \n"
+"ic ialluis  ": : );
+   dsb(ish);
+}
-- 
2.1.4

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


[PATCH 11/31] arm64: KVM: Implement debug save/restore

2015-12-24 Thread Marc Zyngier
Implement the debug save restore as a direct translation of
the assembly code version.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Tested-by: Alex Bennée <alex.ben...@linaro.org>
Reviewed-by: Alex Bennée <alex.ben...@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/hyp/Makefile   |   1 +
 arch/arm64/kvm/hyp/debug-sr.c | 137 ++
 arch/arm64/kvm/hyp/hyp.h  |   9 +++
 3 files changed, 147 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/debug-sr.c

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index ec94200..ec14cac 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
new file mode 100644
index 000..7848322
--- /dev/null
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+
+#include 
+
+#include "hyp.h"
+
+#define read_debug(r,n)read_sysreg(r##n##_el1)
+#define write_debug(v,r,n) write_sysreg(v, r##n##_el1)
+
+#define save_debug(ptr,reg,nr) \
+   switch (nr) {   \
+   case 15:ptr[15] = read_debug(reg, 15);  \
+   case 14:ptr[14] = read_debug(reg, 14);  \
+   case 13:ptr[13] = read_debug(reg, 13);  \
+   case 12:ptr[12] = read_debug(reg, 12);  \
+   case 11:ptr[11] = read_debug(reg, 11);  \
+   case 10:ptr[10] = read_debug(reg, 10);  \
+   case 9: ptr[9] = read_debug(reg, 9);\
+   case 8: ptr[8] = read_debug(reg, 8);\
+   case 7: ptr[7] = read_debug(reg, 7);\
+   case 6: ptr[6] = read_debug(reg, 6);\
+   case 5: ptr[5] = read_debug(reg, 5);\
+   case 4: ptr[4] = read_debug(reg, 4);\
+   case 3: ptr[3] = read_debug(reg, 3);\
+   case 2: ptr[2] = read_debug(reg, 2);\
+   case 1: ptr[1] = read_debug(reg, 1);\
+   default:ptr[0] = read_debug(reg, 0);\
+   }
+
+#define restore_debug(ptr,reg,nr)  \
+   switch (nr) {   \
+   case 15:write_debug(ptr[15], reg, 15);  \
+   case 14:write_debug(ptr[14], reg, 14);  \
+   case 13:write_debug(ptr[13], reg, 13);  \
+   case 12:write_debug(ptr[12], reg, 12);  \
+   case 11:write_debug(ptr[11], reg, 11);  \
+   case 10:write_debug(ptr[10], reg, 10);  \
+   case 9: write_debug(ptr[9], reg, 9);\
+   case 8: write_debug(ptr[8], reg, 8);\
+   case 7: write_debug(ptr[7], reg, 7);\
+   case 6: write_debug(ptr[6], reg, 6);\
+   case 5: write_debug(ptr[5], reg, 5);\
+   case 4: write_debug(ptr[4], reg, 4);\
+   case 3: write_debug(ptr[3], reg, 3);\
+   case 2: write_debug(ptr[2], reg, 2);\
+   case 1: write_debug(ptr[1], reg, 1);\
+   default:write_debug(ptr[0], reg, 0);\
+   }
+
+void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
+  struct kvm_guest_debug_arch *dbg,
+  struct kvm_cpu_context *ctxt)
+{
+   u64 aa64dfr0;
+   int brps, wrps;
+
+   if (!(

[PATCH 08/31] arm64: KVM: Implement timer save/restore

2015-12-24 Thread Marc Zyngier
Implement the timer save restore as a direct translation of
the assembly code version.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/hyp/Makefile  |  1 +
 arch/arm64/kvm/hyp/hyp.h |  3 ++
 arch/arm64/kvm/hyp/timer-sr.c| 71 
 include/clocksource/arm_arch_timer.h |  6 +++
 4 files changed, 81 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/timer-sr.c

diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index d1e38ce..455dc0a 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
index 5759f9f..f213e46 100644
--- a/arch/arm64/kvm/hyp/hyp.h
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -35,5 +35,8 @@ void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
 
+void __timer_save_state(struct kvm_vcpu *vcpu);
+void __timer_restore_state(struct kvm_vcpu *vcpu);
+
 #endif /* __ARM64_KVM_HYP_H__ */
 
diff --git a/arch/arm64/kvm/hyp/timer-sr.c b/arch/arm64/kvm/hyp/timer-sr.c
new file mode 100644
index 000..1051e5d
--- /dev/null
+++ b/arch/arm64/kvm/hyp/timer-sr.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyng...@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+
+#include "hyp.h"
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
+{
+   struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+   struct arch_timer_cpu *timer = >arch.timer_cpu;
+   u64 val;
+
+   if (kvm->arch.timer.enabled) {
+   timer->cntv_ctl = read_sysreg(cntv_ctl_el0);
+   timer->cntv_cval = read_sysreg(cntv_cval_el0);
+   }
+
+   /* Disable the virtual timer */
+   write_sysreg(0, cntv_ctl_el0);
+
+   /* Allow physical timer/counter access for the host */
+   val = read_sysreg(cnthctl_el2);
+   val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+   write_sysreg(val, cnthctl_el2);
+
+   /* Clear cntvoff for the host */
+   write_sysreg(0, cntvoff_el2);
+}
+
+void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
+{
+   struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+   struct arch_timer_cpu *timer = >arch.timer_cpu;
+   u64 val;
+
+   /*
+* Disallow physical timer access for the guest
+* Physical counter access is allowed
+*/
+   val = read_sysreg(cnthctl_el2);
+   val &= ~CNTHCTL_EL1PCEN;
+   val |= CNTHCTL_EL1PCTEN;
+   write_sysreg(val, cnthctl_el2);
+
+   if (kvm->arch.timer.enabled) {
+   write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
+   write_sysreg(timer->cntv_cval, cntv_cval_el0);
+   isb();
+   write_sysreg(timer->cntv_ctl, cntv_ctl_el0);
+   }
+}
diff --git a/include/clocksource/arm_arch_timer.h 
b/include/clocksource/arm_arch_timer.h
index 9916d0e..25d0914 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -23,6 +23,12 @@
 #define ARCH_TIMER_CTRL_IT_MASK(1 << 1)
 #define ARCH_TIMER_CTRL_IT_STAT(1 << 2)
 
+#define CNTHCTL_EL1PCTEN   (1 << 0)
+#define CNTHCTL_EL1PCEN(1 << 1)
+#define CNTHCTL_EVNTEN (1 << 2)
+#define CNTHCTL_EVNTDIR(1 << 3)
+#define CNTHCTL_EVNTI  (0xF << 4)
+
 enum arch_timer_reg {
ARCH_TIMER_REG_CTRL,
ARCH_TIMER_REG_TVAL,
-- 
2.1.4

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


[PATCH 06/31] KVM: arm/arm64: vgic-v3: Make the LR indexing macro public

2015-12-24 Thread Marc Zyngier
We store GICv3 LRs in reverse order so that the CPU can save/restore
them in rever order as well (don't ask why, the design is crazy),
and yet generate memory traffic that doesn't completely suck.

We need this macro to be available to the C version of save/restore.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 include/kvm/arm_vgic.h |  6 ++
 virt/kvm/arm/vgic-v3.c | 10 ++
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index d2f4147..13a3d53 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -279,6 +279,12 @@ struct vgic_v2_cpu_if {
u32 vgic_lr[VGIC_V2_MAX_LRS];
 };
 
+/*
+ * LRs are stored in reverse order in memory. make sure we index them
+ * correctly.
+ */
+#define VGIC_V3_LR_INDEX(lr)   (VGIC_V3_MAX_LRS - 1 - lr)
+
 struct vgic_v3_cpu_if {
 #ifdef CONFIG_KVM_ARM_VGIC_V3
u32 vgic_hcr;
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 487d635..3813d23 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -36,18 +36,12 @@
 #define GICH_LR_PHYSID_CPUID   (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
 #define ICH_LR_VIRTUALID_MASK  (BIT_ULL(32) - 1)
 
-/*
- * LRs are stored in reverse order in memory. make sure we index them
- * correctly.
- */
-#define LR_INDEX(lr)   (VGIC_V3_MAX_LRS - 1 - lr)
-
 static u32 ich_vtr_el2;
 
 static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
 {
struct vgic_lr lr_desc;
-   u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)];
+   u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)];
 
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
lr_desc.irq = val & ICH_LR_VIRTUALID_MASK;
@@ -111,7 +105,7 @@ static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
lr_val |= ((u64)lr_desc.hwirq) << ICH_LR_PHYS_ID_SHIFT;
}
 
-   vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val;
+   vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)] = lr_val;
 
if (!(lr_desc.state & LR_STATE_MASK))
vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
-- 
2.1.4

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


[PATCH 01/31] KVM: arm/arm64: vgic: make vgic_io_ops static

2015-12-24 Thread Marc Zyngier
From: Jisheng Zhang 

vgic_io_ops is only referenced within vgic.c, so it can be declared
static.

Signed-off-by: Jisheng Zhang 
Signed-off-by: Christoffer Dall 
---
 virt/kvm/arm/vgic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 65461f8..0c739a7 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -878,7 +878,7 @@ static int vgic_handle_mmio_write(struct kvm_vcpu *vcpu,
   true);
 }
 
-struct kvm_io_device_ops vgic_io_ops = {
+static struct kvm_io_device_ops vgic_io_ops = {
.read   = vgic_handle_mmio_read,
.write  = vgic_handle_mmio_write,
 };
-- 
2.1.4

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


[PULL] KVM/ARM updates for 4.5

2015-12-24 Thread Marc Zyngier
Hi Paolo,

THis is the first pull request for the 4.5 merge window. Not much in
terms of features, but a rewrite of our 64bit world switch, making it
a lot nicer, maintainable, and much more likely to cope with things
like VHE. Also support 16bit VMIDs for systems that need to run that
many VMs concurrently.

I was really hoping that the PMU code would make it this time around,
but it got slightly delayed, and the holiday season didn't help. If
we're lucky enough (read: if all known issues have been addressed), I
may send you another pull request early in the new year.

In the mean time, please pull!

Happy Christmas,

  M.

The following changes since commit 9f9499ae8e6415cefc4fe0a96ad0e27864353c89:

  Linux 4.4-rc5 (2015-12-13 17:42:58 -0800)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git 
tags/kvm-arm-for-4.5-1

for you to fetch changes up to c7da6fa43cb1c5e649da0f478a491feb9208cae7:

  arm/arm64: KVM: Detect vGIC presence at runtime (2015-12-18 12:01:58 +)


KVM/ARM changes for Linux v4.5

- Complete rewrite of the arm64 world switch in C, hopefully
  paving the way for more sharing with the 32bit code, better
  maintainability and easier integration of new features.
  Also smaller and slightly faster in some cases...
- Support for 16bit VM identifiers
- Various cleanups


Amit Tomar (1):
  KVM: arm/arm64: Count guest exit due to various reasons

Fengguang Wu (1):
  MAINTAINERS: add git URL for KVM/ARM

Jisheng Zhang (1):
  KVM: arm/arm64: vgic: make vgic_io_ops static

Marc Zyngier (23):
  arm64: KVM: Add a HYP-specific header file
  arm64: KVM: Implement vgic-v2 save/restore
  KVM: arm/arm64: vgic-v3: Make the LR indexing macro public
  arm64: KVM: Implement vgic-v3 save/restore
  arm64: KVM: Implement timer save/restore
  arm64: KVM: Implement system register save/restore
  arm64: KVM: Implement 32bit system register save/restore
  arm64: KVM: Implement debug save/restore
  arm64: KVM: Implement guest entry
  arm64: KVM: Add patchable function selector
  arm64: KVM: Implement the core world switch
  arm64: KVM: Implement fpsimd save/restore
  arm64: KVM: Implement TLB handling
  arm64: KVM: HYP mode entry points
  arm64: KVM: Add panic handling
  arm64: KVM: Add compatibility aliases
  arm64: KVM: Map the kernel RO section into HYP
  arm64: KVM: Move away from the assembly version of the world switch
  arm64: KVM: Turn system register numbers to an enum
  arm64: KVM: Cleanup asm-offset.c
  arm64: KVM: Remove weak attributes
  ARM: KVM: Cleanup exception injection
  arm64: KVM: debug: Remove spurious inline attributes

Mark Rutland (1):
  arm64: Add macros to read/write system registers

Pavel Fedin (1):
  arm/arm64: KVM: Detect vGIC presence at runtime

Vladimir Murzin (3):
  arm/arm64: KVM: Remove unreferenced S2_PGD_ORDER
  arm: KVM: Make kvm_arm.h friendly to assembly code
  arm64: KVM: Add support for 16-bit VMID

 MAINTAINERS  |1 +
 arch/arm/include/asm/kvm_arm.h   |   34 +-
 arch/arm/include/asm/kvm_host.h  |6 +
 arch/arm/include/asm/kvm_mmu.h   |5 +
 arch/arm/kvm/arm.c   |   40 +-
 arch/arm/kvm/emulate.c   |   74 +--
 arch/arm/kvm/guest.c |6 +
 arch/arm/kvm/handle_exit.c   |3 +
 arch/arm/kvm/mmio.c  |3 +
 arch/arm/kvm/mmu.c   |6 +-
 arch/arm64/include/asm/kvm_arm.h |3 +-
 arch/arm64/include/asm/kvm_asm.h |   76 ---
 arch/arm64/include/asm/kvm_emulate.h |1 -
 arch/arm64/include/asm/kvm_host.h|   87 ++-
 arch/arm64/include/asm/kvm_mmio.h|1 -
 arch/arm64/include/asm/kvm_mmu.h |9 +-
 arch/arm64/include/asm/sysreg.h  |   21 +
 arch/arm64/kernel/asm-offsets.c  |   40 +-
 arch/arm64/kvm/Makefile  |3 +-
 arch/arm64/kvm/guest.c   |   10 +-
 arch/arm64/kvm/handle_exit.c |4 +
 arch/arm64/kvm/hyp-init.S|9 +
 arch/arm64/kvm/hyp.S | 1081 +-
 arch/arm64/kvm/hyp/Makefile  |   14 +
 arch/arm64/kvm/hyp/debug-sr.c|  140 +
 arch/arm64/kvm/hyp/entry.S   |  160 +
 arch/arm64/kvm/hyp/fpsimd.S  |   33 ++
 arch/arm64/kvm/hyp/hyp-entry.S   |  212 +++
 arch/arm64/kvm/hyp/hyp.h |   90 +++
 arch/arm64/kvm/hyp/switch.c  |  175 ++
 arch/arm64/kvm/hyp/sysreg-sr.c   |  138 +
 arch/arm64/kvm/hyp/timer-sr.c|   71 +++
 arch/arm64/kvm/hyp/tlb.c |   80 +++
 arch/arm64/kvm/hyp/vgic-v2-sr.c  |   84 +++
 arch/arm64/kvm/hyp/vgic-v3-sr.c  |  228 +++
 arch/arm64/kvm/sys_regs.c|   59 +-
 arch/arm64/kvm/vgic

[PATCH 26/31] arm64: KVM: debug: Remove spurious inline attributes

2015-12-24 Thread Marc Zyngier
The debug trapping code is pretty heavy on the "inline" attribute,
but most functions are actually referenced in the sysreg tables,
making the inlining imposible.

Removing the useless inline qualifier seems the right thing to do,
having verified that the output code is similar.

Cc: Alex Bennée <alex.ben...@linaro.org>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/sys_regs.c | 58 +++
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 88adebf..eec3598 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -220,9 +220,9 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
  * All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the
  * hyp.S code switches between host and guest values in future.
  */
-static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
- struct sys_reg_params *p,
- u64 *dbg_reg)
+static void reg_to_dbg(struct kvm_vcpu *vcpu,
+  struct sys_reg_params *p,
+  u64 *dbg_reg)
 {
u64 val = p->regval;
 
@@ -235,18 +235,18 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
 }
 
-static inline void dbg_to_reg(struct kvm_vcpu *vcpu,
- struct sys_reg_params *p,
- u64 *dbg_reg)
+static void dbg_to_reg(struct kvm_vcpu *vcpu,
+  struct sys_reg_params *p,
+  u64 *dbg_reg)
 {
p->regval = *dbg_reg;
if (p->is_32bit)
p->regval &= 0xUL;
 }
 
-static inline bool trap_bvr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_bvr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_bvr[rd->reg];
 
@@ -280,15 +280,15 @@ static int get_bvr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_bvr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_bvr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg] = rd->val;
 }
 
-static inline bool trap_bcr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_bcr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_bcr[rd->reg];
 
@@ -323,15 +323,15 @@ static int get_bcr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_bcr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_bcr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg] = rd->val;
 }
 
-static inline bool trap_wvr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_wvr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_wvr[rd->reg];
 
@@ -366,15 +366,15 @@ static int get_wvr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_wvr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_wvr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg] = rd->val;
 }
 
-static inline bool trap_wcr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_wcr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_wcr[rd->reg];
 
@@ -408,8 +408,8 @@ static int get_wcr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_wcr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_wcr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_wcr[

[PATCH 29/31] arm64: KVM: Add support for 16-bit VMID

2015-12-24 Thread Marc Zyngier
From: Vladimir Murzin <vladimir.mur...@arm.com>

The ARMv8.1 architecture extension allows to choose between 8-bit and
16-bit of VMID, so use this capability for KVM.

Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Vladimir Murzin <vladimir.mur...@arm.com>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm/include/asm/kvm_arm.h   |  2 +-
 arch/arm/include/asm/kvm_mmu.h   |  5 +
 arch/arm/kvm/arm.c   | 10 --
 arch/arm64/include/asm/kvm_arm.h |  3 ++-
 arch/arm64/include/asm/kvm_mmu.h |  8 
 arch/arm64/kvm/hyp-init.S|  9 +
 6 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index 01d4d7a..e22089f 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -164,7 +164,7 @@
 #define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
 #define VTTBR_BADDR_MASK  (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << 
VTTBR_BADDR_SHIFT)
 #define VTTBR_VMID_SHIFT  _AC(48, ULL)
-#define VTTBR_VMID_MASK  (_AC(0xff, ULL) << VTTBR_VMID_SHIFT)
+#define VTTBR_VMID_MASK(size)  (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
 
 /* Hyp Syndrome Register (HSR) bits */
 #define HSR_EC_SHIFT   (26)
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 405aa18..9203c21 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -279,6 +279,11 @@ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
   pgd_t *merged_hyp_pgd,
   unsigned long hyp_idmap_start) { }
 
+static inline unsigned int kvm_get_vmid_bits(void)
+{
+   return 8;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 6e35d1d..f6bcc2e 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -59,7 +59,8 @@ static DEFINE_PER_CPU(struct kvm_vcpu *, 
kvm_arm_running_vcpu);
 
 /* The VMID used in the VTTBR */
 static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
-static u8 kvm_next_vmid;
+static u32 kvm_next_vmid;
+static unsigned int kvm_vmid_bits __read_mostly;
 static DEFINE_SPINLOCK(kvm_vmid_lock);
 
 static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
@@ -434,11 +435,12 @@ static void update_vttbr(struct kvm *kvm)
kvm->arch.vmid_gen = atomic64_read(_vmid_gen);
kvm->arch.vmid = kvm_next_vmid;
kvm_next_vmid++;
+   kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
 
/* update vttbr to be used with the new vmid */
pgd_phys = virt_to_phys(kvm_get_hwpgd(kvm));
BUG_ON(pgd_phys & ~VTTBR_BADDR_MASK);
-   vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK;
+   vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & 
VTTBR_VMID_MASK(kvm_vmid_bits);
kvm->arch.vttbr = pgd_phys | vmid;
 
spin_unlock(_vmid_lock);
@@ -1135,6 +1137,10 @@ static int init_hyp_mode(void)
 
kvm_perf_init();
 
+   /* set size of VMID supported by CPU */
+   kvm_vmid_bits = kvm_get_vmid_bits();
+   kvm_info("%d-bit VMID\n", kvm_vmid_bits);
+
kvm_info("Hyp mode initialized successfully\n");
 
return 0;
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 5e6857b..738a95f 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -125,6 +125,7 @@
 #define VTCR_EL2_SL0_LVL1  (1 << 6)
 #define VTCR_EL2_T0SZ_MASK 0x3f
 #define VTCR_EL2_T0SZ_40B  24
+#define VTCR_EL2_VS19
 
 /*
  * We configure the Stage-2 page tables to always restrict the IPA space to be
@@ -169,7 +170,7 @@
 #define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
 #define VTTBR_BADDR_MASK  (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << 
VTTBR_BADDR_SHIFT)
 #define VTTBR_VMID_SHIFT  (UL(48))
-#define VTTBR_VMID_MASK  (UL(0xFF) << VTTBR_VMID_SHIFT)
+#define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
 
 /* Hyp System Trap Register */
 #define HSTR_EL2_T(x)  (1 << x)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 54cba80..0bf8b43 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -20,6 +20,7 @@
 
 #include 
 #include 
+#include 
 
 /*
  * As we only have the TTBR0_EL2 register, we cannot express
@@ -301,5 +302,12 @@ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
merged_hyp_pgd[idmap_idx] = __pgd(__pa(boot_hyp_pgd) | PMD_TYPE_TABLE);
 }
 
+static inline unsigned int kvm_get_vmid_bits(void)
+{
+   int reg = read_system_reg(SYS_ID_AA64MMFR1_EL1);
+
+   return (cpuid_feature_extract_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) 
== 2) ? 16 : 8;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif 

[PATCH 31/31] arm/arm64: KVM: Detect vGIC presence at runtime

2015-12-24 Thread Marc Zyngier
From: Pavel Fedin <p.fe...@samsung.com>

Before commit 662d9715840aef44dcb573b0f9fab9e8319c868a
("arm/arm64: KVM: Kill CONFIG_KVM_ARM_{VGIC,TIMER}") is was possible to
compile the kernel without vGIC and vTimer support. Commit message says
about possibility to detect vGIC support in runtime, but this has never
been implemented.

This patch introduces runtime check, restoring the lost functionality.
It again allows to use KVM on hardware without vGIC. Interrupt
controller has to be emulated in userspace in this case.

-ENODEV return code from probe function means there's no GIC at all.
-ENXIO happens when, for example, there is GIC node in the device tree,
but it does not specify vGIC resources. Any other error code is still
treated as full stop because it might mean some really serious problems.

Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm/kvm/arm.c | 22 --
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index f6bcc2e..dda1959 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -63,6 +63,8 @@ static u32 kvm_next_vmid;
 static unsigned int kvm_vmid_bits __read_mostly;
 static DEFINE_SPINLOCK(kvm_vmid_lock);
 
+static bool vgic_present;
+
 static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
 {
BUG_ON(preemptible());
@@ -134,7 +136,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.vmid_gen = 0;
 
/* The maximum number of VCPUs is limited by the host's GIC model */
-   kvm->arch.max_vcpus = kvm_vgic_get_max_vcpus();
+   kvm->arch.max_vcpus = vgic_present ?
+   kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
 
return ret;
 out_free_stage2_pgd:
@@ -174,6 +177,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
int r;
switch (ext) {
case KVM_CAP_IRQCHIP:
+   r = vgic_present;
+   break;
case KVM_CAP_IOEVENTFD:
case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_USER_MEMORY:
@@ -917,6 +922,8 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
 
switch (dev_id) {
case KVM_ARM_DEVICE_VGIC_V2:
+   if (!vgic_present)
+   return -ENXIO;
return kvm_vgic_addr(kvm, type, _addr->addr, true);
default:
return -ENODEV;
@@ -931,6 +938,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
 
switch (ioctl) {
case KVM_CREATE_IRQCHIP: {
+   if (!vgic_present)
+   return -ENXIO;
return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
}
case KVM_ARM_SET_DEVICE_ADDR: {
@@ -1121,8 +1130,17 @@ static int init_hyp_mode(void)
 * Init HYP view of VGIC
 */
err = kvm_vgic_hyp_init();
-   if (err)
+   switch (err) {
+   case 0:
+   vgic_present = true;
+   break;
+   case -ENODEV:
+   case -ENXIO:
+   vgic_present = false;
+   break;
+   default:
goto out_free_context;
+   }
 
/*
 * Init HYP architected timer support
-- 
2.1.4

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


[PATCH 27/31] arm/arm64: KVM: Remove unreferenced S2_PGD_ORDER

2015-12-24 Thread Marc Zyngier
From: Vladimir Murzin <vladimir.mur...@arm.com>

Since commit a987370 ("arm64: KVM: Fix stage-2 PGD allocation to have
per-page refcounting") there is no reference to S2_PGD_ORDER, so kill it
for the good.

Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Vladimir Murzin <vladimir.mur...@arm.com>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm/include/asm/kvm_arm.h   | 1 -
 arch/arm/kvm/mmu.c   | 6 +++---
 arch/arm64/include/asm/kvm_mmu.h | 1 -
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index dc641dd..b05bb5a 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -135,7 +135,6 @@
 #define KVM_PHYS_SIZE  (1ULL << KVM_PHYS_SHIFT)
 #define KVM_PHYS_MASK  (KVM_PHYS_SIZE - 1ULL)
 #define PTRS_PER_S2_PGD(1ULL << (KVM_PHYS_SHIFT - 30))
-#define S2_PGD_ORDER   get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
 
 /* Virtualization Translation Control Register (VTCR) bits */
 #define VTCR_SH0   (3 << 12)
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 61d96a6..22f7fa0 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -656,9 +656,9 @@ static void *kvm_alloc_hwpgd(void)
  * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
  * @kvm:   The KVM struct pointer for the VM.
  *
- * Allocates the 1st level table only of size defined by S2_PGD_ORDER (can
- * support either full 40-bit input addresses or limited to 32-bit input
- * addresses). Clears the allocated pages.
+ * Allocates only the stage-2 HW PGD level table(s) (can support either full
+ * 40-bit input addresses or limited to 32-bit input addresses). Clears the
+ * allocated pages.
  *
  * Note we don't need locking here as this is only called when the VM is
  * created, which can only be done once.
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6150567..54cba80 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -158,7 +158,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
 #define PTRS_PER_S2_PGD_SHIFT  (KVM_PHYS_SHIFT - PGDIR_SHIFT)
 #endif
 #define PTRS_PER_S2_PGD(1 << PTRS_PER_S2_PGD_SHIFT)
-#define S2_PGD_ORDER   get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
 
 #define kvm_pgd_index(addr)(((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 
1))
 
-- 
2.1.4

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


[PATCH 20/31] arm64: KVM: Map the kernel RO section into HYP

2015-12-24 Thread Marc Zyngier
In order to run C code in HYP, we must make sure that the kernel's
RO section is mapped into HYP (otherwise things break badly).

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm/kvm/arm.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 8a79a57..6e35d1d 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #ifdef REQUIRES_VIRT
 __asm__(".arch_extension   virt");
@@ -1068,6 +1069,12 @@ static int init_hyp_mode(void)
goto out_free_mappings;
}
 
+   err = create_hyp_mappings(__start_rodata, __end_rodata);
+   if (err) {
+   kvm_err("Cannot map rodata section\n");
+   goto out_free_mappings;
+   }
+
/*
 * Map the Hyp stack pages
 */
-- 
2.1.4

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


[PATCH 24/31] arm64: KVM: Remove weak attributes

2015-12-24 Thread Marc Zyngier
As we've now switched to the new world switch implementation,
remove the weak attributes, as nobody is supposed to override
it anymore.

Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/hyp/debug-sr.c   |  5 ++---
 arch/arm64/kvm/hyp/hyp-entry.S  |  3 ---
 arch/arm64/kvm/hyp/switch.c |  5 ++---
 arch/arm64/kvm/hyp/tlb.c| 16 +++-
 arch/arm64/kvm/hyp/vgic-v3-sr.c |  5 ++---
 5 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index 567a0d6..c9c1e97 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -132,10 +132,9 @@ void __hyp_text __debug_cond_restore_host_state(struct 
kvm_vcpu *vcpu)
vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
 }
 
-u32 __hyp_text __debug_read_mdcr_el2(void)
+static u32 __hyp_text __debug_read_mdcr_el2(void)
 {
return read_sysreg(mdcr_el2);
 }
 
-__alias(__debug_read_mdcr_el2)
-u32 __weak __kvm_get_mdcr_el2(void);
+__alias(__debug_read_mdcr_el2) u32 __kvm_get_mdcr_el2(void);
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 10d6d2a..93e8d983 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -189,9 +189,7 @@ ENDPROC(\label)
 
.align 11
 
-   .weak   __kvm_hyp_vector
 ENTRY(__kvm_hyp_vector)
-ENTRY(__hyp_vector)
ventry  el2t_sync_invalid   // Synchronous EL2t
ventry  el2t_irq_invalid// IRQ EL2t
ventry  el2t_fiq_invalid// FIQ EL2t
@@ -211,5 +209,4 @@ ENTRY(__hyp_vector)
ventry  el1_irq // IRQ 32-bit EL1
ventry  el1_fiq_invalid // FIQ 32-bit EL1
ventry  el1_error_invalid   // Error 32-bit EL1
-ENDPROC(__hyp_vector)
 ENDPROC(__kvm_hyp_vector)
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 7457ae4..ca8f5a5 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -85,7 +85,7 @@ static void __hyp_text __vgic_restore_state(struct kvm_vcpu 
*vcpu)
__vgic_call_restore_state()(vcpu);
 }
 
-int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
+static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
 {
struct kvm_cpu_context *host_ctxt;
struct kvm_cpu_context *guest_ctxt;
@@ -142,8 +142,7 @@ int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
return exit_code;
 }
 
-__alias(__guest_run)
-int __weak __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+__alias(__guest_run) int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
 static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx 
ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
 
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index 5f815cf..2a7e0d8 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -17,7 +17,7 @@
 
 #include "hyp.h"
 
-void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
+static void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
 {
dsb(ishst);
 
@@ -48,10 +48,10 @@ void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, 
phys_addr_t ipa)
write_sysreg(0, vttbr_el2);
 }
 
-__alias(__tlb_flush_vmid_ipa)
-void __weak __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
+__alias(__tlb_flush_vmid_ipa) void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm,
+   phys_addr_t ipa);
 
-void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
+static void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
 {
dsb(ishst);
 
@@ -67,10 +67,9 @@ void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
write_sysreg(0, vttbr_el2);
 }
 
-__alias(__tlb_flush_vmid)
-void __weak __kvm_tlb_flush_vmid(struct kvm *kvm);
+__alias(__tlb_flush_vmid) void __kvm_tlb_flush_vmid(struct kvm *kvm);
 
-void __hyp_text __tlb_flush_vm_context(void)
+static void __hyp_text __tlb_flush_vm_context(void)
 {
dsb(ishst);
asm volatile("tlbi alle1is  \n"
@@ -78,5 +77,4 @@ void __hyp_text __tlb_flush_vm_context(void)
dsb(ish);
 }
 
-__alias(__tlb_flush_vm_context)
-void __weak __kvm_flush_vm_context(void);
+__alias(__tlb_flush_vm_context) void __kvm_flush_vm_context(void);
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index a769458..9142e08 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -220,10 +220,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu 
*vcpu)
}
 }
 
-u64 __hyp_text __vgic_v3_read_ich_vtr_el2(void)
+static u64 __hyp_text __vgic_v3_read_ich_vtr_el2(void)
 {
return read_gicreg(ICH_VTR_EL2);
 }
 
-__alias(__vgic_v3_read_ich_vtr_el2)
-u64 __weak __vgic_v3_get_ich_vtr_el2(void);
+__alias(__vgic_v3_read_ich_vtr_el

[PATCH 28/31] arm: KVM: Make kvm_arm.h friendly to assembly code

2015-12-24 Thread Marc Zyngier
From: Vladimir Murzin <vladimir.mur...@arm.com>

kvm_arm.h is included from both C code and assembly code; however some
definitions in this header supplied with U/UL/ULL suffixes which might
confuse assembly once they got evaluated.
We have _AC macro for such cases, so just wrap problem places with it.

Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Vladimir Murzin <vladimir.mur...@arm.com>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm/include/asm/kvm_arm.h | 33 +
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index b05bb5a..01d4d7a 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -19,6 +19,7 @@
 #ifndef __ARM_KVM_ARM_H__
 #define __ARM_KVM_ARM_H__
 
+#include 
 #include 
 
 /* Hyp Configuration Register (HCR) bits */
@@ -132,9 +133,9 @@
  * space.
  */
 #define KVM_PHYS_SHIFT (40)
-#define KVM_PHYS_SIZE  (1ULL << KVM_PHYS_SHIFT)
-#define KVM_PHYS_MASK  (KVM_PHYS_SIZE - 1ULL)
-#define PTRS_PER_S2_PGD(1ULL << (KVM_PHYS_SHIFT - 30))
+#define KVM_PHYS_SIZE  (_AC(1, ULL) << KVM_PHYS_SHIFT)
+#define KVM_PHYS_MASK  (KVM_PHYS_SIZE - _AC(1, ULL))
+#define PTRS_PER_S2_PGD(_AC(1, ULL) << (KVM_PHYS_SHIFT - 30))
 
 /* Virtualization Translation Control Register (VTCR) bits */
 #define VTCR_SH0   (3 << 12)
@@ -161,17 +162,17 @@
 #define VTTBR_X(5 - KVM_T0SZ)
 #endif
 #define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
-#define VTTBR_BADDR_MASK  (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
-#define VTTBR_VMID_SHIFT  (48LLU)
-#define VTTBR_VMID_MASK  (0xffLLU << VTTBR_VMID_SHIFT)
+#define VTTBR_BADDR_MASK  (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << 
VTTBR_BADDR_SHIFT)
+#define VTTBR_VMID_SHIFT  _AC(48, ULL)
+#define VTTBR_VMID_MASK  (_AC(0xff, ULL) << VTTBR_VMID_SHIFT)
 
 /* Hyp Syndrome Register (HSR) bits */
 #define HSR_EC_SHIFT   (26)
-#define HSR_EC (0x3fU << HSR_EC_SHIFT)
-#define HSR_IL (1U << 25)
+#define HSR_EC (_AC(0x3f, UL) << HSR_EC_SHIFT)
+#define HSR_IL (_AC(1, UL) << 25)
 #define HSR_ISS(HSR_IL - 1)
 #define HSR_ISV_SHIFT  (24)
-#define HSR_ISV(1U << HSR_ISV_SHIFT)
+#define HSR_ISV(_AC(1, UL) << HSR_ISV_SHIFT)
 #define HSR_SRT_SHIFT  (16)
 #define HSR_SRT_MASK   (0xf << HSR_SRT_SHIFT)
 #define HSR_FSC(0x3f)
@@ -179,9 +180,9 @@
 #define HSR_SSE(1 << 21)
 #define HSR_WNR(1 << 6)
 #define HSR_CV_SHIFT   (24)
-#define HSR_CV (1U << HSR_CV_SHIFT)
+#define HSR_CV (_AC(1, UL) << HSR_CV_SHIFT)
 #define HSR_COND_SHIFT (20)
-#define HSR_COND   (0xfU << HSR_COND_SHIFT)
+#define HSR_COND   (_AC(0xf, UL) << HSR_COND_SHIFT)
 
 #define FSC_FAULT  (0x04)
 #define FSC_ACCESS (0x08)
@@ -209,13 +210,13 @@
 #define HSR_EC_DABT(0x24)
 #define HSR_EC_DABT_HYP(0x25)
 
-#define HSR_WFI_IS_WFE (1U << 0)
+#define HSR_WFI_IS_WFE (_AC(1, UL) << 0)
 
-#define HSR_HVC_IMM_MASK   ((1UL << 16) - 1)
+#define HSR_HVC_IMM_MASK   ((_AC(1, UL) << 16) - 1)
 
-#define HSR_DABT_S1PTW (1U << 7)
-#define HSR_DABT_CM(1U << 8)
-#define HSR_DABT_EA(1U << 9)
+#define HSR_DABT_S1PTW (_AC(1, UL) << 7)
+#define HSR_DABT_CM(_AC(1, UL) << 8)
+#define HSR_DABT_EA(_AC(1, UL) << 9)
 
 #define kvm_arm_exception_type \
{0, "RESET" },  \
-- 
2.1.4

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


[PATCH 30/31] MAINTAINERS: add git URL for KVM/ARM

2015-12-24 Thread Marc Zyngier
From: Fengguang Wu <fengguang...@intel.com>

Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Fengguang Wu <fengguang...@intel.com>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9bff63c..8e92b45 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6102,6 +6102,7 @@ M:Marc Zyngier <marc.zyng...@arm.com>
 L: linux-arm-ker...@lists.infradead.org (moderated for non-subscribers)
 L: kvm...@lists.cs.columbia.edu
 W: http://systems.cs.columbia.edu/projects/kvm-arm
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
 S: Supported
 F: arch/arm/include/uapi/asm/kvm*
 F: arch/arm/include/asm/kvm*
-- 
2.1.4

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


[PATCH 23/31] arm64: KVM: Cleanup asm-offset.c

2015-12-24 Thread Marc Zyngier
As we've now rewritten most of our code-base in C, most of the
KVM-specific code in asm-offset.c is useless. Delete-time again!

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kernel/asm-offsets.c | 39 ---
 1 file changed, 39 deletions(-)

diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 4b72231..94090a6 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -108,50 +108,11 @@ int main(void)
   DEFINE(CPU_GP_REGS,  offsetof(struct kvm_cpu_context, gp_regs));
   DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs));
   DEFINE(CPU_FP_REGS,  offsetof(struct kvm_regs, fp_regs));
-  DEFINE(CPU_SP_EL1,   offsetof(struct kvm_regs, sp_el1));
-  DEFINE(CPU_ELR_EL1,  offsetof(struct kvm_regs, elr_el1));
-  DEFINE(CPU_SPSR, offsetof(struct kvm_regs, spsr));
-  DEFINE(CPU_SYSREGS,  offsetof(struct kvm_cpu_context, sys_regs));
   DEFINE(VCPU_FPEXC32_EL2, offsetof(struct kvm_vcpu, 
arch.ctxt.sys_regs[FPEXC32_EL2]));
   DEFINE(VCPU_ESR_EL2, offsetof(struct kvm_vcpu, arch.fault.esr_el2));
   DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2));
   DEFINE(VCPU_HPFAR_EL2,   offsetof(struct kvm_vcpu, 
arch.fault.hpfar_el2));
-  DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags));
-  DEFINE(VCPU_DEBUG_PTR,   offsetof(struct kvm_vcpu, arch.debug_ptr));
-  DEFINE(DEBUG_BCR,offsetof(struct kvm_guest_debug_arch, dbg_bcr));
-  DEFINE(DEBUG_BVR,offsetof(struct kvm_guest_debug_arch, dbg_bvr));
-  DEFINE(DEBUG_WCR,offsetof(struct kvm_guest_debug_arch, dbg_wcr));
-  DEFINE(DEBUG_WVR,offsetof(struct kvm_guest_debug_arch, dbg_wvr));
-  DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2));
-  DEFINE(VCPU_MDCR_EL2,offsetof(struct kvm_vcpu, arch.mdcr_el2));
-  DEFINE(VCPU_IRQ_LINES,   offsetof(struct kvm_vcpu, arch.irq_lines));
   DEFINE(VCPU_HOST_CONTEXT,offsetof(struct kvm_vcpu, 
arch.host_cpu_context));
-  DEFINE(VCPU_HOST_DEBUG_STATE, offsetof(struct kvm_vcpu, 
arch.host_debug_state));
-  DEFINE(VCPU_TIMER_CNTV_CTL,  offsetof(struct kvm_vcpu, 
arch.timer_cpu.cntv_ctl));
-  DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, 
arch.timer_cpu.cntv_cval));
-  DEFINE(KVM_TIMER_CNTVOFF,offsetof(struct kvm, arch.timer.cntvoff));
-  DEFINE(KVM_TIMER_ENABLED,offsetof(struct kvm, arch.timer.enabled));
-  DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
-  DEFINE(VCPU_VGIC_CPU,offsetof(struct kvm_vcpu, 
arch.vgic_cpu));
-  DEFINE(VGIC_V2_CPU_HCR,  offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
-  DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
-  DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
-  DEFINE(VGIC_V2_CPU_EISR, offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
-  DEFINE(VGIC_V2_CPU_ELRSR,offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
-  DEFINE(VGIC_V2_CPU_APR,  offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
-  DEFINE(VGIC_V2_CPU_LR,   offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
-  DEFINE(VGIC_V3_CPU_SRE,  offsetof(struct vgic_cpu, vgic_v3.vgic_sre));
-  DEFINE(VGIC_V3_CPU_HCR,  offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
-  DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
-  DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
-  DEFINE(VGIC_V3_CPU_EISR, offsetof(struct vgic_cpu, vgic_v3.vgic_eisr));
-  DEFINE(VGIC_V3_CPU_ELRSR,offsetof(struct vgic_cpu, vgic_v3.vgic_elrsr));
-  DEFINE(VGIC_V3_CPU_AP0R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap0r));
-  DEFINE(VGIC_V3_CPU_AP1R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap1r));
-  DEFINE(VGIC_V3_CPU_LR,   offsetof(struct vgic_cpu, vgic_v3.vgic_lr));
-  DEFINE(VGIC_CPU_NR_LR,   offsetof(struct vgic_cpu, nr_lr));
-  DEFINE(KVM_VTTBR,offsetof(struct kvm, arch.vttbr));
-  DEFINE(KVM_VGIC_VCTRL,   offsetof(struct kvm, arch.vgic.vctrl_base));
 #endif
 #ifdef CONFIG_CPU_PM
   DEFINE(CPU_SUSPEND_SZ,   sizeof(struct cpu_suspend_ctx));
-- 
2.1.4

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


[PATCH 2/2] arm64: KVM: Do not update PC if the trap handler has updated it

2015-12-22 Thread Marc Zyngier
Assuming we trap a system register, and decide that the access is
illegal, we will inject an exception in the guest. In this
case, we shouldn't increment the PC, or the vcpu will miss the
first instruction of the handler, leading to a mildly confused
guest.

Solve this by snapshoting PC before the access is performed,
and checking if it has moved or not before incrementing it.

Reported-by: Shannon Zhao <shannon.z...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/sys_regs.c | 73 +++
 1 file changed, 36 insertions(+), 37 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d2650e8..9c87e0c 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -966,6 +966,39 @@ static const struct sys_reg_desc *find_reg(const struct 
sys_reg_params *params,
return NULL;
 }
 
+/* Perform the sysreg access, returns 0 on success */
+static int access_sys_reg(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *params,
+ const struct sys_reg_desc *r)
+{
+   u64 pc = *vcpu_pc(vcpu);
+
+   if (unlikely(!r))
+   return -1;
+
+   /*
+* Not having an accessor means that we have configured a trap
+* that we don't know how to handle. This certainly qualifies
+* as a gross bug that should be fixed right away.
+*/
+   BUG_ON(!r->access);
+
+   if (likely(r->access(vcpu, params, r))) {
+   /*
+* Skip the instruction if it was emulated without PC
+* having changed. This allows us to detect a fault
+* being injected (incrementing the PC here would
+* cause the vcpu to skip the first instruction of its
+* fault handler).
+*/
+   if (pc == *vcpu_pc(vcpu))
+   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+   return 0;
+   }
+
+   return -1;
+}
+
 int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
kvm_inject_undefined(vcpu);
@@ -994,26 +1027,7 @@ static int emulate_cp(struct kvm_vcpu *vcpu,
 
r = find_reg(params, table, num);
 
-   if (r) {
-   /*
-* Not having an accessor means that we have
-* configured a trap that we don't know how to
-* handle. This certainly qualifies as a gross bug
-* that should be fixed right away.
-*/
-   BUG_ON(!r->access);
-
-   if (likely(r->access(vcpu, params, r))) {
-   /* Skip instruction, since it was emulated */
-   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
-   }
-
-   /* Handled */
-   return 0;
-   }
-
-   /* Not handled */
-   return -1;
+   return access_sys_reg(vcpu, params, r);
 }
 
 static void unhandled_cp_access(struct kvm_vcpu *vcpu,
@@ -1178,27 +1192,12 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
if (!r)
r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
 
-   if (likely(r)) {
-   /*
-* Not having an accessor means that we have
-* configured a trap that we don't know how to
-* handle. This certainly qualifies as a gross bug
-* that should be fixed right away.
-*/
-   BUG_ON(!r->access);
-
-   if (likely(r->access(vcpu, params, r))) {
-   /* Skip instruction, since it was emulated */
-   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
-   return 1;
-   }
-   /* If access function fails, it should complain. */
-   } else {
+   if (access_sys_reg(vcpu, params, r)) {
kvm_err("Unsupported guest sys_reg access at: %lx\n",
*vcpu_pc(vcpu));
print_sys_reg_instr(params);
+   kvm_inject_undefined(vcpu);
}
-   kvm_inject_undefined(vcpu);
return 1;
 }
 
-- 
2.1.4

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


[PATCH 0/2] Fix PC corruption when injecting a fault

2015-12-22 Thread Marc Zyngier
When injecting a fault as the result of a system register trap, we
change the PC to point to the fault handler. This clashes with the
code that increments the PC to skip over the emulated system register
access, leading to a situation where we skip the first instruction of
the fault handler.

The good news is that so far, we never do this, so I believe the
current code is safe. But the PMU code is soon going to exercise that
path, and I'd rather plug it sooner that later.

Thanks,

M.

Marc Zyngier (2):
  arm: KVM: Do not update PC if the trap handler has updated it
  arm64: KVM: Do not update PC if the trap handler has updated it

 arch/arm/kvm/coproc.c | 14 +++--
 arch/arm64/kvm/sys_regs.c | 73 +++
 2 files changed, 48 insertions(+), 39 deletions(-)

-- 
2.1.4

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


[PATCH 1/2] arm: KVM: Do not update PC if the trap handler has updated it

2015-12-22 Thread Marc Zyngier
Assuming we trap a coprocessor access, and decide that the access
is illegal, we will inject an exception in the guest. In this
case, we shouldn't increment the PC, or the vcpu will miss the
first instruction of the handler, leading to a mildly confused
guest.

Solve this by snapshoting PC before the access is performed,
and checking if it has moved or not before incrementing it.

Reported-by: Shannon Zhao <shannon.z...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm/kvm/coproc.c | 14 --
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index f3d88dc..f4ad2f2 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -447,12 +447,22 @@ static int emulate_cp15(struct kvm_vcpu *vcpu,
r = find_reg(params, cp15_regs, ARRAY_SIZE(cp15_regs));
 
if (likely(r)) {
+   unsigned long pc = *vcpu_pc(vcpu);
+
/* If we don't have an accessor, we should never get here! */
BUG_ON(!r->access);
 
if (likely(r->access(vcpu, params, r))) {
-   /* Skip instruction, since it was emulated */
-   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+   /*
+* Skip the instruction if it was emulated
+* without PC having changed. This allows us
+* to detect a fault being injected
+* (incrementing the PC here would cause the
+* vcpu to skip the first instruction of its
+* fault handler).
+*/
+   if (pc == *vcpu_pc(vcpu))
+   kvm_skip_instr(vcpu, 
kvm_vcpu_trap_il_is32bit(vcpu));
return 1;
}
/* If access function fails, it should complain. */
-- 
2.1.4

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


Re: [PATCH v7] arm/arm64: KVM: Detect vGIC presence at runtime

2015-12-18 Thread Marc Zyngier
On Fri, 18 Dec 2015 14:38:43 +0300
Pavel Fedin  wrote:

> Before commit 662d9715840aef44dcb573b0f9fab9e8319c868a
> ("arm/arm64: KVM: Kill CONFIG_KVM_ARM_{VGIC,TIMER}") is was possible to
> compile the kernel without vGIC and vTimer support. Commit message says
> about possibility to detect vGIC support in runtime, but this has never
> been implemented.
> 
> This patch introduces runtime check, restoring the lost functionality.
> It again allows to use KVM on hardware without vGIC. Interrupt
> controller has to be emulated in userspace in this case.
> 
> -ENODEV return code from probe function means there's no GIC at all.
> -ENXIO happens when, for example, there is GIC node in the device tree,
> but it does not specify vGIC resources. Any other error code is still
> treated as full stop because it might mean some really serious problems.
> 
> Signed-off-by: Pavel Fedin 
> Reviewed-by: Christoffer Dall 

Applied.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] KVM: arm/arm64: vgic-new: Try to insert multi-source SGIs at once

2015-12-18 Thread Marc Zyngier
Improve handling of multi-source SGIs: instead of only inserting
one source per SGI per run, try to insert them all at once.

Hopefully this is a rare case.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 30 ++
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index c6f04a1..052f917 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -371,15 +371,22 @@ static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
struct vgic_irq *irq;
int count = 0;
 
-   list_for_each_entry(irq, _cpu->ap_list_head, ap_list)
-   count++;
-
+   list_for_each_entry(irq, _cpu->ap_list_head, ap_list) {
+   spin_lock(>irq_lock);
+   /* GICv2 SGIs can count for more than one... */
+   if (irq->intid < VGIC_NR_SGIS && irq->source)
+   count += hweight8(irq->source);
+   else
+   count++;
+   spin_unlock(>irq_lock);
+   }
return count;
 }
 
 static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
 {
struct vgic_cpu *vgic_cpu = >arch.vgic_cpu;
+   u32 model = vcpu->kvm->arch.vgic.vgic_model;
struct vgic_irq *irq;
int count = 0;
 
@@ -390,8 +397,23 @@ static void vgic_populate_lrs(struct kvm_vcpu *vcpu)
 
list_for_each_entry(irq, _cpu->ap_list_head, ap_list) {
spin_lock(>irq_lock);
-   if (vgic_target_oracle(irq) == vcpu)
+
+   if (unlikely(vgic_target_oracle(irq) != vcpu))
+   goto next;
+
+   /*
+* If we get an SGI with multiple sources, try to get
+* them in all at once.
+*/
+   if (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+   irq->intid < VGIC_NR_SGIS) {
+   while(irq->source && count < vcpu->arch.vgic_cpu.nr_lr)
+   vgic_populate_lr(vcpu, irq, count++);
+   } else {
vgic_populate_lr(vcpu, irq, count++);
+   }
+
+   next:
spin_unlock(>irq_lock);
 
if (count == vcpu->arch.vgic_cpu.nr_lr)
-- 
2.1.4

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


[PULL] KVM/ARM fixes for v4.4-rc6

2015-12-18 Thread Marc Zyngier
Hi Paolo,

We have a one line fix for the VGIC this time around, fixing a patch
that went in -rc2. Oh well. Hopefully this is the last one for v4.4.

Please pull!

Thanks,

M.

The following changes since commit 0de58f852875a0f0dcfb120bb8433e4e73c7803b:

  ARM/arm64: KVM: correct PTE uncachedness check (2015-12-04 16:30:17 +)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git 
tags/kvm-arm-for-v4.4-rc6

for you to fetch changes up to fdec12c12ed4333afb49c9948c29fbd5fb52da97:

  KVM: arm/arm64: vgic: Fix kvm_vgic_map_is_active's dist check (2015-12-11 
16:33:31 +)


KVM/ARM fixes for v4.4-rc6

- Fix for the active interrupt detection code, affecting
  the timer interrupt injection.


Christoffer Dall (1):
  KVM: arm/arm64: vgic: Fix kvm_vgic_map_is_active's dist check

 virt/kvm/arm/vgic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PULL] KVM/ARM fixes for v4.4-rc6

2015-12-18 Thread Marc Zyngier

Idiot alert, sending the wrong patch...

On 18/12/15 13:00, Marc Zyngier wrote:
> Hi Paolo,
> 
> We have a one line fix for the VGIC this time around, fixing a patch
> that went in -rc2. Oh well. Hopefully this is the last one for v4.4.
> 
> Please pull!

Or don't, actually.

Sorry about the noise, the real one is coming in a minute, once I've
collected a couple of brain cells...

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] KVM: arm/arm64: vgic: Fix kvm_vgic_map_is_active's dist check

2015-12-18 Thread Marc Zyngier
From: Christoffer Dall <christoffer.d...@linaro.org>

External inputs to the vgic from time to time need to poke into the
state of a virtual interrupt, the prime example is the architected timer
code.

Since the IRQ's active state can be represented in two places; the LR or
the distributor, we first loop over the LRs but if not active in the LRs
we just return if *any* IRQ is active on the VCPU in question.

This is of course bogus, as we should check if the specific IRQ in
quesiton is active on the distributor instead.

Reported-by: Eric Auger <eric.au...@linaro.org>
Acked-by: Marc Zyngier <marc.zyng...@arm.com>
Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 virt/kvm/arm/vgic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 65461f8..7a2f449 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1114,7 +1114,7 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct 
irq_phys_map *map)
return true;
}
 
-   return dist_active_irq(vcpu);
+   return vgic_irq_is_active(vcpu, map->virt_irq);
 }
 
 /*
-- 
2.1.4

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


[PULL take #2] KVM/ARM fixes for v4.4-rc6

2015-12-18 Thread Marc Zyngier
Hi Paolo,

We have a one line fix for the VGIC this time around, fixing a patch
that went in -rc2. Oh well. Hopefully this is the last one for v4.4.
And yes, the right patch is following the pull-request this time...

Please pull!

Thanks,

M.

The following changes since commit 0de58f852875a0f0dcfb120bb8433e4e73c7803b:

  ARM/arm64: KVM: correct PTE uncachedness check (2015-12-04 16:30:17 +)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git 
tags/kvm-arm-for-v4.4-rc6

for you to fetch changes up to fdec12c12ed4333afb49c9948c29fbd5fb52da97:

  KVM: arm/arm64: vgic: Fix kvm_vgic_map_is_active's dist check (2015-12-11 
16:33:31 +)


KVM/ARM fixes for v4.4-rc6

- Fix for the active interrupt detection code, affecting
  the timer interrupt injection.


Christoffer Dall (1):
  KVM: arm/arm64: vgic: Fix kvm_vgic_map_is_active's dist check

 virt/kvm/arm/vgic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-17 Thread Marc Zyngier
On Thu, 17 Dec 2015 15:22:50 +0800
Shannon Zhao  wrote:

> 
> 
> On 2015/12/17 4:33, Christoffer Dall wrote:
> > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> >> Hi,
> >>
> >> On 2015/12/16 15:31, Shannon Zhao wrote:
> > But in this case, you're returning an error if it is *not* 
> > initialized.
> > I understand that in that case you cannot return an interrupt 
> > number (-1
> > would be weird), but returning -EBUSY feels even more weird.
> >
> > I'd settle for -ENOXIO, or something similar. Anyone having a 
> > better idea?
> >
> > ENXIO or ENODEV would be my choice too, and add that to the
> > Documentation clearly describing when this error code is used.
> >
> > By the way, why do you loop over all VCPUS to set the same value when
> > you can't do anything per VCPU anyway?  It seems to me it's either a
> > per-VM property (that you can store on the VM data structure) or it's a
> > true per-VCPU property?
> >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> >>> the interrupt numbers are same for each vcpu, while for SPI they are
> >>> different, so it needs to set them separately. I planned to support both
> >>> PPI and SPI. I think I should add support for SPI at this moment and let
> >>> users (QEMU) to set these interrupts for each one.
> >>
> >> How about below vPMU Documentation?
> >>
> >> ARM Virtual Performance Monitor Unit (vPMU)
> >> ===
> >>
> >> Device types supported:
> >>   KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
> >>
> >> Instantiate one PMU instance for per VCPU through this API.
> >>
> >> Groups:
> >>   KVM_DEV_ARM_PMU_GRP_IRQ
> >>   Attributes:
> >> The attr field of kvm_device_attr encodes two values:
> >> bits: | 63  32 | 31  0 |
> >> values:   | vcpu_index |  irq_num  |
> BTW, I change this Attribute to below format and pass vcpu_index through
> this Attribute while pass irq_num through kvm_device_attr.addr.
> Is it fine?
> 
> bits: | 63  32 | 31   0 |
> values:   |  reserved  | vcpu_index |

Using the .addr field for something that is clearly not an address is
rather odd. Is there any prior usage of that field for something that
is not an address?

Thanks,

M.
-- 
Without deviation from the norm, progress is not possible.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-17 Thread Marc Zyngier
On 17/12/15 10:10, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 17:38, Marc Zyngier wrote:
>> On 17/12/15 08:41, Shannon Zhao wrote:
>>>>
>>>>
>>>> On 2015/12/17 16:33, Marc Zyngier wrote:
>>>>>> On Thu, 17 Dec 2015 15:22:50 +0800
>>>>>> Shannon Zhao <zhaoshengl...@huawei.com> wrote:
>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>>>>>>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> But in this case, you're 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> returning an error if it is 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> *not* initialized.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I understand that in that case 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> you cannot return an interrupt 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> number (-1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> would be weird), but returning 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> something similar. Anyone having 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> a better idea?
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> that to the
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Documentation clearly describing when this error 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> code is used.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> set the same value when
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> to me it's either a
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> per-VM property (that you can store on the VM 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> data structure) or it's a
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>>>>>>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI 
>>>>>>>>>>>>>>>>>>>>>> or SPI. For PPI
>>>>>>>>>>>>>>>>>>>>>> the interrupt numbers are same for each vcpu, while for 
>>>>>>>>>>>>>>>>>>>>>> SPI they are
>>>>>>>>>>>>>>>>>>>>>> different, so it needs to set them separately. I planned 
>>>>>>>>>>>>>>>>>>>>>> to support both
>>>>>>>>>>>>>>>>>>>>>> PPI and SPI. I think I should add support for SPI at 
>>>>>>>>>>>>>>>>>>>>>> this moment and let
>>>>>>>>>>>>>>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> How about below vPMU Documentation?
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>>>>>>>>>>>> ===
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Device types supported:
>>>>>>>>>>>>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor 
>>>>>>>>>>>>>>>>>> Unit v3
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Groups:
>>>>>>>>>>>>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>>>>>>>>>>>   Attributes:
>>>>>>>>>>>>>>>>>> The attr field of kvm_device_attr encodes two values:
>>>>>>>>>>>>>>>>>> bits: | 63  32 | 31  0 |
>>>>>>>>>>>>>>>>>> values:   | vcpu_index |  irq_num  |
>>>>>>>>>> BTW, I change this Attribute to below format and pass vcpu_index 
>>>>>>>>>> through
>>>>>>>>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>>>>>>>> Is it fine?
>>>>>>>>>>
>>>>>>>>>> bits: | 63  32 | 31   0 |
>>>>>>>>>> values:   |  reserved  | vcpu_index |
>>>>>> Using the .addr field for something that is clearly not an address is
>>>>>> rather odd. Is there any prior usage of that field for something that
>>>>>> is not an address?
>>>>
>>>> I see this usage in vgic_attr_regs_access(). But if you prefer previous
>>>> one, I'll use that.
>> Ah, you're using the .addr field to point to a userspace value, not to
>> carry the value itself! That'd be fine by me (even if I still prefer the
>> original one), but I'd like others to chime in (I'm quite bad at
>> defining userspace stuff...).
> 
> Another reason I think is that it needs to pass the irq_num to user
> space when calling get_attr. It could be passed via kvm_device_attr.addr
> while can't be passed via kvm_device_attr.attr within current framework.

That's a very good reason. Go for it.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-17 Thread Marc Zyngier
On 17/12/15 08:41, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 16:33, Marc Zyngier wrote:
>> On Thu, 17 Dec 2015 15:22:50 +0800
>> Shannon Zhao <zhaoshengl...@huawei.com> wrote:
>>
>>>>
>>>>
>>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is 
>>>>>>>>>>>>>>>>>>>>>> *not* initialized.
>>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an 
>>>>>>>>>>>>>>>>>>>>>> interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more 
>>>>>>>>>>>>>>>>>>>>>> weird.
>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone 
>>>>>>>>>>>>>>>>>>>>>> having a better idea?
>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value 
>>>>>>>>>>>>>> when
>>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's 
>>>>>>>>>>>>>> either a
>>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or 
>>>>>>>>>>>>>> it's a
>>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For 
>>>>>>>>>> PPI
>>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>> different, so it needs to set them separately. I planned to support 
>>>>>>>>>> both
>>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and 
>>>>>>>>>> let
>>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>
>>>>>>>> How about below vPMU Documentation?
>>>>>>>>
>>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>> ===
>>>>>>>>
>>>>>>>> Device types supported:
>>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
>>>>>>>>
>>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>
>>>>>>>> Groups:
>>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>   Attributes:
>>>>>>>> The attr field of kvm_device_attr encodes two values:
>>>>>>>> bits: | 63  32 | 31  0 |
>>>>>>>> values:   | vcpu_index |  irq_num  |
>>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>> Is it fine?
>>>>
>>>> bits: | 63  32 | 31   0 |
>>>> values:   |  reserved  | vcpu_index |
>> Using the .addr field for something that is clearly not an address is
>> rather odd. Is there any prior usage of that field for something that
>> is not an address?
> 
> I see this usage in vgic_attr_regs_access(). But if you prefer previous
> one, I'll use that.

Ah, you're using the .addr field to point to a userspace value, not to
carry the value itself! That'd be fine by me (even if I still prefer the
original one), but I'd like others to chime in (I'm quite bad at
defining userspace stuff...).

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function

2015-12-17 Thread Marc Zyngier
On 17/12/15 15:22, Mark Rutland wrote:
> On Tue, Dec 15, 2015 at 04:49:27PM +0800, Shannon Zhao wrote:
>> From: Shannon Zhao 
>>
>> When we use tools like perf on host, perf passes the event type and the
>> id of this event type category to kernel, then kernel will map them to
>> hardware event number and write this number to PMU PMEVTYPER_EL0
>> register. When getting the event number in KVM, directly use raw event
>> type to create a perf_event for it.
>>
>> Signed-off-by: Shannon Zhao 
>> ---
>>  arch/arm64/include/asm/pmu.h |   3 ++
>>  arch/arm64/kvm/Makefile  |   1 +
>>  include/kvm/arm_pmu.h|  11 
>>  virt/kvm/arm/pmu.c   | 122 
>> +++
>>  4 files changed, 137 insertions(+)
>>  create mode 100644 virt/kvm/arm/pmu.c
> 
> [...]
> 
>> +/**
>> + * kvm_pmu_set_counter_event_type - set selected counter to monitor some 
>> event
>> + * @vcpu: The vcpu pointer
>> + * @data: The data guest writes to PMXEVTYPER_EL0
>> + * @select_idx: The number of selected counter
>> + *
>> + * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to 
>> count an
>> + * event with given hardware event number. Here we call perf_event API to
>> + * emulate this action and create a kernel perf event for it.
>> + */
>> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>> +u64 select_idx)
>> +{
>> +struct kvm_pmu *pmu = >arch.pmu;
>> +struct kvm_pmc *pmc = >pmc[select_idx];
>> +struct perf_event *event;
>> +struct perf_event_attr attr;
>> +u64 eventsel, counter;
>> +
>> +kvm_pmu_stop_counter(vcpu, pmc);
>> +eventsel = data & ARMV8_EVTYPE_EVENT;
>> +
>> +memset(, 0, sizeof(struct perf_event_attr));
>> +attr.type = PERF_TYPE_RAW;
>> +attr.size = sizeof(attr);
>> +attr.pinned = 1;
>> +attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
>> +attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
>> +attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
>> +attr.exclude_hv = 1; /* Don't count EL2 events */
>> +attr.exclude_host = 1; /* Don't count host events */
>> +attr.config = eventsel;
>> +
>> +counter = kvm_pmu_get_counter_value(vcpu, select_idx);
>> +/* The initial sample period (overflow count) of an event. */
>> +attr.sample_period = (-counter) & pmc->bitmask;
>> +
>> +event = perf_event_create_kernel_counter(, -1, current, NULL, pmc);
> 
> As far as I can see, this is going to result in unreliable counts on a
> big.LITTLE system, even if the VCPUs are constrained to one class of
> core.
> 
> As this is a task-bound event (cpu == -1, task is current), the perf
> core will stop as soon as one PMU driver agrees to handle the event. The
> event will then only count on CPUs handled by that driver.
> 
> If you're unlucky, the set of CPUs handled by that driver is not the
> same as the set of CPUs your VM is constrained to. e.g. your VM might be
> on little cores, but the big PMU driver accepted the event, and only
> counts on big cores.
> 
> I'm not sure how we can solve that.

Yeah, another level of BL braindeadness. We should have some API to
match the PMU we want on the CPU we're on at the moment that trap occurs.

I don't think this should block this series though - this is something
we can improve on in parallel (a possible solution being to forbid KVM
on BL platform altogether).

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] arm64: KVM: debug: Remove spurious inline attributes

2015-12-17 Thread Marc Zyngier
On 17/12/15 16:28, Alex Bennée wrote:
> 
> Marc Zyngier <marc.zyng...@arm.com> writes:
> 
>> The debug trapping code is pretty heavy on the "inline" attribute,
>> but most functions are actually referenced in the sysreg tables,
>> making the inlining imposible.
>>
>> Removing the useless inline qualifier seems the right thing to do,
>> having verified that the output code is similar.
>>
>> Cc: Alex Bennée <alex.ben...@linaro.org>
>> Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
>> ---
>>  arch/arm64/kvm/sys_regs.c | 58 
>> +++
>>  1 file changed, 29 insertions(+), 29 deletions(-)
>>
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index 88adebf..eec3598 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -220,9 +220,9 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
>>   * All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the
>>   * hyp.S code switches between host and guest values in future.
>>   */
>> -static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
>> -  struct sys_reg_params *p,
>> -  u64 *dbg_reg)
>> +static void reg_to_dbg(struct kvm_vcpu *vcpu,
>> +   struct sys_reg_params *p,
>> +   u64 *dbg_reg)
>>  {
>>  u64 val = p->regval;
>>
>> @@ -235,18 +235,18 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
>>  vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>>  }
>>
>> -static inline void dbg_to_reg(struct kvm_vcpu *vcpu,
>> -  struct sys_reg_params *p,
>> -  u64 *dbg_reg)
>> +static void dbg_to_reg(struct kvm_vcpu *vcpu,
>> +   struct sys_reg_params *p,
>> +   u64 *dbg_reg)
>>  {
>>  p->regval = *dbg_reg;
>>  if (p->is_32bit)
>>  p->regval &= 0xUL;
>>  }
> 
> Christoffer's "register keyword" comments not-withstanding I'd prefer to
> keep the reg_to_dbg/dbg_to_reg functions as inline because they really
> are just boilerplate helpers I didn't want to repeat in the actual
> access functions - although if you've looked at the code I assume that
> means GCC has been smart about it.

Indeed, GCC is smart enough to directly inline it. In general, GCC is
doing a pretty good job at inlining static functions that are small
enough not to be worth jumping to. These days, "static inline" only
really makes sense in an include file.

> The rest all make sense. I wonder why I was being so inline happy?
> 
> Reviewed-by: Alex Bennée <alex.ben...@linaro.org>

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] arm64: KVM: debug: Remove spurious inline attributes

2015-12-16 Thread Marc Zyngier
The debug trapping code is pretty heavy on the "inline" attribute,
but most functions are actually referenced in the sysreg tables,
making the inlining imposible.

Removing the useless inline qualifier seems the right thing to do,
having verified that the output code is similar.

Cc: Alex Bennée <alex.ben...@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm64/kvm/sys_regs.c | 58 +++
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 88adebf..eec3598 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -220,9 +220,9 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
  * All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the
  * hyp.S code switches between host and guest values in future.
  */
-static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
- struct sys_reg_params *p,
- u64 *dbg_reg)
+static void reg_to_dbg(struct kvm_vcpu *vcpu,
+  struct sys_reg_params *p,
+  u64 *dbg_reg)
 {
u64 val = p->regval;
 
@@ -235,18 +235,18 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
 }
 
-static inline void dbg_to_reg(struct kvm_vcpu *vcpu,
- struct sys_reg_params *p,
- u64 *dbg_reg)
+static void dbg_to_reg(struct kvm_vcpu *vcpu,
+  struct sys_reg_params *p,
+  u64 *dbg_reg)
 {
p->regval = *dbg_reg;
if (p->is_32bit)
p->regval &= 0xUL;
 }
 
-static inline bool trap_bvr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_bvr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_bvr[rd->reg];
 
@@ -280,15 +280,15 @@ static int get_bvr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_bvr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_bvr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg] = rd->val;
 }
 
-static inline bool trap_bcr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_bcr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_bcr[rd->reg];
 
@@ -323,15 +323,15 @@ static int get_bcr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_bcr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_bcr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg] = rd->val;
 }
 
-static inline bool trap_wvr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_wvr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_wvr[rd->reg];
 
@@ -366,15 +366,15 @@ static int get_wvr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_wvr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_wvr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg] = rd->val;
 }
 
-static inline bool trap_wcr(struct kvm_vcpu *vcpu,
-   struct sys_reg_params *p,
-   const struct sys_reg_desc *rd)
+static bool trap_wcr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *p,
+const struct sys_reg_desc *rd)
 {
u64 *dbg_reg = >arch.vcpu_debug_state.dbg_wcr[rd->reg];
 
@@ -408,8 +408,8 @@ static int get_wcr(struct kvm_vcpu *vcpu, const struct 
sys_reg_desc *rd,
return 0;
 }
 
-static inline void reset_wcr(struct kvm_vcpu *vcpu,
-const struct sys_reg_desc *rd)
+static void reset_wcr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
 {
vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg] = rd->val;
 }
@@ -723,9 +723,9 @@ static bool trap_debug

Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-16 Thread Marc Zyngier
On 16/12/15 08:06, Shannon Zhao wrote:
> Hi,
> 
> On 2015/12/16 15:31, Shannon Zhao wrote:
 But in this case, you're returning an error if it is *not* initialized.
 I understand that in that case you cannot return an interrupt number 
 (-1
 would be weird), but returning -EBUSY feels even more weird.

 I'd settle for -ENOXIO, or something similar. Anyone having a better 
 idea?

 ENXIO or ENODEV would be my choice too, and add that to the
 Documentation clearly describing when this error code is used.

 By the way, why do you loop over all VCPUS to set the same value when
 you can't do anything per VCPU anyway?  It seems to me it's either a
 per-VM property (that you can store on the VM data structure) or it's a
 true per-VCPU property?
>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>> the interrupt numbers are same for each vcpu, while for SPI they are
>> different, so it needs to set them separately. I planned to support both
>> PPI and SPI. I think I should add support for SPI at this moment and let
>> users (QEMU) to set these interrupts for each one.
> 
> How about below vPMU Documentation?
> 
> ARM Virtual Performance Monitor Unit (vPMU)
> ===
> 
> Device types supported:
>   KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
> 
> Instantiate one PMU instance for per VCPU through this API.
> 
> Groups:
>   KVM_DEV_ARM_PMU_GRP_IRQ
>   Attributes:
> The attr field of kvm_device_attr encodes two values:
> bits: | 63  32 | 31  0 |
> values:   | vcpu_index |  irq_num  |
> The irq_num describes the PMU overflow interrupt number for the
> specified
> vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
> VM the
> interrupt type must be same for each vcpu.
> 
>   Errors:
> -ENXIO: Getting or setting this attribute is not yet supported
> -ENODEV: Getting the PMU overflow interrupt number while it's not set
> -EBUSY: The PMU overflow interrupt is already set
> -EINVAL: Invalid vcpu_index or irq_num supplied
> 
> 

Let's add at least one comment that forbids two vcpus from getting the
same SPI. This is too common a mistake that we see in actual SoCs, and I
don't want to see it replicated in VMs...

Thanks,

M.

-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 15:59, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 22:58, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
>>>> From: Shannon Zhao<shannon.z...@linaro.org>
>>>>
>>>> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
>>>>
>>>> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
>>>> accessed from EL0. Add some check helpers to handle the access from EL0.
>>>>
>>>> Signed-off-by: Shannon Zhao<shannon.z...@linaro.org>
>>>> ---
>>>>  arch/arm64/kvm/sys_regs.c | 124 
>>>> --
>>>>  1 file changed, 119 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>>>> index b2ccc25..bad3dfd 100644
>>>> --- a/arch/arm64/kvm/sys_regs.c
>>>> +++ b/arch/arm64/kvm/sys_regs.c
>>>> @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
>>>> struct sys_reg_desc *r)
>>>>vcpu_sys_reg(vcpu, r->reg) = val;
>>>>  }
>>>>
>>>> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +  return !((reg & 0x1) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +  return !((reg & 0x3) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu 
>>>> *vcpu)
>>>> +{
>>>> +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +  return !((reg & 0x5) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu 
>>>> *vcpu)
>>>> +{
>>>> +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +  return !((reg & 0x9) || vcpu_mode_priv(vcpu));
>>>> +}
>> Please add #defines for the PMUSERNR_EL0 bits.
>>
>>>> +
>>>>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>>>>const struct sys_reg_desc *r)
>>>>  {
>>>>u64 val;
>>>> +  bool unaccessible = pmu_access_el0_disabled(vcpu);
>>>>
>>>>if (p->is_write) {
>>>> +  if (unaccessible)
>>>> +  return ignore_write(vcpu, p);
>>>> +
>> This is not how this is supposed to work. If EL0 is denied access to the
>> PMU, you must inject an exception into EL1 for it to handle the fault.
>> The code should reflect the flow described at D5.11.2 in the ARM ARM.
>>
> Does it need to add a helper to inject an exception into EL1 or is there 
> a existing one?

You can use some of the stuff in inject_fault.c as a starting point.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Marc Zyngier
On 15/12/15 03:46, Bhushan Bharat wrote:
> 
> Hi All,
> 
> I am running "iperf" in KVM guest on ARM64 machine and observing below crash.
> 
> =
> $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
> 
> Client connecting to 3.3.3.3, TCP port 5001
> TCP window size:  180 KByte (WARNING: requested 90.0 KByte)
> 
> [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001
> [  6] local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001
> [  5] local 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001
> [  4] local 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
> [   53.088567] random: nonblocking pool is initialized
> [ ID] Interval   Transfer Bandwidth
> [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
> [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec
> [  5] 40.0-45.0 sec  1.11 GBytes  1.90 Gbits/sec
> [  4] 40.0-45.0 sec  1.16 GBytes  1.99 Gbits/sec
> [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
> [   98.896164] page:78296100 count:-1 mapcount:0 mapping:  
> (null) index:0x0
> [   98.897436] flags: 0x0()
> [   98.897885] page dumped because: nonzero _count
> [   98.898640] Modules linked in:
> [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-ge5431ad 
> #141
> [   98.900302] Hardware name: linux,dummy-virt (DT)
> [   98.901014] Call trace:
> [   98.901406] [] dump_backtrace+0x0/0x12c
> [   98.902522] [] show_stack+0x10/0x1c
> [   98.903441] [] dump_stack+0x8c/0xdc
> [   98.904202] [] bad_page+0xc4/0x114
> [   98.904945] [] get_page_from_freelist+0x590/0x63c
> [   98.905871] [] __alloc_pages_nodemask+0xec/0x794
> [   98.906791] [] skb_page_frag_refill+0x70/0xa8
> [   98.907678] [] sk_page_frag_refill+0x20/0xd0
> [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
> [   98.909368] [] inet_sendmsg+0x5c/0xd0
> [   98.910178] [] sock_sendmsg+0x14/0x58
> [   98.911027] [] sock_write_iter+0x64/0xbc
> [   98.912119] [] __vfs_write+0xac/0x10c
> [   98.913126] [] vfs_write+0x90/0x1a0
> [   98.913963] [] SyS_write+0x40/0xa0

This looks quite bad, but I don't see anything here that links it to KVM
(apart from being a guest). Do you have any indication that this is due
to KVM misbehaving? I'd appreciate a few more details.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Marc Zyngier
On 15/12/15 09:53, Bhushan Bharat wrote:
> Hi Mark,
> 
>> -Original Message-----
>> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
>> Sent: Tuesday, December 15, 2015 3:05 PM
>> To: Bhushan Bharat-R65777 <bharat.bhus...@freescale.com>;
>> kvm...@lists.cs.columbia.edu; kvm@vger.kernel.org; linux-arm-
>> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
>> Subject: Re: ARM64/KVM: Bad page state in process iperf
>>
>> On 15/12/15 03:46, Bhushan Bharat wrote:
>>>
>>> Hi All,
>>>
>>> I am running "iperf" in KVM guest on ARM64 machine and observing below
>> crash.
>>>
>>> =
>>> $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
>>> 
>>> Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
>>> KByte (WARNING: requested 90.0 KByte)
>>> 
>>> [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [  6]
>>> local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5] local
>>> 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
>>> 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
>>> [   53.088567] random: nonblocking pool is initialized
>>> [ ID] Interval   Transfer Bandwidth
>>> [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
>>> [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0 sec
>>> 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
>>> Gbits/sec
>>> [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
>>> [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
>> (null) index:0x0
>>> [   98.897436] flags: 0x0()
>>> [   98.897885] page dumped because: nonzero _count
>>> [   98.898640] Modules linked in:
>>> [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
>> ge5431ad #141
>>> [   98.900302] Hardware name: linux,dummy-virt (DT)
>>> [   98.901014] Call trace:
>>> [   98.901406] [] dump_backtrace+0x0/0x12c
>>> [   98.902522] [] show_stack+0x10/0x1c
>>> [   98.903441] [] dump_stack+0x8c/0xdc
>>> [   98.904202] [] bad_page+0xc4/0x114
>>> [   98.904945] [] get_page_from_freelist+0x590/0x63c
>>> [   98.905871] [] __alloc_pages_nodemask+0xec/0x794
>>> [   98.906791] [] skb_page_frag_refill+0x70/0xa8
>>> [   98.907678] [] sk_page_frag_refill+0x20/0xd0
>>> [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
>>> [   98.909368] [] inet_sendmsg+0x5c/0xd0
>>> [   98.910178] [] sock_sendmsg+0x14/0x58
>>> [   98.911027] [] sock_write_iter+0x64/0xbc
>>> [   98.912119] [] __vfs_write+0xac/0x10c
>>> [   98.913126] [] vfs_write+0x90/0x1a0
>>> [   98.913963] [] SyS_write+0x40/0xa0
>>
>> This looks quite bad, but I don't see anything here that links it to KVM 
>> (apart
>> from being a guest). Do you have any indication that this is due to KVM
>> misbehaving? 
> 
> I never observed this issue in host Linux but observed this issue always in 
> guest Linux. This issue does not comes immediately after I run "iperf" but 
> after some time.
> 
>> I'd appreciate a few more details.
> 
> We have a networking hardware and we are directly assigning the h/w to guest. 
> When using the same networking hardware in host it always works as expected 
> (tried 100s of times).
> Also this issue is not observed when we have only one vCPU in guest but seen 
> when we have SMP guest. 

Can you reproduce the same issue without VFIO (using virtio, for
example)? Is that platform VFIO? or PCI?

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Marc Zyngier
On 15/12/15 10:57, Bhushan Bharat wrote:
> 
> 
>> -Original Message-----
>> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
>> Sent: Tuesday, December 15, 2015 3:50 PM
>> To: Bhushan Bharat-R65777 <bharat.bhus...@freescale.com>;
>> kvm...@lists.cs.columbia.edu; kvm@vger.kernel.org; linux-arm-
>> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
>> Subject: Re: ARM64/KVM: Bad page state in process iperf
>>
>> On 15/12/15 09:53, Bhushan Bharat wrote:
>>> Hi Mark,
>>>
>>>> -Original Message-
>>>> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
>>>> Sent: Tuesday, December 15, 2015 3:05 PM
>>>> To: Bhushan Bharat-R65777 <bharat.bhus...@freescale.com>;
>>>> kvm...@lists.cs.columbia.edu; kvm@vger.kernel.org; linux-arm-
>>>> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
>>>> Subject: Re: ARM64/KVM: Bad page state in process iperf
>>>>
>>>> On 15/12/15 03:46, Bhushan Bharat wrote:
>>>>>
>>>>> Hi All,
>>>>>
>>>>> I am running "iperf" in KVM guest on ARM64 machine and observing
>>>>> below
>>>> crash.
>>>>>
>>>>> =
>>>>> $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
>>>>> 
>>>>> Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
>>>>> KByte (WARNING: requested 90.0 KByte)
>>>>> 
>>>>> [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [
>>>>> 6] local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5]
>>>>> local
>>>>> 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
>>>>> 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
>>>>> [   53.088567] random: nonblocking pool is initialized
>>>>> [ ID] Interval   Transfer Bandwidth
>>>>> [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
>>>>> [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0 sec
>>>>> 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
>>>>> Gbits/sec
>>>>> [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
>>>>> [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
>>>> (null) index:0x0
>>>>> [   98.897436] flags: 0x0()
>>>>> [   98.897885] page dumped because: nonzero _count
>>>>> [   98.898640] Modules linked in:
>>>>> [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
>>>> ge5431ad #141
>>>>> [   98.900302] Hardware name: linux,dummy-virt (DT)
>>>>> [   98.901014] Call trace:
>>>>> [   98.901406] [] dump_backtrace+0x0/0x12c
>>>>> [   98.902522] [] show_stack+0x10/0x1c
>>>>> [   98.903441] [] dump_stack+0x8c/0xdc
>>>>> [   98.904202] [] bad_page+0xc4/0x114
>>>>> [   98.904945] []
>> get_page_from_freelist+0x590/0x63c
>>>>> [   98.905871] []
>> __alloc_pages_nodemask+0xec/0x794
>>>>> [   98.906791] [] skb_page_frag_refill+0x70/0xa8
>>>>> [   98.907678] [] sk_page_frag_refill+0x20/0xd0
>>>>> [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
>>>>> [   98.909368] [] inet_sendmsg+0x5c/0xd0
>>>>> [   98.910178] [] sock_sendmsg+0x14/0x58
>>>>> [   98.911027] [] sock_write_iter+0x64/0xbc
>>>>> [   98.912119] [] __vfs_write+0xac/0x10c
>>>>> [   98.913126] [] vfs_write+0x90/0x1a0
>>>>> [   98.913963] [] SyS_write+0x40/0xa0
>>>>
>>>> This looks quite bad, but I don't see anything here that links it to
>>>> KVM (apart from being a guest). Do you have any indication that this
>>>> is due to KVM misbehaving?
>>>
>>> I never observed this issue in host Linux but observed this issue always in
>> guest Linux. This issue does not comes immediately after I run "iperf" but
>> after some time.
>>>
>>>> I'd appreciate a few more details.
>>>
>>> We have a networking hardware and we are directly assigning the h/w to
>> guest. When using the same networking hardware in host it always works as
>> expected (tried 100s of times).
>>> Also this issue is not observed when we have only one vCPU in guest but
>> seen when we have SMP guest.
>>
>> Can you reproduce the same issue without VFIO (using virtio, for example)?
> 
> With virtio I have not observed this issue.
> 
>> Is that platform VFIO? or PCI?
> 
> It is not vfio-pci and vfio-platform. It is vfio-fls-mc (some
> Freescale new hardware), similar to the lines of vfio-platform uses
> same set of VFIO APIs used by vfio-pci/platform. Do you think this
> can be some h/w specific issue.

I have no idea, but by the look of it, something could be doing DMA on
top of your guest page tables, which is not really expected. I suggest
you carefully look at:

1) the DMA addresses that are passed to your device
2) the page tables that are programmed into the SMMU
3) the resulting translation

Hopefully this will give you a clue about what is generating this.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> To use the ARMv8 PMU related register defines from the KVM code,
> we move the relevant definitions to asm/pmu.h header file.
> 
> Signed-off-by: Anup Patel 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/include/asm/pmu.h   | 64 
> ++
>  arch/arm64/kernel/perf_event.c | 36 +---
>  2 files changed, 65 insertions(+), 35 deletions(-)
>  create mode 100644 arch/arm64/include/asm/pmu.h
> 
> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
> new file mode 100644
> index 000..4264ea0
> --- /dev/null
> +++ b/arch/arm64/include/asm/pmu.h
> @@ -0,0 +1,64 @@
> +/*
> + * Copyright (C) 2015 Linaro Ltd, Shannon Zhao

Erm, not quite. You're simply moving existing code from one file to
another. That doesn't change the copyright of said code, which reads:

 * PMU support
 *
 * Copyright (C) 2012 ARM Limited
 * Author: Will Deacon 

Please keep this mention in place.

> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see .
> + */
> +#ifndef __ASM_PMU_H
> +#define __ASM_PMU_H
> +
> +#define ARMV8_MAX_COUNTERS  32
> +#define ARMV8_COUNTER_MASK  (ARMV8_MAX_COUNTERS - 1)
> +
> +/*
> + * Per-CPU PMCR: config reg
> + */
> +#define ARMV8_PMCR_E (1 << 0) /* Enable all counters */
> +#define ARMV8_PMCR_P (1 << 1) /* Reset all counters */
> +#define ARMV8_PMCR_C (1 << 2) /* Cycle counter reset */
> +#define ARMV8_PMCR_D (1 << 3) /* CCNT counts every 64th cpu cycle */
> +#define ARMV8_PMCR_X (1 << 4) /* Export to ETM */
> +#define ARMV8_PMCR_DP(1 << 5) /* Disable CCNT if 
> non-invasive debug*/
> +#define  ARMV8_PMCR_N_SHIFT  11   /* Number of counters 
> supported */
> +#define  ARMV8_PMCR_N_MASK   0x1f
> +#define  ARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
> +
> +/*
> + * PMCNTEN: counters enable reg
> + */
> +#define  ARMV8_CNTEN_MASK0x  /* Mask for writable 
> bits */
> +
> +/*
> + * PMINTEN: counters interrupt enable reg
> + */
> +#define  ARMV8_INTEN_MASK0x  /* Mask for writable 
> bits */
> +
> +/*
> + * PMOVSR: counters overflow flag status reg
> + */
> +#define  ARMV8_OVSR_MASK 0x  /* Mask for writable 
> bits */
> +#define  ARMV8_OVERFLOWED_MASK   ARMV8_OVSR_MASK
> +
> +/*
> + * PMXEVTYPER: Event selection reg
> + */
> +#define  ARMV8_EVTYPE_MASK   0xc80003ff  /* Mask for writable 
> bits */
> +#define  ARMV8_EVTYPE_EVENT  0x3ff   /* Mask for EVENT bits 
> */
> +
> +/*
> + * Event filters for PMUv3
> + */
> +#define  ARMV8_EXCLUDE_EL1   (1 << 31)
> +#define  ARMV8_EXCLUDE_EL0   (1 << 30)
> +#define  ARMV8_INCLUDE_EL2   (1 << 27)
> +
> +#endif /* __ASM_PMU_H */
> diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
> index 5b1897e..7eca5dc 100644
> --- a/arch/arm64/kernel/perf_event.c
> +++ b/arch/arm64/kernel/perf_event.c
> @@ -24,6 +24,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  /*
>   * ARMv8 PMUv3 Performance Events handling code.
> @@ -187,9 +188,6 @@ static const unsigned 
> armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
>  #define  ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
>   (ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
>  
> -#define  ARMV8_MAX_COUNTERS  32
> -#define  ARMV8_COUNTER_MASK  (ARMV8_MAX_COUNTERS - 1)
> -
>  /*
>   * ARMv8 low level PMU access
>   */
> @@ -200,38 +198,6 @@ static const unsigned 
> armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
>  #define  ARMV8_IDX_TO_COUNTER(x) \
>   (((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
>  
> -/*
> - * Per-CPU PMCR: config reg
> - */
> -#define ARMV8_PMCR_E (1 << 0) /* Enable all counters */
> -#define ARMV8_PMCR_P (1 << 1) /* Reset all counters */
> -#define ARMV8_PMCR_C (1 << 2) /* Cycle counter reset */
> -#define ARMV8_PMCR_D (1 << 3) /* CCNT counts every 64th cpu cycle */
> -#define ARMV8_PMCR_X (1 << 4) /* Export to ETM */
> -#define ARMV8_PMCR_DP(1 << 5) /* Disable CCNT if 
> non-invasive debug*/
> -#define  ARMV8_PMCR_N_SHIFT  11   /* Number of counters 
> supported */
> 

Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Marc Zyngier
On 15/12/15 15:50, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 23:33, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
>>>> From: Shannon Zhao<shannon.z...@linaro.org>
>>>>
>>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>>>> the kvm_device_ops for it.
>>>>
>>>> Signed-off-by: Shannon Zhao<shannon.z...@linaro.org>
>>>> ---
>>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
>>>>  arch/arm64/include/uapi/asm/kvm.h |   3 +
>>>>  include/linux/kvm_host.h  |   1 +
>>>>  include/uapi/linux/kvm.h  |   2 +
>>>>  virt/kvm/arm/pmu.c| 115 
>>>> ++
>>>>  virt/kvm/kvm_main.c   |   4 +
>>>>  6 files changed, 141 insertions(+)
>>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>
>>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
>>>> b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>> new file mode 100644
>>>> index 000..5121f1f
>>>> --- /dev/null
>>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>> @@ -0,0 +1,16 @@
>>>> +ARM Virtual Performance Monitor Unit (vPMU)
>>>> +===
>>>> +
>>>> +Device types supported:
>>>> +  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
>>>> +
>>>> +Instantiate one PMU instance for per VCPU through this API.
>>>> +
>>>> +Groups:
>>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
>>>> +  Attributes:
>>>> +A value describing the interrupt number of PMU overflow interrupt. 
>>>> This
>>>> +interrupt should be a PPI.
>>>> +
>>>> +  Errors:
>>>> +-EINVAL: Value set is out of the expected range (from 16 to 31)
>>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h 
>>>> b/arch/arm64/include/uapi/asm/kvm.h
>>>> index 2d4ca4b..568afa2 100644
>>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL 4
>>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT  0
>>>>
>>>> +/* Device Control API: ARM PMU */
>>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ   0
>>>> +
>>>>  /* KVM_IRQ_LINE irq field index values */
>>>>  #define KVM_ARM_IRQ_TYPE_SHIFT24
>>>>  #define KVM_ARM_IRQ_TYPE_MASK 0xff
>>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>>>> index c923350..608dea6 100644
>>>> --- a/include/linux/kvm_host.h
>>>> +++ b/include/linux/kvm_host.h
>>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>>>>  extern struct kvm_device_ops kvm_xics_ops;
>>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>>>>
>>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>>>>
>>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>> index 03f3618..4ba6fdd 100644
>>>> --- a/include/uapi/linux/kvm.h
>>>> +++ b/include/uapi/linux/kvm.h
>>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>>>>  #define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
>>>>KVM_DEV_TYPE_ARM_VGIC_V3,
>>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3  KVM_DEV_TYPE_ARM_VGIC_V3
>>>> +  KVM_DEV_TYPE_ARM_PMU_V3,
>>>> +#define   KVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
>>>>KVM_DEV_TYPE_MAX,
>>>>  };
>>>>
>>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>>>> index d113ee4..1965d0d 100644
>>>> --- a/virt/kvm/arm/pmu.c
>>>> +++ b/virt/kvm/arm/pmu.c
>>>> @@ -19,6 +19,7 @@
>>>>  #include 
>>>>  #include 
>>>>  #include 
>>>> +#include 
>>>>  #include 
>>>>  #include 
>>>>  #include 
>>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
>>>> *vcpu, u64 data,
>>>>
>>>>pmc->

Re: [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
> which is mapped to PMEVTYPERn or PMCCFILTR.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When writing to these registers, create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 154 
> +-
>  1 file changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e043224..c52ff15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> + u64 pmcr, val;
> +
> + pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> + val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> + if (idx >= val && idx != ARMV8_CYCLE_IDX)
> + return false;
> +
> + return true;
> +}
> +
> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p,
> +const struct sys_reg_desc *r)
> +{
> + u64 idx, reg;
> +
> + if (r->CRn == 9) {
> + /* PMXEVTYPER_EL0 */
> + reg = 0;
> + } else {
> + if (!p->is_aarch32) {
> + /* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
> + reg = r->reg;
> + } else {
> + if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
> + reg = PMCCFILTR_EL0;
> + } else {
> + reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);

Shouldn't that be "((r->CRm & 3) << 3) | (r->Op2 & 7)"? Otherwise reg is
always 0.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMINTENSET or PMINTENCLR register.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 29 +
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f216da7..594e53f 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> + if (p->is_write) {
> + if (r->Op2 & 0x1) {
> + /* accessing PMINTENSET_EL1 */
> + vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
> + } else {
> + /* accessing PMINTENCLR_EL1 */
> + vcpu_sys_reg(vcpu, r->reg) &= mask;
> + vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

This looks wrong. The first line doesn't have any effect (you shouldn't
be able to set bits that are not in the mask the first place). I'd
prefer something like:

vcpu_sys_reg(vcpu, r->reg) &= ~(p->regval & mask);

which is symmetrical to the SET operator.

> + }
> + } else {
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  
>   /* PMINTENSET_EL1 */
>   { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
> -   trap_raz_wi },
> +   access_pmintenset, reset_unknown, PMINTENSET_EL1 },
>   /* PMINTENCLR_EL1 */
>   { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
> -   trap_raz_wi },
> +   access_pmintenset, NULL, PMINTENSET_EL1 },
>  
>   /* MAIR_EL1 */
>   { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
> @@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
>  
>   { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>   { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> 

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
> is mapped to PMEVCNTRn.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When reading these registers, return the sum of register value and the
> value perf event counts.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 136 
> --
>  1 file changed, 132 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c52ff15..dc6bb26 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -566,6 +566,55 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
> +   struct sys_reg_params *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 idx, reg, val;
> +
> + if (!p->is_aarch32) {
> + if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
> + /* PMXEVCNTR_EL0 */
> + reg = 0;
> + else
> + /* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
> + reg = r->reg;
> + } else {
> + if (r->CRn == 9 && r->CRm == 13) {
> + reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
> + } else {
> + reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);

Same bug as the previous patch.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMCNTENSET or PMCNTENCLR register.
> 
> When writing to PMCNTENSET, call perf_event_enable to enable the perf
> event. When writing to PMCNTENCLR, call perf_event_disable to disable
> the perf event.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 41 +++
>  include/kvm/arm_pmu.h |  4 
>  virt/kvm/arm/pmu.c| 55 
> +++
>  3 files changed, 96 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index dc6bb26..f216da7 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>   return true;
>  }
>  
> +static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
> +{
> + u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
> +
> + val &= ARMV8_PMCR_N_MASK;
> + return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
> +}
> +
> +static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 val, mask;
> +
> + mask = kvm_pmu_valid_counter_mask(vcpu);
> + if (p->is_write) {
> + val = p->regval & mask;
> + if (r->Op2 & 0x1) {
> + /* accessing PMCNTENSET_EL0 */
> + vcpu_sys_reg(vcpu, r->reg) |= val;
> + kvm_pmu_enable_counter(vcpu, val);
> + } else {
> + /* accessing PMCNTENCLR_EL0 */
> + vcpu_sys_reg(vcpu, r->reg) &= mask;
> + vcpu_sys_reg(vcpu, r->reg) &= ~val;
> + kvm_pmu_disable_counter(vcpu, val);
> + }
> + } else {
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmcr, reset_pmcr, PMCR_EL0, },
>   /* PMCNTENSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
> -   trap_raz_wi },
> +   access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
>   /* PMCNTENCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
> -   trap_raz_wi },
> +   access_pmcntenset, NULL, PMCNTENSET_EL0 },
>   /* PMOVSCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> trap_raz_wi },
> @@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>  
>   /* PMU */
>   { Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 14bedb0..43c4117 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -36,6 +36,8 @@ struct kvm_pmu {
>  };
>  
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx);
>  #else
> @@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx)
>  {
>   return 0;
>  }
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index b107fb8..94bff0e 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, 
> struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_enable_counter - enable selected PMU counter
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMCNTENSET register
> + *
> + * Call perf_event_enable to start 

Re: [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add access handler which emulates writing and reading PMSWINC
> register and add support for creating software increment event.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 14 +-
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c| 32 
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index d1926c4..f09e500 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +const struct sys_reg_desc *r)
> +{
> + if (p->is_write) {
> + kvm_pmu_software_increment(vcpu, p->regval);

Shouldn't you filter this with valid counter mask?

> + return true;
> + } else {
> + return read_zero(vcpu, p);

Mark just mentioned to me that reading from this register is UNDEFINED.
Which means you should generate an exception into the guest by calling
kvm_inject_undefined() for that vcpu.

> + }
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmovsset, NULL, PMOVSSET_EL0 },
>   /* PMSWINC_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> -   trap_raz_wi },
> +   access_pmswinc, reset_unknown, PMSWINC_EL0 },
>   /* PMSELR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
> access_pmselr, reset_unknown, PMSELR_EL0 },
> @@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 93aea6a..f5888eb 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx);
>  #else
> @@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx)
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 861471d..01af727 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
>  }
>  
>  /**
> + * kvm_pmu_software_increment - do software increment
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMSWINC register
> + */
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
> +{
> + int i;
> + u64 type, enable, reg;
> +
> + if (val == 0)
> + return;
> +
> + for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
> + if (!((val >> i) & 0x1))

Same comment as for the other patches.

> + continue;
> + type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +& ARMV8_EVTYPE_EVENT;
> + enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> + if ((type == 0) && ((enable >> i) & 0x1)) {
> + vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
> + reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
> + if ((reg & 0x) == 0)
> + kvm_pmu_overflow_set(vcpu, BIT(i));

The increment handling is not very nice, as you end-up with stuff in the
upper 

Re: [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
> which is mapped to PMEVTYPERn or PMCCFILTR.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When writing to these registers, create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 154 
> +-
>  1 file changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e043224..c52ff15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> + u64 pmcr, val;
> +
> + pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> + val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> + if (idx >= val && idx != ARMV8_CYCLE_IDX)
> + return false;
> +
> + return true;
> +}
> +
> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p,
> +const struct sys_reg_desc *r)
> +{
> + u64 idx, reg;
> +
> + if (r->CRn == 9) {
> + /* PMXEVTYPER_EL0 */
> + reg = 0;
> + } else {
> + if (!p->is_aarch32) {
> + /* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
> + reg = r->reg;
> + } else {
> + if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
> + reg = PMCCFILTR_EL0;
> + } else {
> + reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
> + reg += PMEVTYPER0_EL0;
> + }
> + }
> + }
> +
> + switch (reg) {
> + case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
> + idx = reg - PMEVTYPER0_EL0;
> + break;
> + case PMCCFILTR_EL0:
> + idx = ARMV8_CYCLE_IDX;
> + break;
> + default:
> + /* PMXEVTYPER_EL0 */
> + idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
> + if (!pmu_counter_idx_valid(vcpu, idx))
> + return true;

Shouldn't you check the validity of the index in the first case as well?

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMOVSSET or PMOVSCLR register.
> 
> When writing non-zero value to PMOVSSET, pend PMU interrupt.

This comment doesn't match the code anymore

> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 28 +---
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c| 20 
>  3 files changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 594e53f..d1926c4 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> + const struct sys_reg_desc *r)
> +{
> + u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> + if (p->is_write) {
> + if (r->CRm & 0x2) {
> + /* accessing PMOVSSET_EL0 */
> + kvm_pmu_overflow_set(vcpu, p->regval & mask);
> + } else {
> + /* accessing PMOVSCLR_EL0 */
> + vcpu_sys_reg(vcpu, r->reg) &= mask;
> + vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

Same as the previous patch.

> + }
> + } else {
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmcntenset, NULL, PMCNTENSET_EL0 },
>   /* PMOVSCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> -   trap_raz_wi },
> +   access_pmovsset, NULL, PMOVSSET_EL0 },
>   /* PMSWINC_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> trap_raz_wi },
> @@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> trap_raz_wi },
>   /* PMOVSSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
> -   trap_raz_wi },
> +   access_pmovsset, reset_unknown, PMOVSSET_EL0 },
>  
>   /* TPIDR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b010),
> @@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> @@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
>  
>   { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>   { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 43c4117..93aea6a 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -38,6 +38,7 @@ struct kvm_pmu {
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx);
>  #else
> @@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx)
>  }
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 94bff0e..861471d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -130,6 

Re: [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add access handler which gets host value of PMCEID0 or PMCEID1 when
> guest access these registers. Writing action to PMCEID0 or PMCEID1 is
> ignored.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 26 ++
>  1 file changed, 22 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c21f91b..e043224 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -486,6 +486,24 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 pmceid;
> +
> + if (p->is_write)
> + return write_to_read_only(vcpu, p);

This register in UNDEFINED in that case. You should call
kvm_inject_undefined() for that vcpu and return.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
> 
> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
> accessed from EL0. Add some check helpers to handle the access from EL0.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 124 
> --
>  1 file changed, 119 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b2ccc25..bad3dfd 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
> struct sys_reg_desc *r)
>   vcpu_sys_reg(vcpu, r->reg) = val;
>  }
>  
> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x1) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x3) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu 
> *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x5) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu 
> *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x9) || vcpu_mode_priv(vcpu));
> +}

Please add #defines for the PMUSERNR_EL0 bits.

> +
>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>   const struct sys_reg_desc *r)
>  {
>   u64 val;
> + bool unaccessible = pmu_access_el0_disabled(vcpu);
>  
>   if (p->is_write) {
> + if (unaccessible)
> + return ignore_write(vcpu, p);
> +

This is not how this is supposed to work. If EL0 is denied access to the
PMU, you must inject an exception into EL1 for it to handle the fault.
The code should reflect the flow described at D5.11.2 in the ARM ARM.

This whole patch needs to be revisited, I'm afraid.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> When calling perf_event_create_kernel_counter to create perf_event,
> assign a overflow handler. Then when the perf event overflows, set the
> corresponding bit of guest PMOVSSET register. If this counter is enabled
> and its interrupt is enabled as well, kick the vcpu to sync the
> interrupt.
> 
> On VM entry, if there is counter overflowed, inject the interrupt with
> the level set to 1. Otherwise, inject the interrupt with the level set
> to 0.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm/kvm/arm.c|  2 ++
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c| 54 
> ++-
>  3 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index e06fd29..cd696ef 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -28,6 +28,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #define CREATE_TRACE_POINTS
>  #include "trace.h"
> @@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct 
> kvm_run *run)
>* non-preemptible context.
>*/
>   preempt_disable();
> + kvm_pmu_flush_hwstate(vcpu);
>   kvm_timer_flush_hwstate(vcpu);
>   kvm_vgic_flush_hwstate(vcpu);
>  
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 25b5f98..732ccaf 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -35,6 +35,7 @@ struct kvm_pmu {
>   struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
>  };
>  
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
> @@ -47,6 +48,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
>  struct kvm_pmu {
>  };
>  
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
>   return 0;
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index e664721..eff5b19 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -21,6 +21,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  /**
>   * kvm_pmu_get_counter_value - get PMU counter value
> @@ -75,6 +76,56 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, 
> struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_flush_hwstate - flush pmu state to cpu
> + * @vcpu: The vcpu pointer
> + *
> + * Inject virtual PMU IRQ if IRQ is pending for this cpu.
> + */
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> + struct kvm_pmu *pmu = >arch.pmu;
> + u64 overflow;
> +
> + if (pmu->irq_num == -1)
> + return;
> +
> + if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
> + return;
> +
> + overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
> +& vcpu_sys_reg(vcpu, PMINTENSET_EL1)
> +& vcpu_sys_reg(vcpu, PMOVSSET_EL0);

You already have something similar to deal with enabling the overflow
interrupt. You may want to have a common helper.

> +
> + kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
> + overflow ? 1 : 0);

nit: can also be written as !!overflow.

> +}
> +
> +static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
> +{
> + struct kvm_pmu *pmu;
> + struct kvm_vcpu_arch *vcpu_arch;
> +
> + pmc -= pmc->idx;
> + pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
> + vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
> + return container_of(vcpu_arch, struct kvm_vcpu, arch);
> +}
> +
> +/**
> + * When perf event overflows, call kvm_pmu_overflow_set to set overflow 
> status.
> + */
> +static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
> +   struct perf_sample_data *data,
> +   struct pt_regs *regs)
> +{
> + struct kvm_pmc *pmc = perf_event->overflow_handler_context;
> + struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
> + int idx = pmc->idx;
> +
> + kvm_pmu_overflow_set(vcpu, BIT(idx));
> +}
> +
> +/**
>   * kvm_pmu_enable_counter - enable selected PMU counter
>   * @vcpu: The vcpu pointer
>   * @val: the value guest writes to PMCNTENSET register
> @@ -258,7 +309,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
> *vcpu, u64 data,
>   /* The initial sample period (overflow count) of an event. */
>   attr.sample_period = (-counter) & pmc->bitmask;
>  
> - event = perf_event_create_kernel_counter(, -1, current, NULL, pmc);
> + event = perf_event_create_kernel_counter(, -1, current,
> +  kvm_pmu_perf_overflow, pmc);
>   if (IS_ERR(event)) {
>   

Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> the kvm_device_ops for it.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
>  arch/arm64/include/uapi/asm/kvm.h |   3 +
>  include/linux/kvm_host.h  |   1 +
>  include/uapi/linux/kvm.h  |   2 +
>  virt/kvm/arm/pmu.c| 115 
> ++
>  virt/kvm/kvm_main.c   |   4 +
>  6 files changed, 141 insertions(+)
>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> 
> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
> b/Documentation/virtual/kvm/devices/arm-pmu.txt
> new file mode 100644
> index 000..5121f1f
> --- /dev/null
> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> @@ -0,0 +1,16 @@
> +ARM Virtual Performance Monitor Unit (vPMU)
> +===
> +
> +Device types supported:
> +  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
> +
> +Instantiate one PMU instance for per VCPU through this API.
> +
> +Groups:
> +  KVM_DEV_ARM_PMU_GRP_IRQ
> +  Attributes:
> +A value describing the interrupt number of PMU overflow interrupt. This
> +interrupt should be a PPI.
> +
> +  Errors:
> +-EINVAL: Value set is out of the expected range (from 16 to 31)
> diff --git a/arch/arm64/include/uapi/asm/kvm.h 
> b/arch/arm64/include/uapi/asm/kvm.h
> index 2d4ca4b..568afa2 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL4
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT 0
>  
> +/* Device Control API: ARM PMU */
> +#define KVM_DEV_ARM_PMU_GRP_IRQ  0
> +
>  /* KVM_IRQ_LINE irq field index values */
>  #define KVM_ARM_IRQ_TYPE_SHIFT   24
>  #define KVM_ARM_IRQ_TYPE_MASK0xff
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index c923350..608dea6 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>  extern struct kvm_device_ops kvm_xics_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>  
>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>  
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 03f3618..4ba6fdd 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>  #define KVM_DEV_TYPE_FLICKVM_DEV_TYPE_FLIC
>   KVM_DEV_TYPE_ARM_VGIC_V3,
>  #define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
> + KVM_DEV_TYPE_ARM_PMU_V3,
> +#define  KVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
>   KVM_DEV_TYPE_MAX,
>  };
>  
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index d113ee4..1965d0d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -19,6 +19,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
> *vcpu, u64 data,
>  
>   pmc->perf_event = event;
>  }
> +
> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> +{
> + return vcpu->arch.pmu.irq_num != -1;
> +}
> +
> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> +{
> + int j;
> + struct kvm_vcpu *vcpu;
> +
> + kvm_for_each_vcpu(j, vcpu, kvm) {
> + struct kvm_pmu *pmu = >arch.pmu;
> +
> + if (!is_set) {
> + if (!kvm_arm_pmu_initialized(vcpu))
> + return -EBUSY;

Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
anyway. Actually, why would you return an error in this case?

> +
> + *irq = pmu->irq_num;
> + break;
> + }
> +
> + if (kvm_arm_pmu_initialized(vcpu))
> + return -EBUSY;
> +
> + kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
> + pmu->irq_num = *irq;
> + }
> +
> + return 0;
> +}
> +
> +static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
> +{
> + int i;
> + struct kvm_vcpu *vcpu;
> + struct kvm *kvm = dev->kvm;
> +
> + kvm_for_each_vcpu(i, vcpu, kvm) {
> + struct kvm_pmu *pmu = >arch.pmu;
> +
> + memset(pmu, 0, sizeof(*pmu));
> + kvm_pmu_vcpu_reset(vcpu);
> + pmu->irq_num = -1;
> + }
> +
> + return 0;
> +}
> +
> +static void kvm_arm_pmu_destroy(struct kvm_device *dev)
> +{
> + kfree(dev);
> +}
> +
> +static int kvm_arm_pmu_set_attr(struct 

Re: [PATCH v7 00/19] KVM: ARM64: Add guest PMU support

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> This patchset adds guest PMU support for KVM on ARM64. It takes
> trap-and-emulate approach. When guest wants to monitor one event, it
> will be trapped by KVM and KVM will call perf_event API to create a perf
> event and call relevant perf_event APIs to get the count value of event.
> 
> Use perf to test this patchset in guest. When using "perf list", it
> shows the list of the hardware events and hardware cache events perf
> supports. Then use "perf stat -e EVENT" to monitor some event. For
> example, use "perf stat -e cycles" to count cpu cycles and
> "perf stat -e cache-misses" to count cache misses.
> 
> Below are the outputs of "perf stat -r 5 sleep 5" when running in host
> and guest.
> 
> Host:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>   0.549456  task-clock (msec) #0.000 CPUs utilized
> ( +-  5.68% )
>  1  context-switches  #0.002 M/sec
>  0  cpu-migrations#0.000 K/sec
> 48  page-faults   #0.088 M/sec
> ( +-  1.40% )
>1146243  cycles#2.086 GHz  
> ( +-  5.71% )
>  stalled-cycles-frontend
>  stalled-cycles-backend
> 627195  instructions  #0.55  insns per cycle  
> ( +- 15.65% )
>  branches
>   9826  branch-misses #   17.883 M/sec
> ( +-  1.10% )
> 
>5.000875516 seconds time elapsed   
>( +-  0.00% )
> 
> 
> Guest:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>   0.640712  task-clock (msec) #0.000 CPUs utilized
> ( +-  0.41% )
>  1  context-switches  #0.002 M/sec
>  0  cpu-migrations#0.000 K/sec
> 50  page-faults   #0.077 M/sec
> ( +-  1.37% )
>1320428  cycles#2.061 GHz  
> ( +-  0.29% )
>  stalled-cycles-frontend
>  stalled-cycles-backend
> 642373  instructions  #0.49  insns per cycle  
> ( +-  0.46% )
>  branches
>  10399  branch-misses #   16.230 M/sec
> ( +-  1.57% )
> 
>5.001181020 seconds time elapsed   
>( +-  0.00% )
> 
> 
> Have a cycle counter read test like below in guest and host:
> 
> static void test(void)
> {
>   unsigned long count, count1, count2;
>   count1 = read_cycles();
>   count++;
>   count2 = read_cycles();
> }
> 
> Host:
> count1: 3049567104
> count2: 3049567247
> delta: 143
> 
> Guest:
> count1: 5281420890
> count2: 5281421068
> delta: 178
> 
> The gap between guest and host is very small. One reason for this I
> think is that it doesn't count the cycles in EL2 and host since we add
> exclude_hv = 1. So the cycles spent to store/restore registers which
> happens at EL2 are not included.
> 
> This patchset can be fetched from [1] and the relevant QEMU version for
> test can be fetched from [2].
> 
> The results of 'perf test' can be found from [3][4].
> The results of perf_event_tests test suite can be found from [5][6].
> 
> Also, I have tested "perf top" in two VMs and host at the same time. It
> works well.

So while things are steadily improving, there is still more things to do
(and the more I review the code, the more I find things, which worries me).

The biggest issue at the moment is the handling of accesses at EL0,
which should be forwarded to EL1 instead of ignoring the access when
denied. There is also the UNDEFINED accesses (which are pretty easy to
solve), and a couple of straightforward bugs and other nits that should
be easy to fix.

If you can fix the above and that the result looks good, I'll try to put
it into -next. But at the moment, it looks like we're not really on
track to make it into 4.5.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] KVM: arm/arm64: vgic: Fix kvm_vgic_map_is_active's dist check

2015-12-11 Thread Marc Zyngier
On 10/12/15 21:46, Christoffer Dall wrote:
> External inputs to the vgic from time to time need to poke into the
> state of a virtual interrupt, the prime example is the architected timer
> code.
> 
> Since the IRQ's active state can be represented in two places; the LR or
> the distributor, we first loop over the LRs but if not active in the LRs
> we just return if *any* IRQ is active on the VCPU in question.
> 
> This is of course bogus, as we should check if the specific IRQ in
> quesiton is active on the distributor instead.
> 
> Reported-by: Eric Auger <eric.au...@linaro.org>
> Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
> ---
>  virt/kvm/arm/vgic.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
> index 65461f8..7a2f449 100644
> --- a/virt/kvm/arm/vgic.c
> +++ b/virt/kvm/arm/vgic.c
> @@ -1114,7 +1114,7 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, 
> struct irq_phys_map *map)
>   return true;
>   }
>  
> - return dist_active_irq(vcpu);
> + return vgic_irq_is_active(vcpu, map->virt_irq);
>  }
>  
>  /*
> 

Damn!

Acked-by: Marc Zyngier <marc.zyng...@arm.com>

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 07/22] arm64: KVM: Implement system register save/restore

2015-12-11 Thread Marc Zyngier
Hi Mario,

On 11/12/15 03:24, Mario Smarduch wrote:
> Hi Marc,
> 
> On 12/7/2015 2:53 AM, Marc Zyngier wrote:
>> Implement the system register save/restore as a direct translation of
>> the assembly code version.
>>
>> Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
>> Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
>> ---
>>  arch/arm64/kvm/hyp/Makefile|  1 +
>>  arch/arm64/kvm/hyp/hyp.h   |  3 ++
>>  arch/arm64/kvm/hyp/sysreg-sr.c | 90 
>> ++
>>  3 files changed, 94 insertions(+)
>>  create mode 100644 arch/arm64/kvm/hyp/sysreg-sr.c
>>
>> diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
>> index 455dc0a..ec94200 100644
>> --- a/arch/arm64/kvm/hyp/Makefile
>> +++ b/arch/arm64/kvm/hyp/Makefile
>> @@ -5,3 +5,4 @@
>>  obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
>>  obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
>>  obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
>> +obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
>> diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
>> index f213e46..778d56d 100644
>> --- a/arch/arm64/kvm/hyp/hyp.h
>> +++ b/arch/arm64/kvm/hyp/hyp.h
>> @@ -38,5 +38,8 @@ void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
>>  void __timer_save_state(struct kvm_vcpu *vcpu);
>>  void __timer_restore_state(struct kvm_vcpu *vcpu);
>>  
>> +void __sysreg_save_state(struct kvm_cpu_context *ctxt);
>> +void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
>> +
>>  #endif /* __ARM64_KVM_HYP_H__ */
>>  
>> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
>> new file mode 100644
>> index 000..add8fcb
>> --- /dev/null
>> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
>> @@ -0,0 +1,90 @@
>> +/*
>> + * Copyright (C) 2012-2015 - ARM Ltd
>> + * Author: Marc Zyngier <marc.zyng...@arm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include 
>> +#include 
>> +
>> +#include 
>> +
>> +#include "hyp.h"
>> +
> 
> I looked closer on some other ways to get better performance out of
> the compiler. This code sequence performs about 35% faster for 
> __sysreg_save_state(..) for 5000 exits you save about 500mS or 100nS
> per exit. This is on Juno.

35% faster? Really? That's pretty crazy. Was that on the A57 or the A53?

> 
> register int volatile count asm("r2") = 0;

Does this even work on arm64? We don't have an "r2" register...

> 
> do {
> 
> } while(count);
> 
> I didn't test the restore function (ran out of time) but I suspect it should 
> be
> the same. The assembler pretty much uses all the GPRs, (a little too many, 
> using
> stp to push 4 pairs on the stack and restore) looking at the assembler it all
> should execute out of order.

Are you talking about the original implementation here? or the generated
code out of the compiler? The original implementation didn't push
anything on the stack (apart from the prologue, but we have the same
thing in the C implementation).

Looking at the compiler output, we have a bunch of mrs/str, one after
the other - pretty basic. Maybe that gives the CPU some "breathing"
time, but I have no idea if that's more or less efficient.

But the main thing is that we can now rely on the compiler to generate
something that is more or less optimized for a given platform if there
is such a requirement. We go from something that was cast in stone to
something that has some degree of flexibility.

> 
> FWIW I gave this a try since compilers like to optimize loops. I used
> 'cntpct_el0' counter register to measure the intervals.

It'd be nice to have a measure in terms of cycle, but that's a good
first approximation.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 10/21] KVM: ARM64: Add access handler for PMEVCNTRn and PMCCNTR register

2015-12-10 Thread Marc Zyngier
Hi Shannon,

On 10/12/15 11:36, Shannon Zhao wrote:
> Hi Marc,
> 
> On 2015/12/9 0:30, Marc Zyngier wrote:
>> On 08/12/15 12:47, Shannon Zhao wrote:
>>>> From: Shannon Zhao <shannon.z...@linaro.org>
>>>>
>>>> Since the reset value of PMEVCNTRn or PMCCNTR is UNKNOWN, use
>>>> reset_unknown for its reset handler. Add access handler which emulates
>>>> writing and reading PMEVCNTRn or PMCCNTR register. When reading
>>>> PMEVCNTRn or PMCCNTR, call perf_event_read_value to get the count value
>>>> of the perf event.
>>>>
>>>> Signed-off-by: Shannon Zhao <shannon.z...@linaro.org>
>>>> ---
>>>>  arch/arm64/kvm/sys_regs.c | 107 
>>>> +-
>>>>  1 file changed, 105 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>>>> index c116a1b..f7a73b5 100644
>>>> --- a/arch/arm64/kvm/sys_regs.c
>>>> +++ b/arch/arm64/kvm/sys_regs.c
>>>> @@ -525,6 +525,12 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>>>>  
>>>>if (p->is_write) {
>>>>switch (r->reg) {
>>>> +  case PMEVCNTR0_EL0 ... PMCCNTR_EL0: {
>> Same problem as previously mentioned.
>>
>>>> +  val = kvm_pmu_get_counter_value(vcpu,
>>>> +  r->reg - PMEVCNTR0_EL0);
>>>> +  vcpu_sys_reg(vcpu, r->reg) += (s64)p->regval - val;
>>>> +  break;
>>>> +  }
> 
> If I use a handler to handle these accesses to PMEVCNTRn and PMCCNTR
> like below. It converts the register offset c14_PMEVCNTRn and c9_PMCCNTR
> to PMEVCNTRn_EL0 and PMCCNTR_EL0, uniformly uses vcpu_sys_reg and
> doesn't need to take care the big endian. What do you think about this?
> 
> static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>   struct sys_reg_params *p,
>   const struct sys_reg_desc *r)
> {
> u64 idx, reg, val;
> 
> if (p->is_aarch32)
> reg = r->reg / 2;

I'd prefer it if you actually decoded the reg itself. Something like:

if (p->is_aarch32) {
if (r->CRn == 9 && r->CRm == 13)
reg = (r->Op2 & 1) ? 0 : PMCCNTR_EL0;
if (r->CRn == 14 && (r->CRm & 0xc) == 8) {
reg = ((r->CRm & 3) << 2) & (r->Op2 & 7);
reg += PMEVCNTR0_EL0;
} else {
BUG();
}
} else {

}

And then you can get rid of the c14_PMVCNTR* and c9_PMCCNTR macros.
The only slightly ugly thing is this 0 value to represent PMXEVTYPER,
but that's what we already have with your "default" clause below.

> else
> reg = r->reg;
> 
> switch (reg) {
> case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0: {
> idx = reg - PMEVCNTR0_EL0;
> break;
> }
> case PMCCNTR_EL0: {
> idx = ARMV8_CYCLE_IDX;
> break;
> }
> default:
> idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
> if (!pmu_counter_idx_valid(vcpu, idx))
> return true;
> reg = (idx == ARMV8_CYCLE_IDX) ? PMCCNTR_EL0 :
> PMEVCNTR0_EL0 + idx;
> break;
> }
> 
> val = kvm_pmu_get_counter_value(vcpu, idx);
> if (p->is_write)
> vcpu_sys_reg(vcpu, reg) = (s64)p->regval - val;

Maybe I don't have my head screwed in the right way, but as long as
we're only using u64 quantities, why do we need this s64 cast?

> else
> p->regval = val;
> 
> return true;
> }

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 07/21] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function

2015-12-09 Thread Marc Zyngier
On Wed, 9 Dec 2015 15:38:09 +0800
Shannon Zhao <zhaoshengl...@huawei.com> wrote:

> 
> 
> On 2015/12/8 23:43, Marc Zyngier wrote:
> > On 08/12/15 12:47, Shannon Zhao wrote:
> >> From: Shannon Zhao <shannon.z...@linaro.org>
> >> +/**
> >> + * kvm_pmu_get_counter_value - get PMU counter value
> >> + * @vcpu: The vcpu pointer
> >> + * @select_idx: The counter index
> >> + */
> >> +u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx)
> >> +{
> >> +  u64 counter, enabled, running;
> >> +  struct kvm_pmu *pmu = >arch.pmu;
> >> +  struct kvm_pmc *pmc = >pmc[select_idx];
> >> +
> >> +  if (!vcpu_mode_is_32bit(vcpu))
> >> +  counter = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + select_idx);
> >> +  else
> >> +  counter = vcpu_cp15(vcpu, c14_PMEVCNTR0 + select_idx);
> >> +
> >> +  if (pmc->perf_event)
> >> +  counter += perf_event_read_value(pmc->perf_event, ,
> >> +   );
> >> +
> >> +  return counter & pmc->bitmask;
> > 
> > This one confused me for a while. Is it the case that you return
> > whatever is in the vcpu view of the counter, plus anything that perf
> > itself has counted? If so, I'd appreciate a comment here...
> > 
> Yes, the real counter value is the current counter value plus the value
> perf event counts. I'll add a comment.
> 
> >> +}
> >> +
> >> +static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u32 
> >> select_idx)
> >> +{
> >> +  if (!vcpu_mode_is_32bit(vcpu))
> >> +  return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &
> >> + (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) >> select_idx);
> > 
> > This looks wrong. Shouldn't it be:
> > 
> > return ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &&
> > (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & (1 << select_idx)));
> > 
> >> +  else
> >> +  return (vcpu_sys_reg(vcpu, c9_PMCR) & ARMV8_PMCR_E) &
> >> + (vcpu_sys_reg(vcpu, c9_PMCNTENSET) >> select_idx);
> >> +}
> > 
> > Also, I don't really see why we need to check the 32bit version, which
> > has the exact same content.
> > 
> >> +
> >> +static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
> >> +{
> >> +  struct kvm_pmu *pmu;
> >> +  struct kvm_vcpu_arch *vcpu_arch;
> >> +
> >> +  pmc -= pmc->idx;
> >> +  pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
> >> +  vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
> >> +  return container_of(vcpu_arch, struct kvm_vcpu, arch);
> >> +}
> >> +
> >> +/**
> >> + * kvm_pmu_stop_counter - stop PMU counter
> >> + * @pmc: The PMU counter pointer
> >> + *
> >> + * If this counter has been configured to monitor some event, release it 
> >> here.
> >> + */
> >> +static void kvm_pmu_stop_counter(struct kvm_pmc *pmc)
> >> +{
> >> +  struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
> >> +  u64 counter;
> >> +
> >> +  if (pmc->perf_event) {
> >> +  counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
> >> +  if (!vcpu_mode_is_32bit(vcpu))
> >> +  vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + pmc->idx) = counter;
> >> +  else
> >> +  vcpu_cp15(vcpu, c14_PMEVCNTR0 + pmc->idx) = counter;
> > 
> > Same thing - we don't need to make a difference between 32 and 64bit.
> > 
> So it's fine to drop all the vcpu_mode_is_32bit(vcpu) check of this
> series? The only one we should take care is the PMCCNTR, right?

Yes, mostly. As long as you only reason on the 64bit register set,
you're pretty safe, and that in turn solves all kind of ugly endianness
issues.

> >> +
> >> +  perf_event_release_kernel(pmc->perf_event);
> >> +  pmc->perf_event = NULL;
> >> +  }
> >> +}
> >> +
> >> +/**
> >> + * kvm_pmu_set_counter_event_type - set selected counter to monitor some 
> >> event
> >> + * @vcpu: The vcpu pointer
> >> + * @data: The data guest writes to PMXEVTYPER_EL0
> >> + * @select_idx: The number of selected counter
> >> + *
> >> + * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to 
> >> count an
> >> + * event with given

Re: [PATCH v6 12/21] KVM: ARM64: Add reset and access handlers for PMCNTENSET and PMCNTENCLR register

2015-12-09 Thread Marc Zyngier
On Wed, 9 Dec 2015 16:35:58 +0800
Shannon Zhao <zhaoshengl...@huawei.com> wrote:

> 
> 
> On 2015/12/9 0:42, Marc Zyngier wrote:
> >> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u32 val, bool 
> >> all_enable)
> >> > +{
> >> > +int i;
> >> > +struct kvm_pmu *pmu = >arch.pmu;
> >> > +struct kvm_pmc *pmc;
> >> > +
> >> > +if (!all_enable)
> >> > +return;
> > You have the vcpu. Can you move the check for PMCR_EL0.E here instead of
> > having it in both of the callers?
> > 
> But it still needs to check PMCR_EL0.E in kvm_pmu_handle_pmcr(). When
> PMCR_EL0.E == 1, it calls kvm_pmu_enable_counter(), otherwise it calls
> kvm_pmu_disable_counter(). So as it checks already, just pass the result
> as a parameter.

I've seen that, but it makes the code look ugly. At any rate, you might
as well not call enable_counter if PMCR.E==0. But splitting the lookup
of the bit and the test like you do is not nice at all. Making it
self-contained looks a lot better, and you don't have to think about
the caller.

> >> > +
> >> > +for_each_set_bit(i, (const unsigned long *), 
> >> > ARMV8_MAX_COUNTERS) {
> > Nonononono... If you must have to use a long, use a long. Don't cast it
> > to a different type (hint: big endian).
> > 
> >> > +pmc = >pmc[i];
> >> > +if (pmc->perf_event) {
> >> > +perf_event_enable(pmc->perf_event);
> >> > +if (pmc->perf_event->state != 
> >> > PERF_EVENT_STATE_ACTIVE)
> >> > +kvm_debug("fail to enable perf 
> >> > event\n");
> >> > +}
> >> > +}
> >> > +}
> >> > +
> >> > +/**
> >> > + * kvm_pmu_disable_counter - disable selected PMU counter
> >> > + * @vcpu: The vcpu pointer
> >> > + * @val: the value guest writes to PMCNTENCLR register
> >> > + *
> >> > + * Call perf_event_disable to stop counting the perf event
> >> > + */
> >> > +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u32 val)
> >> > +{
> >> > +int i;
> >> > +struct kvm_pmu *pmu = >arch.pmu;
> >> > +struct kvm_pmc *pmc;
> >> > +
> > Why are enable and disable asymmetric (handling of PMCR.E)?
> > 
> To enable a counter, it needs both the PMCR_EL0.E and the corresponding
> bit of PMCNTENSET_EL0 set to 1. But to disable a counter, it only needs
> one of them and when PMCR_EL0.E == 0, it disables all the counters.

OK.

M.
-- 
Jazz is not dead. It just smells funny.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 15/21] KVM: ARM64: Add reset and access handlers for PMUSERENR register

2015-12-09 Thread Marc Zyngier
On Wed, 9 Dec 2015 17:18:02 +0800
Shannon Zhao <zhaoshengl...@huawei.com> wrote:

> 
> 
> On 2015/12/9 1:03, Marc Zyngier wrote:
> > On 08/12/15 12:47, Shannon Zhao wrote:
> >> > From: Shannon Zhao <shannon.z...@linaro.org>
> >> > 
> >> > The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
> >> > 
> >> > Signed-off-by: Shannon Zhao <shannon.z...@linaro.org>
> >> > ---
> >> >  arch/arm64/kvm/sys_regs.c | 5 +++--
> >> >  1 file changed, 3 insertions(+), 2 deletions(-)
> >> > 
> >> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> >> > index c830fde..80b66c0 100644
> >> > --- a/arch/arm64/kvm/sys_regs.c
> >> > +++ b/arch/arm64/kvm/sys_regs.c
> >> > @@ -880,7 +880,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> >> >access_pmu_pmxevcntr },
> >> >  /* PMUSERENR_EL0 */
> >> >  { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
> >> > -  trap_raz_wi },
> >> > +  access_pmu_regs, reset_unknown, PMUSERENR_EL0 },
> > So while the 64bit view of the register resets as unknown, a CPU
> > resetting in 32bit mode resets as 0. I suggest you reset it as zero, and
> > document that choice. You may have to revisit all the other registers
> > that do reset as unknown for 64bit as well.
> > 
> Sure.
> 
> BTW, here I didn't handle the bits of PMUSERENR which are used to
> permit/forbid accessing some PMU registers from EL0. Does it need to add
> the handler? Is there any way to get the exceptional level of the
> accessing in hypervisor?

Ah, good point, I missed that. Yes, we need to be able to handle that.

To find out, you can use vcpu_mode_priv(), which returns true if the
CPU was in a high privilege mode (EL1 for 64bit, anything higher than
USR on 32bit), and false otherwise. So far, the only user is
arch/arm/kvm/perf.c.

Thanks,

M.
-- 
Without deviation from the norm, progress is not possible.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 05/22] arm64: KVM: Implement vgic-v3 save/restore

2015-12-08 Thread Marc Zyngier
On Mon, 7 Dec 2015 18:14:36 -0800
Mario Smarduch <m.smard...@samsung.com> wrote:

> 
> 
> On 12/7/2015 10:20 AM, Marc Zyngier wrote:
> > On 07/12/15 18:05, Mario Smarduch wrote:
> >>
> >>
> >> On 12/7/2015 9:37 AM, Marc Zyngier wrote:
> [...]
> >>>
> >>
> >> I was thinking something like 'current_lr[VGIC_V3_LR_INDEX(...)]'.
> > 
> > That doesn't change anything, the compiler is perfectly able to 
> > optimize something like this:
> > 
> > [...]
> > ffc0007f31ac:   38624862ldrbw2, [x3,w2,uxtw]
> > ffc0007f31b0:   1063adr x3, ffc0007f31bc 
> > <__vgic_v3_save_state+0x64>
> > ffc0007f31b4:   8b228862add x2, x3, w2, sxtb #2
> > ffc0007f31b8:   d61f0040br  x2
> > ffc0007f31bc:   d53ccde2mrs x2, s3_4_c12_c13_7
> > ffc0007f31c0:   f9001c02str x2, [x0,#56]
> > ffc0007f31c4:   d53ccdc2mrs x2, s3_4_c12_c13_6
> > ffc0007f31c8:   f9002002str x2, [x0,#64]
> > ffc0007f31cc:   d53ccda2mrs x2, s3_4_c12_c13_5
> > ffc0007f31d0:   f9002402str x2, [x0,#72]
> > ffc0007f31d4:   d53ccd82mrs x2, s3_4_c12_c13_4
> > ffc0007f31d8:   f9002802str x2, [x0,#80]
> > ffc0007f31dc:   d53ccd62mrs x2, s3_4_c12_c13_3
> > ffc0007f31e0:   f9002c02str x2, [x0,#88]
> > ffc0007f31e4:   d53ccd42mrs x2, s3_4_c12_c13_2
> > ffc0007f31e8:   f9003002str x2, [x0,#96]
> > ffc0007f31ec:   d53ccd22mrs x2, s3_4_c12_c13_1
> > ffc0007f31f0:   f9003402str x2, [x0,#104]
> > ffc0007f31f4:   d53ccd02mrs x2, s3_4_c12_c13_0
> > ffc0007f31f8:   f9003802str x2, [x0,#112]
> > ffc0007f31fc:   d53ccce2mrs x2, s3_4_c12_c12_7
> > ffc0007f3200:   f9003c02str x2, [x0,#120]
> > ffc0007f3204:   d532mrs x2, s3_4_c12_c12_6
> > ffc0007f3208:   f9004002str x2, [x0,#128]
> > ffc0007f320c:   d53ccca2mrs x2, s3_4_c12_c12_5
> > ffc0007f3210:   f9004402str x2, [x0,#136]
> > ffc0007f3214:   d53ccc82mrs x2, s3_4_c12_c12_4
> > ffc0007f3218:   f9004802str x2, [x0,#144]
> > ffc0007f321c:   d53ccc62mrs x2, s3_4_c12_c12_3
> > ffc0007f3220:   f9004c02str x2, [x0,#152]
> > ffc0007f3224:   d53ccc42mrs x2, s3_4_c12_c12_2
> > ffc0007f3228:   f9005002str x2, [x0,#160]
> > ffc0007f322c:   d53ccc22mrs x2, s3_4_c12_c12_1
> > ffc0007f3230:   f9005402str x2, [x0,#168]
> > ffc0007f3234:   d53ccc02mrs x2, s3_4_c12_c12_0
> > ffc0007f3238:   7100183fcmp w1, #0x6
> > ffc0007f323c:   f9005802str x2, [x0,#176]
> > 
> > As you can see, this is as optimal as it gets, short of being able
> > to find a nice way to use more than one register...
> 
> Interesting, thanks for the dump I'm no expert on pipeline optimizations but 
> I'm
> wondering with these system register accesses can these be executed out of 
> order
> provided you didn't have what I thinks are write after read dependencies?

System-register reads can be executed out of order, that is not a
problem. Even the stores can be executed out of order as the CPU
renames the GP registers (depending on the microarchitecture, of
course).

Now, what I'd *really* like to see is GCC to output something similar
to what we have in the original code, where we use as many registers as
possible to store the data, and output it in one go, possibly using
strp. So far, I haven't found a way to convince the compiler to do so.

> It's only 4 registers here, there are some other longer stretches in 
> subsequent
> patches.
> 
> I minor note here is some white space in this patch.

Ah, thanks for letting me know. I'll chase those.

Thanks,

M.
-- 
Without deviation from the norm, progress is not possible.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v5 03/21] KVM: ARM64: Add offset defines for PMU registers

2015-12-08 Thread Marc Zyngier
On 08/12/15 08:09, Shannon Zhao wrote:
> Hi Marc,
> 
> On 2015/12/7 22:55, Marc Zyngier wrote:
>> On 07/12/15 14:31, Shannon Zhao wrote:
>>>>
>>>>
>>>> On 2015/12/7 22:06, Marc Zyngier wrote:
>>>>>> On 03/12/15 06:11, Shannon Zhao wrote:
>>>>>>>> From: Shannon Zhao <shannon.z...@linaro.org>
>>>>>>>>
>>>>>>>> We are about to trap and emulate acccesses to each PMU register
>>>>>>
>>>>>> s/acccesses/accesses/
>>>>>>
>>>>>>>> individually. This adds the context offsets for the AArch64 PMU
>>>>>>>> registers and their AArch32 counterparts.
>>>>>>>>
>>>>>>>> Signed-off-by: Shannon Zhao <shannon.z...@linaro.org>
>>>>>>>> ---
>>>>>>>>   arch/arm64/include/asm/kvm_asm.h | 55 
>>>>>>>> 
>>>>>>>>   1 file changed, 50 insertions(+), 5 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/arch/arm64/include/asm/kvm_asm.h 
>>>>>>>> b/arch/arm64/include/asm/kvm_asm.h
>>>>>>>> index 5e37710..4f804c1 100644
>>>>>>>> --- a/arch/arm64/include/asm/kvm_asm.h
>>>>>>>> +++ b/arch/arm64/include/asm/kvm_asm.h
>>>>>>>> @@ -48,12 +48,34 @@
>>>>>>>>   #define MDSCR_EL122  /* Monitor Debug System Control 
>>>>>>>> Register */
>>>>>>>>   #define MDCCINT_EL1  23  /* Monitor Debug Comms Channel 
>>>>>>>> Interrupt Enable Reg */
>>>>>>>>
>>>>>>
>>>>>> Coming back to this patch, it gives a clear view of where you have state
>>>>>> duplication.
>>>>>>
>>>>>>>> +/* Performance Monitors Registers */
>>>>>>>> +#define PMCR_EL0  24  /* Control Register */
>>>>>>>> +#define PMOVSSET_EL0  25  /* Overflow Flag Status Set Register */
>>>>>>>> +#define PMOVSCLR_EL0  26  /* Overflow Flag Status Clear Register 
>>>>>>>> */
>>>>>>
>>>>>> This should only be a single state. You don't even have to represent it
>>>>>> in the sysreg array, to be honest.
>>>>>>
> 
> Re-think about this. Since there are different operates to SET/CLR
> registers, maybe it should keep both of them while only storing the
> state in one of them.
> 
> To SET:
>   vcpu_sys_reg(vcpu, r->reg) |= val;
> To CLR:
>   vcpu_sys_reg(vcpu, r->reg) &= ~val;

There is really no point keeping both, because they are two views of the
same state. They perform different action on the same data, so the way
to look at it is to have different functions/methods that modify the
same state.

> Or keep one of them and within the access handler, according to the
> operates encoding value to judge whether it's SET or CLR.

That's indeed the way it should be. You just have to register different
functions in the trap table. You could even move the register outside of
the sys_reg array into the kvm_pmu structure.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 06/22] arm64: KVM: Implement timer save/restore

2015-12-08 Thread Marc Zyngier
On 08/12/15 02:18, Mario Smarduch wrote:
> 
> 
> On 12/7/2015 2:53 AM, Marc Zyngier wrote:
>> Implement the timer save restore as a direct translation of
>> the assembly code version.
>>
>> Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
>> ---
>>  arch/arm64/kvm/hyp/Makefile  |  1 +
>>  arch/arm64/kvm/hyp/hyp.h |  3 ++
>>  arch/arm64/kvm/hyp/timer-sr.c| 72 
>> 
>>  include/clocksource/arm_arch_timer.h |  6 +++
>>  4 files changed, 82 insertions(+)
>>  create mode 100644 arch/arm64/kvm/hyp/timer-sr.c
>>
>> diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
>> index d1e38ce..455dc0a 100644
>> --- a/arch/arm64/kvm/hyp/Makefile
>> +++ b/arch/arm64/kvm/hyp/Makefile
>> @@ -4,3 +4,4 @@
>>  
>>  obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
>>  obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
>> +obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
>> diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
>> index 5759f9f..f213e46 100644
>> --- a/arch/arm64/kvm/hyp/hyp.h
>> +++ b/arch/arm64/kvm/hyp/hyp.h
>> @@ -35,5 +35,8 @@ void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
>>  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
>>  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
>>  
>> +void __timer_save_state(struct kvm_vcpu *vcpu);
>> +void __timer_restore_state(struct kvm_vcpu *vcpu);
>> +
>>  #endif /* __ARM64_KVM_HYP_H__ */
>>  
>> diff --git a/arch/arm64/kvm/hyp/timer-sr.c b/arch/arm64/kvm/hyp/timer-sr.c
>> new file mode 100644
>> index 000..67292c0
>> --- /dev/null
>> +++ b/arch/arm64/kvm/hyp/timer-sr.c
>> @@ -0,0 +1,72 @@
>> +/*
>> + * Copyright (C) 2012-2015 - ARM Ltd
>> + * Author: Marc Zyngier <marc.zyng...@arm.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include 
>> +#include 
>> +#include 
>> +
>> +#include 
>> +
>> +#include "hyp.h"
>> +
>> +/* vcpu is already in the HYP VA space */
>> +void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
>> +{
>> +struct kvm *kvm = kern_hyp_va(vcpu->kvm);
>> +struct arch_timer_cpu *timer = >arch.timer_cpu;
>> +u64 val;
>> +
>> +if (kvm->arch.timer.enabled) {
>> +timer->cntv_ctl = read_sysreg(cntv_ctl_el0);
>> +isb();
> 
> Can you share the subtle insight why is the isb() needed here?
> B2.7.3 mentions changes to system registers only.

This is actually a leftover of some previous code rework in the assembly
version of this code, which has found its way into the new
implementation. Duh.

Thanks for pointing this out.

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 02/21] KVM: ARM64: Define PMU data structure for each vcpu

2015-12-08 Thread Marc Zyngier
On 08/12/15 13:53, Will Deacon wrote:
> On Tue, Dec 08, 2015 at 01:37:14PM +0000, Marc Zyngier wrote:
>> On 08/12/15 12:47, Shannon Zhao wrote:
>>> From: Shannon Zhao <shannon.z...@linaro.org>
>>>
>>> Here we plan to support virtual PMU for guest by full software
>>> emulation, so define some basic structs and functions preparing for
>>> futher steps. Define struct kvm_pmc for performance monitor counter and
>>> struct kvm_pmu for performance monitor unit for each vcpu. According to
>>> ARMv8 spec, the PMU contains at most 32(ARMV8_MAX_COUNTERS) counters.
>>>
>>> Since this only supports ARM64 (or PMUv3), add a separate config symbol
>>> for it.
>>>
>>> Signed-off-by: Shannon Zhao <shannon.z...@linaro.org>
>>> ---
>>>  arch/arm64/include/asm/kvm_host.h |  2 ++
>>>  arch/arm64/kvm/Kconfig|  8 
>>>  include/kvm/arm_pmu.h | 40 
>>> +++
>>>  3 files changed, 50 insertions(+)
>>>  create mode 100644 include/kvm/arm_pmu.h
> 
> [...]
> 
>>> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
>>> index a5272c0..66da9a2 100644
>>> --- a/arch/arm64/kvm/Kconfig
>>> +++ b/arch/arm64/kvm/Kconfig
>>> @@ -36,6 +36,7 @@ config KVM
>>> select HAVE_KVM_EVENTFD
>>> select HAVE_KVM_IRQFD
>>> select KVM_ARM_VGIC_V3
>>> +   select KVM_ARM_PMU
>>
>> What if HW_PERF_EVENTS is not selected? Also, selecting HW_PERF_EVENTS
>> is not enough, and you probably need PERF_EVENTS as well, So this should
>> probably read:
>>
>>  select KVM_ARM_PMU if (HW_PERF_EVENTS && PERF_EVENTS)
> 
> HW_PERF_EVENTS depends on ARM_PMU which in turn depends on PERF_EVENTS.

in which case, let's make it:

select KVM_ARM_PMU if HW_PERF_EVENTS

which should give us the minimal chain. I hate the kernel config
language! ;-)

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 06/21] KVM: ARM64: Add reset and access handlers for PMCEID0 and PMCEID1 register

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add reset handler which gets host value of PMCEID0 or PMCEID1. Since
> write action to PMCEID0 or PMCEID1 is ignored, add a new case for this.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 29 +
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index d81f7ac..1bcb2b7 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -452,6 +452,19 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
> struct sys_reg_desc *r)
>   vcpu_sys_reg(vcpu, r->reg) = val;
>  }
>  
> +static void reset_pmceid(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> +{
> + u64 pmceid;
> +
> + if (r->reg == PMCEID0_EL0)
> + asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
> + else
> + /* PMCEID1_EL0 */
> + asm volatile("mrs %0, pmceid1_el0\n" : "=r" (pmceid));
> +
> + vcpu_sys_reg(vcpu, r->reg) = pmceid;
> +}
> +
>  /* PMU registers accessor. */
>  static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   struct sys_reg_params *p,
> @@ -469,6 +482,9 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   vcpu_sys_reg(vcpu, r->reg) = val;
>   break;
>   }
> + case PMCEID0_EL0:
> + case PMCEID1_EL0:
> + return ignore_write(vcpu, p);
>   default:
>   vcpu_sys_reg(vcpu, r->reg) = p->regval;
>   break;
> @@ -693,10 +709,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmu_regs, reset_unknown, PMSELR_EL0 },
>   /* PMCEID0_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_pmceid, PMCEID0_EL0 },
>   /* PMCEID1_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_pmceid, PMCEID1_EL0 },
>   /* PMCCNTR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
> trap_raz_wi },
> @@ -926,6 +942,9 @@ static bool access_pmu_cp15_regs(struct kvm_vcpu *vcpu,
>   vcpu_cp15(vcpu, r->reg) = val;
>   break;
>   }
> + case c9_PMCEID0:
> + case c9_PMCEID1:
> + return ignore_write(vcpu, p);
>   default:
>   vcpu_cp15(vcpu, r->reg) = p->regval;
>   break;
> @@ -983,8 +1002,10 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmu_cp15_regs,
> NULL, c9_PMSELR },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmu_cp15_regs,
> +   NULL, c9_PMCEID0 },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmu_cp15_regs,
> +   NULL, c9_PMCEID1 },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
> 

That's a lot of infrastructure for something that is essentially a
constant that doesn't need to be stored in the sysreg array.
I suggest you drop the constants for PMCEID{0,1}_EL0 and
c9_PMCEID{0,1}, and turn the code into something like this:

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 251d517..09c38d0 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -453,17 +453,22 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
struct sys_reg_desc *r)
vcpu_sys_reg(vcpu, r->reg) = val;
 }
 
-static void reset_pmceid(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+static bool access_pmceid(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
 {
u64 pmceid;
 
-   if (r->reg == PMCEID0_EL0)
+   if (p->is_write)
+   return ignore_write(vcpu, p);
+
+   if (!(p->Op2 & 1))
asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
else
-   /* PMCEID1_EL0 */
asm volatile("mrs %0, pmceid1_el0\n" : "=r" (pmceid));
 
-   vcpu_sys_reg(vcpu, r->reg) = pmceid;
+   p->regval = pmceid;
+   return true;
 }
 
 static bool pmu_counter_idx_valid(u64 pmcr, u64 idx)
@@ -624,9 +629,6 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
kvm_pmu_handle_pmcr(vcpu, val);
break;
}
-   case PMCEID0_EL0:
-   case PMCEID1_EL0:

Re: [PATCH v6 02/21] KVM: ARM64: Define PMU data structure for each vcpu

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Here we plan to support virtual PMU for guest by full software
> emulation, so define some basic structs and functions preparing for
> futher steps. Define struct kvm_pmc for performance monitor counter and
> struct kvm_pmu for performance monitor unit for each vcpu. According to
> ARMv8 spec, the PMU contains at most 32(ARMV8_MAX_COUNTERS) counters.
> 
> Since this only supports ARM64 (or PMUv3), add a separate config symbol
> for it.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/include/asm/kvm_host.h |  2 ++
>  arch/arm64/kvm/Kconfig|  8 
>  include/kvm/arm_pmu.h | 40 
> +++
>  3 files changed, 50 insertions(+)
>  create mode 100644 include/kvm/arm_pmu.h
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h 
> b/arch/arm64/include/asm/kvm_host.h
> index a35ce72..42e15bb 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -37,6 +37,7 @@
>  
>  #include 
>  #include 
> +#include 
>  
>  #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
>  
> @@ -132,6 +133,7 @@ struct kvm_vcpu_arch {
>   /* VGIC state */
>   struct vgic_cpu vgic_cpu;
>   struct arch_timer_cpu timer_cpu;
> + struct kvm_pmu pmu;
>  
>   /*
>* Anything that is not used directly from assembly code goes
> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
> index a5272c0..66da9a2 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -36,6 +36,7 @@ config KVM
>   select HAVE_KVM_EVENTFD
>   select HAVE_KVM_IRQFD
>   select KVM_ARM_VGIC_V3
> + select KVM_ARM_PMU

What if HW_PERF_EVENTS is not selected? Also, selecting HW_PERF_EVENTS
is not enough, and you probably need PERF_EVENTS as well, So this should
probably read:

select KVM_ARM_PMU if (HW_PERF_EVENTS && PERF_EVENTS)

>   ---help---
> Support hosting virtualized guest machines.
> We don't support KVM with 16K page tables yet, due to the multiple
> @@ -48,6 +49,13 @@ config KVM_ARM_HOST
>   ---help---
> Provides host support for ARM processors.
>  
> +config KVM_ARM_PMU
> + bool
> + depends on KVM_ARM_HOST && HW_PERF_EVENTS

and this line should be dropped.

> + ---help---
> +   Adds support for a virtual Performance Monitoring Unit (PMU) in
> +   virtual machines.
> +
>  source drivers/vhost/Kconfig
>  
>  endif # VIRTUALIZATION
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> new file mode 100644
> index 000..dea78f8
> --- /dev/null
> +++ b/include/kvm/arm_pmu.h
> @@ -0,0 +1,40 @@
> +/*
> + * Copyright (C) 2015 Linaro Ltd.
> + * Author: Shannon Zhao 
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see .
> + */
> +
> +#ifndef __ASM_ARM_KVM_PMU_H
> +#define __ASM_ARM_KVM_PMU_H
> +
> +#include 
> +#ifdef CONFIG_KVM_ARM_PMU
> +#include 
> +#endif
> +
> +struct kvm_pmc {
> + u8 idx;/* index into the pmu->pmc array */
> + struct perf_event *perf_event;
> + u64 bitmask;
> +};
> +
> +struct kvm_pmu {
> +#ifdef CONFIG_KVM_ARM_PMU
> + /* PMU IRQ Number per VCPU */
> + int irq_num;
> + struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
> +#endif
> +};
> +
> +#endif
> 

The repetition of #ifdef CONFIG_KVM_ARM_PMU is a bit ugly. How about
something like this instead:

#ifndef __ASM_ARM_KVM_PMU_H
#define __ASM_ARM_KVM_PMU_H

#ifdef CONFIG_KVM_ARM_PMU

#include 
#include 

struct kvm_pmc {
u8 idx;/* index into the pmu->pmc array */
struct perf_event *perf_event;
u64 bitmask;
};

struct kvm_pmu {
/* PMU IRQ Number per VCPU */
int irq_num;
struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
};

#else

struct kvm_pmu {
};

#endif

#endif

and you can then populate the rest of the function prototype and stubs
where needed.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 10/21] KVM: ARM64: Add access handler for PMEVCNTRn and PMCCNTR register

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMEVCNTRn or PMCCNTR is UNKNOWN, use
> reset_unknown for its reset handler. Add access handler which emulates
> writing and reading PMEVCNTRn or PMCCNTR register. When reading
> PMEVCNTRn or PMCCNTR, call perf_event_read_value to get the count value
> of the perf event.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 107 
> +-
>  1 file changed, 105 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c116a1b..f7a73b5 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -525,6 +525,12 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>  
>   if (p->is_write) {
>   switch (r->reg) {
> + case PMEVCNTR0_EL0 ... PMCCNTR_EL0: {

Same problem as previously mentioned.

> + val = kvm_pmu_get_counter_value(vcpu,
> + r->reg - PMEVCNTR0_EL0);
> + vcpu_sys_reg(vcpu, r->reg) += (s64)p->regval - val;
> + break;
> + }
>   case PMEVTYPER0_EL0 ... PMCCFILTR_EL0: {
>   val = r->reg - PMEVTYPER0_EL0;
>   kvm_pmu_set_counter_event_type(vcpu, p->regval, val);
> @@ -548,6 +554,12 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   }
>   } else {
>   switch (r->reg) {
> + case PMEVCNTR0_EL0 ... PMCCNTR_EL0: {
> + val = kvm_pmu_get_counter_value(vcpu,
> + r->reg - PMEVCNTR0_EL0);
> + p->regval = val;
> + break;
> + }
>   case PMCR_EL0: {
>   /* PMCR.P & PMCR.C are RAZ */
>   val = vcpu_sys_reg(vcpu, r->reg)
> @@ -579,6 +591,13 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b111), \
> trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
>  
> +/* Macro to expand the PMEVCNTRn_EL0 register */
> +#define PMU_PMEVCNTR_EL0(n)  \
> + /* PMEVCNTRn_EL0 */ \
> + { Op0(0b11), Op1(0b011), CRn(0b1110),   \
> +   CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
> +   access_pmu_regs, reset_unknown, (PMEVCNTR0_EL0 + n), }
> +
>  /* Macro to expand the PMEVTYPERn_EL0 register */
>  #define PMU_PMEVTYPER_EL0(n) \
>   /* PMEVTYPERn_EL0 */\
> @@ -779,7 +798,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmu_regs, reset_pmceid, PMCEID1_EL0 },
>   /* PMCCNTR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_unknown, PMCCNTR_EL0 },
>   /* PMXEVTYPER_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
> access_pmu_pmxevtyper },
> @@ -800,6 +819,38 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>   { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b011),
> NULL, reset_unknown, TPIDRRO_EL0 },
>  
> + /* PMEVCNTRn_EL0 */
> + PMU_PMEVCNTR_EL0(0),
> + PMU_PMEVCNTR_EL0(1),
> + PMU_PMEVCNTR_EL0(2),
> + PMU_PMEVCNTR_EL0(3),
> + PMU_PMEVCNTR_EL0(4),
> + PMU_PMEVCNTR_EL0(5),
> + PMU_PMEVCNTR_EL0(6),
> + PMU_PMEVCNTR_EL0(7),
> + PMU_PMEVCNTR_EL0(8),
> + PMU_PMEVCNTR_EL0(9),
> + PMU_PMEVCNTR_EL0(10),
> + PMU_PMEVCNTR_EL0(11),
> + PMU_PMEVCNTR_EL0(12),
> + PMU_PMEVCNTR_EL0(13),
> + PMU_PMEVCNTR_EL0(14),
> + PMU_PMEVCNTR_EL0(15),
> + PMU_PMEVCNTR_EL0(16),
> + PMU_PMEVCNTR_EL0(17),
> + PMU_PMEVCNTR_EL0(18),
> + PMU_PMEVCNTR_EL0(19),
> + PMU_PMEVCNTR_EL0(20),
> + PMU_PMEVCNTR_EL0(21),
> + PMU_PMEVCNTR_EL0(22),
> + PMU_PMEVCNTR_EL0(23),
> + PMU_PMEVCNTR_EL0(24),
> + PMU_PMEVCNTR_EL0(25),
> + PMU_PMEVCNTR_EL0(26),
> + PMU_PMEVCNTR_EL0(27),
> + PMU_PMEVCNTR_EL0(28),
> + PMU_PMEVCNTR_EL0(29),
> + PMU_PMEVCNTR_EL0(30),
>   /* PMEVTYPERn_EL0 */
>   PMU_PMEVTYPER_EL0(0),
>   PMU_PMEVTYPER_EL0(1),
> @@ -1034,6 +1085,12 @@ static bool access_pmu_cp15_regs(struct kvm_vcpu *vcpu,
>  
>   if (p->is_write) {
>   switch (r->reg) {
> + case c14_PMEVCNTR0 ... c9_PMCCNTR: {
> + val = kvm_pmu_get_counter_value(vcpu,
> + r->reg - c14_PMEVCNTR0);
> + vcpu_cp15(vcpu, r->reg) += (s64)p->regval - val;

OK, we do have an interesting problem here. On 

Re: [PATCH v6 07/21] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> When we use tools like perf on host, perf passes the event type and the
> id of this event type category to kernel, then kernel will map them to
> hardware event number and write this number to PMU PMEVTYPER_EL0
> register. When getting the event number in KVM, directly use raw event
> type to create a perf_event for it.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/include/asm/pmu.h |   2 +
>  arch/arm64/kvm/Makefile  |   1 +
>  include/kvm/arm_pmu.h|  13 
>  virt/kvm/arm/pmu.c   | 138 
> +++
>  4 files changed, 154 insertions(+)
>  create mode 100644 virt/kvm/arm/pmu.c
> 
> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
> index 4264ea0..e3cb6b3 100644
> --- a/arch/arm64/include/asm/pmu.h
> +++ b/arch/arm64/include/asm/pmu.h
> @@ -28,6 +28,8 @@
>  #define ARMV8_PMCR_D (1 << 3) /* CCNT counts every 64th cpu cycle */
>  #define ARMV8_PMCR_X (1 << 4) /* Export to ETM */
>  #define ARMV8_PMCR_DP(1 << 5) /* Disable CCNT if 
> non-invasive debug*/
> +/* Determines which PMCCNTR_EL0 bit generates an overflow */
> +#define ARMV8_PMCR_LC(1 << 6)
>  #define  ARMV8_PMCR_N_SHIFT  11   /* Number of counters 
> supported */
>  #define  ARMV8_PMCR_N_MASK   0x1f
>  #define  ARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index 1949fe5..18d56d8 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -27,3 +27,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
> +kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index dea78f8..36bde48 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -37,4 +37,17 @@ struct kvm_pmu {
>  #endif
>  };
>  
> +#ifdef CONFIG_KVM_ARM_PMU
> +u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx);
> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u32 data,
> + u32 select_idx);
> +#else
> +u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx)
> +{
> + return 0;
> +}
> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u32 data,
> + u32 select_idx) {}
> +#endif
> +
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> new file mode 100644
> index 000..15babf1
> --- /dev/null
> +++ b/virt/kvm/arm/pmu.c
> @@ -0,0 +1,138 @@
> +/*
> + * Copyright (C) 2015 Linaro Ltd.
> + * Author: Shannon Zhao 
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see .
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +/**
> + * kvm_pmu_get_counter_value - get PMU counter value
> + * @vcpu: The vcpu pointer
> + * @select_idx: The counter index
> + */
> +u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx)
> +{
> + u64 counter, enabled, running;
> + struct kvm_pmu *pmu = >arch.pmu;
> + struct kvm_pmc *pmc = >pmc[select_idx];
> +
> + if (!vcpu_mode_is_32bit(vcpu))
> + counter = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + select_idx);
> + else
> + counter = vcpu_cp15(vcpu, c14_PMEVCNTR0 + select_idx);
> +
> + if (pmc->perf_event)
> + counter += perf_event_read_value(pmc->perf_event, ,
> +  );
> +
> + return counter & pmc->bitmask;

This one confused me for a while. Is it the case that you return
whatever is in the vcpu view of the counter, plus anything that perf
itself has counted? If so, I'd appreciate a comment here...

> +}
> +
> +static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u32 select_idx)
> +{
> + if (!vcpu_mode_is_32bit(vcpu))
> + return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &
> +(vcpu_sys_reg(vcpu, PMCNTENSET_EL0) >> select_idx);

This looks wrong. Shouldn't it be:

return ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &&
(vcpu_sys_reg(vcpu, PMCNTENSET_EL0) 

Re: [PATCH v6 08/21] KVM: ARM64: Add access handler for PMEVTYPERn and PMCCFILTR register

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add access handler which emulates writing and reading PMEVTYPERn or
> PMCCFILTR register. When writing to PMEVTYPERn or PMCCFILTR, call
> kvm_pmu_set_counter_event_type to create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 98 
> +++
>  1 file changed, 98 insertions(+)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 1bcb2b7..2d8bd15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -474,6 +474,12 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>  
>   if (p->is_write) {
>   switch (r->reg) {
> + case PMEVTYPER0_EL0 ... PMCCFILTR_EL0: {

Please don't do that, this is dangerous.

I'm fine with PMEVTYPER0_EL0 ... PMEVTYPER30_EL0, but not with
PMCCFILTR_EL0. It could have been moved to another offset in the
register file, and nobody would notice this. So keep it as a separate
case statement.

> + val = r->reg - PMEVTYPER0_EL0;
> + kvm_pmu_set_counter_event_type(vcpu, p->regval, val);
> + vcpu_sys_reg(vcpu, r->reg) = p->regval;
> + break;
> + }
>   case PMCR_EL0: {
>   /* Only update writeable bits of PMCR */
>   val = vcpu_sys_reg(vcpu, r->reg);
> @@ -522,6 +528,13 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b111), \
> trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
>  
> +/* Macro to expand the PMEVTYPERn_EL0 register */
> +#define PMU_PMEVTYPER_EL0(n) \
> + /* PMEVTYPERn_EL0 */\
> + { Op0(0b11), Op1(0b011), CRn(0b1110),   \
> +   CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
> +   access_pmu_regs, reset_unknown, (PMEVTYPER0_EL0 + n), }
> +
>  /*
>   * Architected system registers.
>   * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
> @@ -736,6 +749,42 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>   { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b011),
> NULL, reset_unknown, TPIDRRO_EL0 },
>  
> + /* PMEVTYPERn_EL0 */
> + PMU_PMEVTYPER_EL0(0),
> + PMU_PMEVTYPER_EL0(1),
> + PMU_PMEVTYPER_EL0(2),
> + PMU_PMEVTYPER_EL0(3),
> + PMU_PMEVTYPER_EL0(4),
> + PMU_PMEVTYPER_EL0(5),
> + PMU_PMEVTYPER_EL0(6),
> + PMU_PMEVTYPER_EL0(7),
> + PMU_PMEVTYPER_EL0(8),
> + PMU_PMEVTYPER_EL0(9),
> + PMU_PMEVTYPER_EL0(10),
> + PMU_PMEVTYPER_EL0(11),
> + PMU_PMEVTYPER_EL0(12),
> + PMU_PMEVTYPER_EL0(13),
> + PMU_PMEVTYPER_EL0(14),
> + PMU_PMEVTYPER_EL0(15),
> + PMU_PMEVTYPER_EL0(16),
> + PMU_PMEVTYPER_EL0(17),
> + PMU_PMEVTYPER_EL0(18),
> + PMU_PMEVTYPER_EL0(19),
> + PMU_PMEVTYPER_EL0(20),
> + PMU_PMEVTYPER_EL0(21),
> + PMU_PMEVTYPER_EL0(22),
> + PMU_PMEVTYPER_EL0(23),
> + PMU_PMEVTYPER_EL0(24),
> + PMU_PMEVTYPER_EL0(25),
> + PMU_PMEVTYPER_EL0(26),
> + PMU_PMEVTYPER_EL0(27),
> + PMU_PMEVTYPER_EL0(28),
> + PMU_PMEVTYPER_EL0(29),
> + PMU_PMEVTYPER_EL0(30),
> + /* PMCCFILTR_EL0 */
> + { Op0(0b11), Op1(0b011), CRn(0b1110), CRm(0b), Op2(0b111),
> +   access_pmu_regs, reset_unknown, PMCCFILTR_EL0, },
> +
>   /* DACR32_EL2 */
>   { Op0(0b11), Op1(0b100), CRn(0b0011), CRm(0b), Op2(0b000),
> NULL, reset_unknown, DACR32_EL2 },
> @@ -934,6 +983,12 @@ static bool access_pmu_cp15_regs(struct kvm_vcpu *vcpu,
>  
>   if (p->is_write) {
>   switch (r->reg) {
> + case c14_PMEVTYPER0 ... c14_PMCCFILTR: {

Same problem here.

> + val = r->reg - c14_PMEVTYPER0;
> + kvm_pmu_set_counter_event_type(vcpu, p->regval, val);
> + vcpu_cp15(vcpu, r->reg) = p->regval;
> + break;
> + }
>   case c9_PMCR: {
>   /* Only update writeable bits of PMCR */
>   val = vcpu_cp15(vcpu, r->reg);
> @@ -967,6 +1022,13 @@ static bool access_pmu_cp15_regs(struct kvm_vcpu *vcpu,
>   return true;
>  }
>  
> +/* Macro to expand the PMEVTYPERn register */
> +#define PMU_PMEVTYPER(n) \
> + /* PMEVTYPERn */\
> + { Op1(0), CRn(0b1110),  \
> +   CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
> +   access_pmu_cp15_regs, NULL, (c14_PMEVTYPER0 + n), }
> +
>  /*
>   * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
>   * depending on the way they are 

Re: [PATCH v6 12/21] KVM: ARM64: Add reset and access handlers for PMCNTENSET and PMCNTENCLR register

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a new case to emulate writing
> PMCNTENSET or PMCNTENCLR register.
> 
> When writing to PMCNTENSET, call perf_event_enable to enable the perf
> event. When writing to PMCNTENCLR, call perf_event_disable to disable
> the perf event.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 39 +++
>  include/kvm/arm_pmu.h |  4 
>  virt/kvm/arm/pmu.c| 47 
> +++
>  3 files changed, 86 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 2304937..a780cb5 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -577,6 +577,21 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   vcpu_sys_reg(vcpu, r->reg) = p->regval;
>   break;
>   }
> + case PMCNTENSET_EL0: {
> + val = p->regval;
> + if (r->Op2 == 1) {
> + /* accessing PMCNTENSET_EL0 */
> + kvm_pmu_enable_counter(vcpu, val,
> +vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E);
> + vcpu_sys_reg(vcpu, r->reg) |= val;
> + } else {
> +
> + /* accessing PMCNTENCLR_EL0 */
> + kvm_pmu_disable_counter(vcpu, val);
> + vcpu_sys_reg(vcpu, r->reg) &= ~val;
> + }
> + break;
> + }
>   case PMCR_EL0: {
>   /* Only update writeable bits of PMCR */
>   val = vcpu_sys_reg(vcpu, r->reg);
> @@ -817,10 +832,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmu_regs, reset_pmcr, PMCR_EL0, },
>   /* PMCNTENSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_unknown, PMCNTENSET_EL0 },
>   /* PMCNTENCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_unknown, PMCNTENSET_EL0 },
>   /* PMOVSCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> trap_raz_wi },
> @@ -1137,6 +1152,20 @@ static bool access_pmu_cp15_regs(struct kvm_vcpu *vcpu,
>   vcpu_cp15(vcpu, r->reg) = p->regval;
>   break;
>   }
> + case c9_PMCNTENSET: {
> + val = p->regval;
> + if (r->Op2 == 1) {
> + /* accessing c9_PMCNTENSET */
> + kvm_pmu_enable_counter(vcpu, val,
> +vcpu_cp15(vcpu, c9_PMCR) & ARMV8_PMCR_E);
> + vcpu_cp15(vcpu, r->reg) |= val;
> + } else {
> + /* accessing c9_PMCNTENCLR */
> + kvm_pmu_disable_counter(vcpu, val);
> + vcpu_cp15(vcpu, r->reg) &= ~val;
> + }
> + break;
> + }
>   case c9_PMCR: {
>   /* Only update writeable bits of PMCR */
>   val = vcpu_cp15(vcpu, r->reg);
> @@ -1220,8 +1249,10 @@ static const struct sys_reg_desc cp15_regs[] = {
>   /* PMU */
>   { Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmu_cp15_regs,
> NULL, c9_PMCR },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmu_cp15_regs,
> +   NULL, c9_PMCNTENSET },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmu_cp15_regs,
> +   NULL, c9_PMCNTENSET },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmu_cp15_regs,
> NULL, c9_PMSELR },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 36bde48..e731656 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -39,6 +39,8 @@ struct kvm_pmu {
>  
>  #ifdef CONFIG_KVM_ARM_PMU
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx);
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u32 val);
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u32 val, bool all_enable);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u32 data,
>   u32 select_idx);
>  #else
> @@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 
> select_idx)
>  {
>   return 0;

Re: [PATCH v6 14/21] KVM: ARM64: Add reset and access handlers for PMOVSSET and PMOVSCLR register

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a new case to emulate writing
> PMOVSSET or PMOVSCLR register.
> 
> When writing non-zero value to PMOVSSET, pend PMU interrupt. When the
> value writing to PMOVSCLR is equal to the current value, clear the PMU
> pending interrupt.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 27 --
>  include/kvm/arm_pmu.h |  4 +++
>  virt/kvm/arm/pmu.c| 72 
> +++
>  3 files changed, 100 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c1dffb2..c830fde 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -601,6 +601,15 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
>   break;
>   }
> + case PMOVSSET_EL0: {
> + if (r->CRm == 14)
> + /* accessing PMOVSSET_EL0 */
> + kvm_pmu_overflow_set(vcpu, p->regval);
> + else
> + /* accessing PMOVSCLR_EL0 */
> + kvm_pmu_overflow_clear(vcpu, p->regval);
> + break;
> + }
>   case PMCR_EL0: {
>   /* Only update writeable bits of PMCR */
>   val = vcpu_sys_reg(vcpu, r->reg);
> @@ -847,7 +856,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmu_regs, reset_unknown, PMCNTENSET_EL0 },
>   /* PMOVSCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_unknown, PMOVSSET_EL0 },
>   /* PMSWINC_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> trap_raz_wi },
> @@ -874,7 +883,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> trap_raz_wi },
>   /* PMOVSSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_unknown, PMOVSSET_EL0 },
>  
>   /* TPIDR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b010),
> @@ -1184,6 +1193,15 @@ static bool access_pmu_cp15_regs(struct kvm_vcpu *vcpu,
>   vcpu_cp15(vcpu, r->reg) &= ~p->regval;
>   break;
>   }
> + case c9_PMOVSSET: {
> + if (r->CRm == 14)
> + /* accessing c9_PMOVSSET */
> + kvm_pmu_overflow_set(vcpu, p->regval);
> + else
> + /* accessing c9_PMOVSCLR */
> + kvm_pmu_overflow_clear(vcpu, p->regval);
> + break;
> + }
>   case c9_PMCR: {
>   /* Only update writeable bits of PMCR */
>   val = vcpu_cp15(vcpu, r->reg);
> @@ -1271,7 +1289,8 @@ static const struct sys_reg_desc cp15_regs[] = {
> NULL, c9_PMCNTENSET },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmu_cp15_regs,
> NULL, c9_PMCNTENSET },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmu_cp15_regs,
> +   NULL, c9_PMOVSSET },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmu_cp15_regs,
> NULL, c9_PMSELR },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmu_cp15_regs,
> @@ -1287,6 +1306,8 @@ static const struct sys_reg_desc cp15_regs[] = {
> NULL, c9_PMINTENSET },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmu_cp15_regs,
> NULL, c9_PMINTENSET },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmu_cp15_regs,
> +   NULL, c9_PMOVSSET },
>  
>   { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>   { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index e731656..a76df52 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -41,6 +41,8 @@ struct kvm_pmu {
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u32 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u32 val, bool all_enable);
> +void kvm_pmu_overflow_clear(struct kvm_vcpu *vcpu, u32 val);
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u32 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u32 data,
>   u32 select_idx);
>  #else
> @@ -50,6 +52,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu 

Re: [PATCH v6 15/21] KVM: ARM64: Add reset and access handlers for PMUSERENR register

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c830fde..80b66c0 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -880,7 +880,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmu_pmxevcntr },
>   /* PMUSERENR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
> -   trap_raz_wi },
> +   access_pmu_regs, reset_unknown, PMUSERENR_EL0 },

So while the 64bit view of the register resets as unknown, a CPU
resetting in 32bit mode resets as 0. I suggest you reset it as zero, and
document that choice. You may have to revisit all the other registers
that do reset as unknown for 64bit as well.

>   /* PMOVSSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
> access_pmu_regs, reset_unknown, PMOVSSET_EL0 },
> @@ -1301,7 +1301,8 @@ static const struct sys_reg_desc cp15_regs[] = {
> NULL, c9_PMCCNTR },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_pmxevtyper },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_pmxevcntr },
> - { Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 0), access_pmu_cp15_regs,
> +   NULL,  c9_PMUSERENR, 0 },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmu_cp15_regs,
> NULL, c9_PMINTENSET },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmu_cp15_regs,
> 

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 11/21] KVM: ARM64: Add access handler for PMXEVCNTR register

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Accessing PMXEVCNTR register is mapped to the PMEVCNTRn or PMCCNTR which
> is selected by PMSELR.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 44 ++--
>  1 file changed, 42 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f7a73b5..2304937 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -516,6 +516,46 @@ out:
>   return true;
>  }
>  
> +static bool access_pmu_pmxevcntr(struct kvm_vcpu *vcpu,
> +  struct sys_reg_params *p,
> +  const struct sys_reg_desc *r)
> +{
> + u64 pmcr, idx, val;
> +
> + if (!vcpu_mode_is_32bit(vcpu)) {
> + pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> + idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
> +
> + if (!pmu_counter_idx_valid(pmcr, idx))
> + goto out;
> +
> + val = kvm_pmu_get_counter_value(vcpu, idx);
> + if (!p->is_write) {
> + p->regval = val;
> + goto out;
> + }
> +
> + vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + idx) += (s64)p->regval - val;
> + } else {
> + pmcr = vcpu_cp15(vcpu, c9_PMCR);
> + idx = vcpu_cp15(vcpu, c9_PMSELR) & ARMV8_COUNTER_MASK;
> +
> + if (!pmu_counter_idx_valid(pmcr, idx))
> + goto out;
> +
> + val = kvm_pmu_get_counter_value(vcpu, idx);
> + if (!p->is_write) {
> + p->regval = val;
> + goto out;
> + }
> +
> + vcpu_cp15(vcpu, c14_PMEVCNTR0 + idx) += (s64)p->regval - val;
> + }
> +
> +out:
> + return true;
> +}

There is definitely some common code with the handling of PMEVCNTRn
here. Can you please factor it ?

> +
>  /* PMU registers accessor. */
>  static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>   struct sys_reg_params *p,
> @@ -804,7 +844,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmu_pmxevtyper },
>   /* PMXEVCNTR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
> -   trap_raz_wi },
> +   access_pmu_pmxevcntr },
>   /* PMUSERENR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
> trap_raz_wi },
> @@ -1192,7 +1232,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_cp15_regs,
> NULL, c9_PMCCNTR },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_pmxevtyper },
> - { Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_pmxevcntr },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
> 

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v6 18/21] KVM: ARM64: Add PMU overflow interrupt routing

2015-12-08 Thread Marc Zyngier
On 08/12/15 12:47, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> When calling perf_event_create_kernel_counter to create perf_event,
> assign a overflow handler. Then when perf event overflows, call
> kvm_vcpu_kick() to sync the interrupt.

Please update the commit message, things have changed quite a bit now.

> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm/kvm/arm.c|  2 ++
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c| 52 
> ++-
>  3 files changed, 55 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index e06fd29..cd696ef 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -28,6 +28,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #define CREATE_TRACE_POINTS
>  #include "trace.h"
> @@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct 
> kvm_run *run)
>* non-preemptible context.
>*/
>   preempt_disable();
> + kvm_pmu_flush_hwstate(vcpu);
>   kvm_timer_flush_hwstate(vcpu);
>   kvm_vgic_flush_hwstate(vcpu);
>  
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index a131f76..c4041008 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -38,6 +38,7 @@ struct kvm_pmu {
>  };
>  
>  #ifdef CONFIG_KVM_ARM_PMU
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u32 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u32 val, bool all_enable);
> @@ -48,6 +49,7 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, 
> u32 data,
>   u32 select_idx);
>  void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u32 val);
>  #else
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u32 select_idx)
>  {
>   return 0;
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 9b9c706..ff182d6 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -21,6 +21,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  /**
>   * kvm_pmu_get_counter_value - get PMU counter value
> @@ -90,6 +91,54 @@ static void kvm_pmu_stop_counter(struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_flush_hwstate - flush pmu state to cpu
> + * @vcpu: The vcpu pointer
> + *
> + * Inject virtual PMU IRQ if IRQ is pending for this cpu.
> + */
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> + struct kvm_pmu *pmu = >arch.pmu;
> + u32 overflow;
> +
> + if (pmu->irq_num == -1)
> + return;
> +
> + if (!vcpu_mode_is_32bit(vcpu)) {
> + if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
> + return;
> +
> + overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
> +& vcpu_sys_reg(vcpu, PMINTENSET_EL1)
> +& vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> + } else {
> + if (!(vcpu_cp15(vcpu, c9_PMCR) & ARMV8_PMCR_E))
> + return;
> +
> + overflow = vcpu_cp15(vcpu, c9_PMCNTENSET)
> +& vcpu_cp15(vcpu, c9_PMINTENSET)
> +& vcpu_cp15(vcpu, c9_PMOVSSET);
> + }
> +
> + kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
> + overflow ? 1 : 0);
> +}
> +
> +/**
> + * When perf event overflows, call kvm_pmu_overflow_set to set overflow 
> status.
> + */
> +static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
> +   struct perf_sample_data *data,
> +   struct pt_regs *regs)
> +{
> + struct kvm_pmc *pmc = perf_event->overflow_handler_context;
> + struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
> + int idx = pmc->idx;
> +
> + kvm_pmu_overflow_set(vcpu, BIT(idx));
> +}
> +
> +/**
>   * kvm_pmu_enable_counter - enable selected PMU counter
>   * @vcpu: The vcpu pointer
>   * @val: the value guest writes to PMCNTENSET register
> @@ -341,7 +390,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
> *vcpu, u32 data,
>   /* The initial sample period (overflow count) of an event. */
>   attr.sample_period = (-counter) & pmc->bitmask;
>  
> - event = perf_event_create_kernel_counter(, -1, current, NULL, pmc);
> + event = perf_event_create_kernel_counter(, -1, current,
> +  kvm_pmu_perf_overflow, pmc);
>   if (IS_ERR(event)) {
>   printk_once("kvm: pmu event creation failed %ld\n",
>   PTR_ERR(event));
> 

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org

  1   2   3   4   5   6   7   8   9   10   >