qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH 3/7] target-arm: Add minimal KVM AArch64 support


From: Christoffer Dall
Subject: Re: [Qemu-devel] [PATCH 3/7] target-arm: Add minimal KVM AArch64 support
Date: Mon, 16 Dec 2013 15:39:50 -0800
User-agent: Mutt/1.5.21 (2010-09-15)

On Thu, Nov 28, 2013 at 01:33:18PM +0000, Peter Maydell wrote:
> From: "Mian M. Hamayun" <address@hidden>
> 
> Add the bare minimum set of functions needed for control of an
> AArch64 KVM vcpu:
>  * CPU initialization
>  * minimal get/put register functions which only handle the
>    basic state of the CPU
> 
> Signed-off-by: Mian M. Hamayun <address@hidden>
> [PMM: significantly overhauled; most notably:
>  * code lives in kvm64.c rather than using #ifdefs
>  * support '-cpu host' rather than implicitly using whatever the
>    host's CPU is regardless of what the user requests
>  * fix bug attempting to get/set nonexistent X[31]
>  * fix bug writing 64 bit kernel pstate into uint32_t env field
> ]
> Signed-off-by: Peter Maydell <address@hidden>

Besides the minor nits/questions below:

Reviewed-by: Christoffer Dall <address@hidden>

> ---
>  target-arm/Makefile.objs |    1 +
>  target-arm/kvm.c         |    4 +
>  target-arm/kvm64.c       |  204 
> ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 209 insertions(+)
>  create mode 100644 target-arm/kvm64.c
> 
> diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
> index d1db77c..5493a4c 100644
> --- a/target-arm/Makefile.objs
> +++ b/target-arm/Makefile.objs
> @@ -7,3 +7,4 @@ obj-y += neon_helper.o iwmmxt_helper.o
>  obj-y += gdbstub.o
>  obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o gdbstub64.o
>  obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
> +obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> index 5cdb3b9..1d2688d 100644
> --- a/target-arm/kvm.c
> +++ b/target-arm/kvm.c
> @@ -128,7 +128,11 @@ static void kvm_arm_host_cpu_initfn(Object *obj)
>  
>  static const TypeInfo host_arm_cpu_type_info = {
>      .name = TYPE_ARM_HOST_CPU,
> +#ifdef TARGET_AARCH64
> +    .parent = TYPE_AARCH64_CPU,
> +#else
>      .parent = TYPE_ARM_CPU,
> +#endif
>      .instance_init = kvm_arm_host_cpu_initfn,
>      .class_init = kvm_arm_host_cpu_class_init,
>      .class_size = sizeof(ARMHostCPUClass),
> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
> new file mode 100644
> index 0000000..599db5d
> --- /dev/null
> +++ b/target-arm/kvm64.c
> @@ -0,0 +1,204 @@
> +/*
> + * ARM implementation of KVM hooks, 64 bit specific code
> + *
> + * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +
> +#include <linux/kvm.h>
> +
> +#include "qemu-common.h"
> +#include "qemu/timer.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/kvm.h"
> +#include "kvm_arm.h"
> +#include "cpu.h"
> +#include "hw/arm/arm.h"
> +
> +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.
> +     * For AArch64 we currently don't care about ID registers at
> +     * all; we just want to know the CPU type.
> +     */
> +    int fdarray[3];
> +    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. Fortunately these old kernels
> +     * support only a very limited number of CPUs.
> +     */
> +    static const uint32_t cpus_to_try[] = {
> +        KVM_ARM_TARGET_AEM_V8,
> +        KVM_ARM_TARGET_FOUNDATION_V8,
> +        KVM_ARM_TARGET_CORTEX_A57,
> +        QEMU_KVM_ARM_TARGET_NONE
> +    };
> +    struct kvm_vcpu_init init;
> +
> +    if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
> +        return false;
> +    }
> +
> +    ahcc->target = init.target;
> +    ahcc->dtb_compatible = "arm,arm-v7";

arm,arm-v8 ?

> +
> +    kvm_arm_destroy_scratch_host_vcpu(fdarray);
> +
> +   /* We can assume any KVM supporting CPU is at least a v8
> +     * with VFPv4+Neon; this in turn implies most of the other
> +     * feature bits.

not sure I understand the bit about implying other feature bits, the
only other thing we're setting here is AARCH64 and the features bits are
enum values?

> +     */
> +    set_feature(&features, ARM_FEATURE_V8);
> +    set_feature(&features, ARM_FEATURE_VFP4);
> +    set_feature(&features, ARM_FEATURE_NEON);
> +    set_feature(&features, ARM_FEATURE_AARCH64);
> +
> +    ahcc->features = features;
> +
> +    return true;
> +}
> +
> +int kvm_arch_init_vcpu(CPUState *cs)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    struct kvm_vcpu_init init;
> +    int ret;
> +
> +    if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
> +        !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> +        fprintf(stderr, "KVM is not supported for this guest CPU type\n");
> +        return -EINVAL;
> +    }
> +
> +    init.target = cpu->kvm_target;
> +    memset(init.features, 0, sizeof(init.features));
> +    if (cpu->start_powered_off) {
> +        init.features[0] = 1 << KVM_ARM_VCPU_POWER_OFF;
> +    }
> +    ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
> +
> +    /* TODO : support for save/restore/reset of system regs via tuple list */
> +
> +    return ret;
> +}
> +
> +#define AARCH64_CORE_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
> +                 KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
> +
> +int kvm_arch_put_registers(CPUState *cs, int level)
> +{
> +    struct kvm_one_reg reg;
> +    uint64_t val;
> +    int i;
> +    int ret;
> +
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +
> +    for (i = 0; i < 31; i++) {
> +        reg.id = AARCH64_CORE_REG(regs.regs[i]);
> +        reg.addr = (uintptr_t) &env->xregs[i];
> +        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    reg.id = AARCH64_CORE_REG(regs.sp);
> +    reg.addr = (uintptr_t) &env->xregs[31];
> +    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    /* Note that KVM thinks pstate is 64 bit but we use a uint32_t */
> +    val = pstate_read(env);
> +    reg.id = AARCH64_CORE_REG(regs.pstate);
> +    reg.addr = (uintptr_t) &val;
> +    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    reg.id = AARCH64_CORE_REG(regs.pc);
> +    reg.addr = (uintptr_t) &env->pc;
> +    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    /* TODO:
> +     * SP_EL1
> +     * ELR_EL1
> +     * SPSR[]
> +     * FP state
> +     * system registers
> +     */
> +    return ret;
> +}
> +
> +int kvm_arch_get_registers(CPUState *cs)
> +{
> +    struct kvm_one_reg reg;
> +    uint64_t val;
> +    int i;
> +    int ret;
> +
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +
> +    for (i = 0; i < 31; i++) {
> +        reg.id = AARCH64_CORE_REG(regs.regs[i]);
> +        reg.addr = (uintptr_t) &env->xregs[i];
> +        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    reg.id = AARCH64_CORE_REG(regs.sp);
> +    reg.addr = (uintptr_t) &env->xregs[31];
> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    reg.id = AARCH64_CORE_REG(regs.pstate);
> +    reg.addr = (uintptr_t) &val;
> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +    pstate_write(env, val);
> +
> +    reg.id = AARCH64_CORE_REG(regs.pc);
> +    reg.addr = (uintptr_t) &env->pc;
> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    /* TODO: other registers */
> +    return ret;
> +}
> +
> +void kvm_arch_reset_vcpu(CPUState *cs)
> +{
> +}
> -- 
> 1.7.9.5
> 
> _______________________________________________
> kvmarm mailing list
> address@hidden
> https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm



reply via email to

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