All of lore.kernel.org
 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 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.