All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-devel@nongnu.org
Cc: kvmarm@lists.cs.columbia.edu, "Andreas Färber" <afaerber@suse.de>,
	patches@linaro.org
Subject: [Qemu-devel] [RFC 2/2] target-arm: Provide '-cpu host' when running KVM
Date: Tue, 13 Aug 2013 19:03:03 +0100	[thread overview]
Message-ID: <1376416983-30838-3-git-send-email-peter.maydell@linaro.org> (raw)
In-Reply-To: <1376416983-30838-1-git-send-email-peter.maydell@linaro.org>

Implement '-cpu host' for ARM when we're using KVM, broadly
in line with other KVM-supporting architectures.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.c |    6 ++
 target-arm/kvm.c    |  195 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 201 insertions(+)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 4968391..6a81101 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1573,6 +1573,12 @@ void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     (*cpu_fprintf)(f, "Available CPUs:\n");
     g_slist_foreach(list, arm_cpu_list_entry, &s);
     g_slist_free(list);
+#ifdef CONFIG_KVM
+    /* The 'host' CPU type is dynamically registered only if KVM is
+     * enabled, so we have to special-case it here:
+     */
+    (*cpu_fprintf)(f, "  host (only available in KVM mode)\n");
+#endif
 }
 
 void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 0e33efc..95573f4 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -36,12 +36,200 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
 };
 
+#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
+#define ARM_HOST_CPU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(ARMHostCPUClass, (klass), TYPE_ARM_HOST_CPU)
+#define ARM_HOST_CPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(ARMHostCPUClass, (obj), TYPE_ARM_HOST_CPU)
+
+typedef struct ARMHostCPUClass {
+    /*< private >*/
+    ARMCPUClass parent_class;
+    /*< public >*/
+
+    uint64_t features;
+    uint32_t target;
+} ARMHostCPUClass;
+
+static void kvm_arm_host_cpu_initfn(Object *obj)
+{
+    ARMHostCPUClass *ahcc = ARM_HOST_CPU_GET_CLASS(obj);
+    ARMCPU *cpu = ARM_CPU(obj);
+    CPUARMState *env = &cpu->env;
+
+    env->features = ahcc->features;
+}
+
+static inline void set_feature(uint64_t *features, int feature)
+{
+    *features |= 1ULL << feature;
+}
+
+static bool get_host_cpu_features(ARMHostCPUClass *ahcc)
+{
+    /* Identify the feature bits corresponding to the host CPU, and
+     * fill out the ARMHostCPUClass fields accordingly. To do this
+     * we have to create a scratch VM, create a single CPU inside it,
+     * and then query that CPU for the relevant ID registers.
+     */
+    int i, ret, kvmfd = -1, vmfd = -1, cpufd = -1;
+    uint32_t midr, id_pfr0, id_isar0, mvfr1;
+    uint64_t features = 0;
+    /* Any kernel old enough to not know about TARGET_HOST must be one which
+     * only supports guest A15 on host A15, so we fall back to trying A15.
+     */
+    static const uint32_t cpus_to_try[] = {
+        /* TODO add KVM_ARM_TARGET_HOST when it appears in the ABI */
+        KVM_ARM_TARGET_CORTEX_A15,
+    };
+    struct kvm_one_reg idregs[] = {
+        {
+            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+            | ENCODE_CP_REG(15, 0, 0, 0, 0, 0),
+            .addr = (uintptr_t)&midr,
+        },
+        {
+            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+            | ENCODE_CP_REG(15, 0, 0, 1, 0, 0),
+            .addr = (uintptr_t)&id_pfr0,
+        },
+        {
+            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+            | ENCODE_CP_REG(15, 0, 0, 2, 0, 0),
+            .addr = (uintptr_t)&id_isar0,
+        },
+        {
+            .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+            | KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR1,
+            .addr = (uintptr_t)&mvfr1,
+        },
+    };
+
+    kvmfd = qemu_open("/dev/kvm", O_RDWR);
+    if (kvmfd < 0) {
+        goto err;
+    }
+    vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
+    if (vmfd < 0) {
+        goto err;
+    }
+    cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
+    if (cpufd < 0) {
+        goto err;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(cpus_to_try); i++) {
+        struct kvm_vcpu_init init;
+
+        init.target = cpus_to_try[i];
+        memset(init.features, 0, sizeof(init.features));
+        ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, &init);
+        if (ret >= 0) {
+            ahcc->target = init.target;
+            break;
+        }
+    }
+    if (ret < 0) {
+        goto err;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(idregs); i++) {
+        ret = ioctl(cpufd, KVM_GET_ONE_REG, &idregs[i]);
+        if (ret) {
+            goto err;
+        }
+    }
+    close(cpufd);
+    close(vmfd);
+    close(kvmfd);
+
+    /* Now we've retrieved all the register information we can
+     * set the feature bits based on the ID register fields.
+     * We can assume any KVM supporting CPU is at least a v7
+     * with VFPv3, LPAE and the generic timers; this in turn implies
+     * most of the other feature bits, but a few must be tested.
+     */
+    set_feature(&features, ARM_FEATURE_V7);
+    set_feature(&features, ARM_FEATURE_VFP3);
+    set_feature(&features, ARM_FEATURE_LPAE);
+    set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
+
+    switch (extract32(id_isar0, 24, 4)) {
+    case 1:
+        set_feature(&features, ARM_FEATURE_THUMB_DIV);
+        break;
+    case 2:
+        set_feature(&features, ARM_FEATURE_ARM_DIV);
+        set_feature(&features, ARM_FEATURE_THUMB_DIV);
+        break;
+    default:
+        break;
+    }
+
+    if (extract32(id_pfr0, 12, 4) == 1) {
+        set_feature(&features, ARM_FEATURE_THUMB2EE);
+    }
+    if (extract32(mvfr1, 20, 4) == 1) {
+        set_feature(&features, ARM_FEATURE_VFP_FP16);
+    }
+    if (extract32(mvfr1, 12, 4) == 1) {
+        set_feature(&features, ARM_FEATURE_NEON);
+    }
+    if (extract32(mvfr1, 28, 4) == 1) {
+        /* FMAC support implies VFPv4 */
+        set_feature(&features, ARM_FEATURE_VFP4);
+    }
+
+    ahcc->features = features;
+
+    return true;
+
+err:
+    if (cpufd >= 0) {
+        close(cpufd);
+    }
+    if (vmfd >= 0) {
+        close(vmfd);
+    }
+    if (kvmfd >= 0) {
+        close(kvmfd);
+    }
+
+    return false;
+}
+
+static void kvm_arm_host_cpu_class_init(ObjectClass *oc, void *data)
+{
+    ARMHostCPUClass *ahcc = ARM_HOST_CPU_CLASS(oc);
+
+    /* All we really need to set up for the 'host' CPU
+     * is the feature bits -- we rely on the fact that the
+     * various ID register values in ARMCPU are only used for
+     * TCG CPUs.
+     */
+    if (!get_host_cpu_features(ahcc)) {
+        fprintf(stderr, "Failed to retrieve host CPU features!\n");
+        abort();
+    }
+}
+
+static const TypeInfo host_arm_cpu_type_info = {
+    .name = TYPE_ARM_HOST_CPU,
+    .parent = TYPE_ARM_CPU,
+    .instance_init = kvm_arm_host_cpu_initfn,
+    .class_init = kvm_arm_host_cpu_class_init,
+    .class_size = sizeof(ARMHostCPUClass),
+};
+
 int kvm_arch_init(KVMState *s)
 {
     /* For ARM interrupt delivery is always asynchronous,
      * whether we are using an in-kernel VGIC or not.
      */
     kvm_async_interrupts_allowed = true;
+
+    type_register_static(&host_arm_cpu_type_info);
+
     return 0;
 }
 
@@ -86,6 +274,13 @@ static bool kvm_arm_get_init_args(ARMCPU *cpu, struct kvm_vcpu_init *init)
 
     memset(init->features, 0, sizeof(init->features));
 
+    if (object_dynamic_cast(obj, TYPE_ARM_HOST_CPU)) {
+        ARMHostCPUClass *ahcc = ARM_HOST_CPU_GET_CLASS(obj);
+
+        init->target = ahcc->target;
+        return true;
+    }
+
     for (i = 0; i < ARRAY_SIZE(kvm_cpus); i++) {
         if (object_dynamic_cast(obj, kvm_cpus[i].name)) {
             init->target = kvm_cpus[i].target;
-- 
1.7.9.5

  parent reply	other threads:[~2013-08-13 18:24 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-13 18:03 [Qemu-devel] [RFC 0/2] target-arm: Provide '-cpu host' when running KVM Peter Maydell
2013-08-13 18:03 ` [Qemu-devel] [RFC 1/2] target-arm: Don't hardcode KVM target CPU to be A15 Peter Maydell
2013-08-13 18:03 ` Peter Maydell [this message]
2013-08-14  6:32 ` [Qemu-devel] [RFC 0/2] target-arm: Provide '-cpu host' when running KVM Alexander Graf
2013-08-14  8:11   ` Marc Zyngier
2013-08-14  8:16     ` Alexander Graf
2013-08-14  8:27       ` Marc Zyngier
2013-08-14  8:46         ` Alexander Graf
2013-08-14  9:07           ` Peter Maydell
2013-08-14  9:11             ` Alexander Graf
2013-08-14  9:23               ` Peter Maydell
2013-08-14  9:30                 ` Alexander Graf
2013-08-14 17:26                   ` Christoffer Dall
2013-08-14 17:31                     ` Alexander Graf
2013-08-14 17:39                       ` Christoffer Dall
2013-08-14 17:44                         ` Alexander Graf
2013-08-14 18:18                           ` Christoffer Dall
2013-08-14 18:21                             ` Alexander Graf
2013-08-14 18:27                               ` Peter Maydell
2013-08-14 19:23                                 ` Alexander Graf
2013-08-14 18:28                               ` Christoffer Dall
2013-08-14 19:28                                 ` Alexander Graf
2013-08-14 20:33                                   ` Christoffer Dall
2013-08-14 20:47                                     ` Alexander Graf
2013-08-14 20:56                                       ` Christoffer Dall
2013-08-14 21:00                                         ` Alexander Graf
2013-08-25 14:42                                   ` Gleb Natapov
2013-08-25 15:11                                     ` Peter Maydell
2013-08-26 11:18                                       ` Gleb Natapov
2013-08-26 12:17                                         ` Peter Maydell
2013-08-14 18:11                       ` Peter Maydell
2013-08-14 18:15                         ` Alexander Graf
2013-08-14 18:24                           ` Peter Maydell
2013-08-14  9:06   ` Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1376416983-30838-3-git-send-email-peter.maydell@linaro.org \
    --to=peter.maydell@linaro.org \
    --cc=afaerber@suse.de \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=patches@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.