qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Christoffer Dall <christoffer.dall@linaro.org>
To: Peter Maydell <peter.maydell@linaro.org>
Cc: patches@linaro.org, qemu-devel@nongnu.org, kvmarm@lists.cs.columbia.edu
Subject: Re: [Qemu-devel] [PATCH v9 10/11] target-arm: Provide '-cpu host' when running KVM
Date: Fri, 22 Nov 2013 10:25:02 -0800	[thread overview]
Message-ID: <20131122182502.GN9314@cbox> (raw)
In-Reply-To: <1385140638-10444-11-git-send-email-peter.maydell@linaro.org>

On Fri, Nov 22, 2013 at 05:17:17PM +0000, Peter Maydell wrote:
> 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     |  224 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  target-arm/kvm_arm.h |   55 +++++++++++++
>  3 files changed, 285 insertions(+)
> 
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 3445813..263dbbf 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1842,6 +1842,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
>  }
>  
>  static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> index 182db85..f865dac 100644
> --- a/target-arm/kvm.c
> +++ b/target-arm/kvm.c
> @@ -27,12 +27,236 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
>      KVM_CAP_LAST_INFO
>  };
>  
> +bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
> +                                      int *fdarray,
> +                                      struct kvm_vcpu_init *init)
> +{
> +    int ret, kvmfd = -1, vmfd = -1, cpufd = -1;
> +
> +    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;
> +    }
> +
> +    ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, init);
> +    if (ret >= 0) {
> +        ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
> +        if (ret < 0) {
> +            goto err;
> +        }
> +    } else {
> +        /* Old kernel which doesn't know about the
> +         * PREFERRED_TARGET ioctl: we know it will only support
> +         * creating one kind of guest CPU which is its preferred
> +         * CPU type.
> +         */
> +        while (*cpus_to_try != QEMU_KVM_ARM_TARGET_NONE) {
> +            init->target = *cpus_to_try++;
> +            memset(init->features, 0, sizeof(init->features));
> +            ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
> +            if (ret >= 0) {
> +                break;
> +            }
> +        }
> +        if (ret < 0) {
> +            goto err;
> +        }
> +    }
> +
> +    fdarray[0] = kvmfd;
> +    fdarray[1] = vmfd;
> +    fdarray[2] = cpufd;

you could consider using a define/enum/struct for this instead of an
array, but bah, not important.

> +
> +    return true;
> +
> +err:
> +    if (cpufd >= 0) {
> +        close(cpufd);
> +    }
> +    if (vmfd >= 0) {
> +        close(vmfd);
> +    }
> +    if (kvmfd >= 0) {
> +        close(kvmfd);
> +    }
> +
> +    return false;
> +}
> +
> +void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
> +{
> +    int i;
> +
> +    for (i = 2; i >= 0; i--) {
> +        close(fdarray[i]);
> +    }
> +}
> +
> +static inline void set_feature(uint64_t *features, int feature)
> +{
> +    *features |= 1ULL << feature;
> +}
> +
> +bool kvm_arm_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, fdarray[3];
> +    uint32_t midr, id_pfr0, id_isar0, mvfr1;
> +    uint64_t features = 0;
> +    /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
> +     * we know these will only support creating one kind of guest CPU,
> +     * which is its preferred CPU type.
> +     */
> +    static const uint32_t cpus_to_try[] = {
> +        QEMU_KVM_ARM_TARGET_CORTEX_A15,
> +        QEMU_KVM_ARM_TARGET_NONE
> +    };
> +    struct kvm_vcpu_init init;
> +    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,
> +        },
> +    };
> +
> +    if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
> +        return false;
> +    }
> +
> +    ahcc->target = init.target;
> +
> +    /* This is not strictly blessed by the device tree binding docs yet,
> +     * but in practice the kernel does not care about this string so
> +     * there is no point maintaining an KVM_ARM_TARGET_* -> string table.
> +     */
> +    ahcc->dtb_compatible = "arm,arm-v7";
> +
> +    for (i = 0; i < ARRAY_SIZE(idregs); i++) {
> +        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &idregs[i]);
> +        if (ret) {
> +            break;
> +        }
> +    }
> +
> +    kvm_arm_destroy_scratch_host_vcpu(fdarray);
> +
> +    if (ret) {
> +        return false;
> +    }
> +
> +    /* 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;
> +}
> +
> +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 (!kvm_arm_get_host_cpu_features(ahcc)) {
> +        fprintf(stderr, "Failed to retrieve host CPU features!\n");
> +        abort();
> +    }
> +}
> +
> +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;
> +
> +    cpu->kvm_target = ahcc->target;
> +    cpu->dtb_compatible = ahcc->dtb_compatible;
> +    env->features = ahcc->features;
> +}
> +
> +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;
>  }
>  
> diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
> index 5d14887..cd3d13c 100644
> --- a/target-arm/kvm_arm.h
> +++ b/target-arm/kvm_arm.h
> @@ -62,4 +62,59 @@ bool write_list_to_kvmstate(ARMCPU *cpu);
>   */
>  bool write_kvmstate_to_list(ARMCPU *cpu);
>  
> +#ifdef CONFIG_KVM
> +/**
> + * kvm_arm_create_scratch_host_vcpu:
> + * @cpus_to_try: array of QEMU_KVM_ARM_TARGET_* values (terminated with
> + * QEMU_KVM_ARM_TARGET_NONE) to try as fallback if the kernel does not
> + * know the PREFERRED_TARGET ioctl
> + * @fdarray: filled in with kvmfd, vmfd, cpufd file descriptors in that order
> + * @init: filled in with the necessary values for creating a host vcpu
> + *
> + * Create a scratch vcpu in its own VM of the type preferred by the host
> + * kernel (as would be used for '-cpu host'), for purposes of probing it
> + * for capabilities.
> + *
> + * Returns: true on success (and fdarray and init are filled in),
> + * false on failure (and fdarray and init are not valid).
> + */
> +bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
> +                                      int *fdarray,
> +                                      struct kvm_vcpu_init *init);

why do we need to export this at all?

> +
> +/**
> + * kvm_arm_destroy_scratch_host_vcpu:
> + * @fdarray: array of fds as set up by kvm_arm_create_scratch_host_vcpu
> + *
> + * Tear down the scratch vcpu created by kvm_arm_create_scratch_host_vcpu.
> + */
> +void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
> +
> +#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;
> +    const char *dtb_compatible;
> +} ARMHostCPUClass;
> +
> +/**
> + * kvm_arm_get_host_cpu_features:
> + * @ahcc: ARMHostCPUClass to fill in
> + *
> + * Probe the capabilities of the host kernel's preferred CPU and fill
> + * in the ARMHostCPUClass struct accordingly.
> + */
> +bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc);
> +
> +#endif
> +
>  #endif
> -- 
> 1.7.9.5
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm

  reply	other threads:[~2013-11-22 18:23 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-22 17:17 [Qemu-devel] [PATCH v9 00/11] target-arm: mach virt and -cpu host support Peter Maydell
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 01/11] target-arm: Provide mechanism for getting KVM constants even if not CONFIG_KVM Peter Maydell
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 02/11] device_tree.c: Terminate the empty reservemap in create_device_tree() Peter Maydell
2013-11-24  8:04   ` Peter Crosthwaite
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 03/11] hw/arm/boot: Allow boards to provide an fdt blob Peter Maydell
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 04/11] target-arm: Provide PSCI constants to generic QEMU code Peter Maydell
2013-11-22 17:52   ` Christoffer Dall
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 05/11] target-arm: Add ARMCPU field for Linux device-tree 'compatible' string Peter Maydell
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 06/11] target-arm: Allow secondary KVM CPUs to be booted via PSCI Peter Maydell
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 07/11] hw/arm: Add 'virt' platform Peter Maydell
2013-11-22 18:11   ` Christoffer Dall
2013-11-22 18:17     ` Peter Maydell
2013-11-22 18:24       ` Christoffer Dall
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 08/11] linux-headers: Update from mainline Peter Maydell
2013-12-02 13:35   ` Peter Maydell
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 09/11] target-arm: Don't hardcode KVM target CPU to be A15 Peter Maydell
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 10/11] target-arm: Provide '-cpu host' when running KVM Peter Maydell
2013-11-22 18:25   ` Christoffer Dall [this message]
2013-11-22 18:50     ` Peter Maydell
2013-11-22 19:00       ` Christoffer Dall
2013-11-22 17:17 ` [Qemu-devel] [PATCH v9 11/11] hw/arm/virt: Support -cpu host Peter Maydell
2013-11-22 18:26 ` [Qemu-devel] [PATCH v9 00/11] target-arm: mach virt and -cpu host support Christoffer Dall
2013-12-02 13:46 ` 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=20131122182502.GN9314@cbox \
    --to=christoffer.dall@linaro.org \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=patches@linaro.org \
    --cc=peter.maydell@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).