From patchwork Tue Dec 17 20:28:39 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 302494 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42DFB2C00B8 for ; Wed, 18 Dec 2013 08:08:29 +1100 (EST) Received: from localhost ([::1]:35468 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vt1sQ-0004gb-8d for incoming@patchwork.ozlabs.org; Tue, 17 Dec 2013 16:08:26 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59316) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vt1i2-00026Z-Qx for qemu-devel@nongnu.org; Tue, 17 Dec 2013 15:57:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Vt1i0-00038W-Ro for qemu-devel@nongnu.org; Tue, 17 Dec 2013 15:57:42 -0500 Received: from mnementh.archaic.org.uk ([2001:8b0:1d0::1]:43648) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vt1i0-0002q7-JQ for qemu-devel@nongnu.org; Tue, 17 Dec 2013 15:57:40 -0500 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1Vt1Gb-0003EV-M9; Tue, 17 Dec 2013 20:29:21 +0000 From: Peter Maydell To: Anthony Liguori Date: Tue, 17 Dec 2013 20:28:39 +0000 Message-Id: <1387312160-12318-22-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1387312160-12318-1-git-send-email-peter.maydell@linaro.org> References: <1387312160-12318-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:8b0:1d0::1 Cc: Blue Swirl , qemu-devel@nongnu.org, Aurelien Jarno Subject: [Qemu-devel] [PULL 21/62] target-arm: Add minimal KVM AArch64 support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: "Mian M. Hamayun" 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 Signed-off-by: Peter Maydell Message-id: 1385645602-18662-4-git-send-email-peter.maydell@linaro.org [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 Reviewed-by: Christoffer Dall --- 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 869ecd0..190499f 100644 --- a/target-arm/Makefile.objs +++ b/target-arm/Makefile.objs @@ -2,6 +2,7 @@ obj-y += arm-semi.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o +obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-y += translate.o op_helper.o helper.o cpu.o obj-y += neon_helper.o iwmmxt_helper.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..1b7ca90 --- /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 +#include +#include +#include + +#include + +#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-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. + */ + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + if (ret) { + return ret; + } + + /* TODO: other registers */ + return ret; +} + +void kvm_arch_reset_vcpu(CPUState *cs) +{ +}