qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-arm] [PATCH RFC 5/7] ARM64: KVM: Support cross type vCPU


From: Shannon Zhao
Subject: [Qemu-arm] [PATCH RFC 5/7] ARM64: KVM: Support cross type vCPU
Date: Mon, 16 Jan 2017 17:33:32 +0800

From: Shannon Zhao <address@hidden>

Add a capability to tell userspace that KVM supports cross type vCPU.
Add a cpu feature for userspace to set when it doesn't use host type
vCPU and kvm_vcpu_preferred_target return the host MIDR register value
so that userspace can check whether its requested vCPU type macthes the
one of physical CPU and if so, KVM will not trap ID registers even
though userspace doesn't specify -cpu host.
Guest accesses MIDR through VPIDR_EL2 so we save/restore it no matter
it's a cross type vCPU.

Signed-off-by: Shannon Zhao <address@hidden>
---
 arch/arm/kvm/arm.c                   | 10 ++++++++--
 arch/arm64/include/asm/kvm_emulate.h |  3 +++
 arch/arm64/include/asm/kvm_host.h    |  3 ++-
 arch/arm64/include/uapi/asm/kvm.h    |  1 +
 arch/arm64/kvm/guest.c               | 17 ++++++++++++++++-
 arch/arm64/kvm/hyp/sysreg-sr.c       |  2 ++
 include/uapi/linux/kvm.h             |  1 +
 7 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 1167678..bdceb19 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -207,6 +207,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_ARM_PSCI_0_2:
        case KVM_CAP_READONLY_MEM:
        case KVM_CAP_MP_STATE:
+       case KVM_CAP_ARM_CROSS_VCPU:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -809,8 +810,9 @@ static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
 {
        unsigned int i;
        int phys_target = kvm_target_cpu();
+       bool cross_vcpu = kvm_vcpu_has_feature_cross_cpu(init);
 
-       if (init->target != phys_target)
+       if (!cross_vcpu && init->target != phys_target)
                return -EINVAL;
 
        /*
@@ -839,7 +841,11 @@ static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
                        set_bit(i, vcpu->arch.features);
        }
 
-       vcpu->arch.target = phys_target;
+       if (!cross_vcpu)
+               vcpu->arch.target = phys_target;
+       else
+               /* Use generic ARMv8 target for cross type vcpu. */
+               vcpu->arch.target = KVM_ARM_TARGET_GENERIC_V8;
 
        /* Now we know what it is, we can reset it. */
        return kvm_reset_vcpu(vcpu);
diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index f5ea0ba..bca7d3a 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -49,6 +49,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
                vcpu->arch.hcr_el2 |= HCR_E2H;
        if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features))
                vcpu->arch.hcr_el2 &= ~HCR_RW;
+       if (test_bit(KVM_ARM_VCPU_CROSS, vcpu->arch.features))
+               /* TODO: Set HCR_TID2 and trap cache registers */
+               vcpu->arch.hcr_el2 |= HCR_TID3 | HCR_TID1 | HCR_TID0;
 }
 
 static inline unsigned long vcpu_get_hcr(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 6034f92..d0073d7 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -41,10 +41,11 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
-#define KVM_VCPU_MAX_FEATURES 4
+#define KVM_VCPU_MAX_FEATURES 5
 
 #define KVM_REQ_VCPU_EXIT      8
 
+bool kvm_vcpu_has_feature_cross_cpu(const struct kvm_vcpu_init *init);
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
diff --git a/arch/arm64/include/uapi/asm/kvm.h 
b/arch/arm64/include/uapi/asm/kvm.h
index 3051f86..7ba7117 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -97,6 +97,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_EL1_32BIT         1 /* CPU running a 32bit VM */
 #define KVM_ARM_VCPU_PSCI_0_2          2 /* CPU uses PSCI v0.2 */
 #define KVM_ARM_VCPU_PMU_V3            3 /* Support guest PMUv3 */
+#define KVM_ARM_VCPU_CROSS             4 /* Support cross type vCPU */
 
 struct kvm_vcpu_init {
        __u32 target;
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 92abe2b..4a5ccab 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -308,8 +308,15 @@ int __attribute_const__ kvm_target_cpu(void)
        return KVM_ARM_TARGET_GENERIC_V8;
 }
 
+bool kvm_vcpu_has_feature_cross_cpu(const struct kvm_vcpu_init *init)
+{
+       return init->features[KVM_ARM_VCPU_CROSS / 32] &
+              (1 << (KVM_ARM_VCPU_CROSS % 32));
+}
+
 int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init)
 {
+       bool cross_vcpu = kvm_vcpu_has_feature_cross_cpu(init);
        int target = kvm_target_cpu();
 
        if (target < 0)
@@ -323,7 +330,15 @@ int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init)
         * specific features available for the preferred
         * target type.
         */
-       init->target = (__u32)target;
+       /* If userspace wants a cross type vcpu other that host, here we return
+        * the midr for userspace to check whether the midr value of requeseted
+        * vcpu matches the one of host. If they match, we will not trap CPU ID
+        * registers even though userspace doesn't specify -cpu host.
+        */
+       if (cross_vcpu)
+               init->target = read_cpuid_id();
+       else
+               init->target = (__u32)target;
 
        return 0;
 }
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 9341376..9461829 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -45,6 +45,7 @@ static void __hyp_text __sysreg_save_common_state(struct 
kvm_cpu_context *ctxt)
 
 static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
 {
+       ctxt->id_sys_regs[MIDR_EL1]     = read_sysreg(vpidr_el2);
        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_el1(sctlr);
@@ -98,6 +99,7 @@ static void __hyp_text __sysreg_restore_common_state(struct 
kvm_cpu_context *ctx
 
 static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
 {
+       write_sysreg(ctxt->id_sys_regs[MIDR_EL1],       vpidr_el2);
        write_sysreg(ctxt->sys_regs[MPIDR_EL1],         vmpidr_el2);
        write_sysreg(ctxt->sys_regs[CSSELR_EL1],        csselr_el1);
        write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1],     sctlr);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index cac48ed..46115a2 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -871,6 +871,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_S390_USER_INSTR0 130
 #define KVM_CAP_MSI_DEVID 131
 #define KVM_CAP_PPC_HTM 132
+#define KVM_CAP_ARM_CROSS_VCPU 133
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
2.0.4





reply via email to

[Prev in Thread] Current Thread [Next in Thread]