From patchwork Tue Aug 13 18:03:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 19094 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-yh0-f70.google.com (mail-yh0-f70.google.com [209.85.213.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 8C118246B8 for ; Tue, 13 Aug 2013 18:03:09 +0000 (UTC) Received: by mail-yh0-f70.google.com with SMTP id l109sf9816466yhq.5 for ; Tue, 13 Aug 2013 11:03:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-gm-message-state:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=q4obes/WCVlJil81YJsRQ5xKskU1XYejYUsXJthC5Ww=; b=GMTZVpdPc+GiSaOaWNht4G0wxx3LNmR6J2LvtasUURyMAOLSNrgru08PH4tnt8R4/1 RLGeI+8+su1FjYEXeSK81VFoQi+14GjkS4C9ugQlN21uB+D20vah8WacPWTzJr/vVhy+ tGzNc1/iOrd+dn+3Udt2mXkU2sdNqGv1TOYqvqJ8trK1Tmp71BYF801poVTFFG3H6qb4 EBOWBWvhRhlD3P+WWCoCW6ixBh8uSgdNBeD6M5wZgXjhBcsGYWAai7msNUxLF7l+Epyy Uu5W8g1+NJ6iTFN0veH8Q4ARBbMeeNf0AdgMtYn67oZIQNFdO3MlEzx7kJP6aJJE9O0N gK6g== X-Received: by 10.236.126.244 with SMTP id b80mr2133012yhi.31.1376416988781; Tue, 13 Aug 2013 11:03:08 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.11.230 with SMTP id t6ls219921qeb.33.gmail; Tue, 13 Aug 2013 11:03:08 -0700 (PDT) X-Received: by 10.220.76.10 with SMTP id a10mr2049342vck.31.1376416988632; Tue, 13 Aug 2013 11:03:08 -0700 (PDT) Received: from mail-vb0-f43.google.com (mail-vb0-f43.google.com [209.85.212.43]) by mx.google.com with ESMTPS id vf5si10014653vdc.44.2013.08.13.11.03.08 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 13 Aug 2013 11:03:08 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.43 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.43; Received: by mail-vb0-f43.google.com with SMTP id h11so6853972vbh.2 for ; Tue, 13 Aug 2013 11:03:08 -0700 (PDT) X-Gm-Message-State: ALoCoQmzjbyDBwi0TsWT/SceblxQrdjkL/tscrdXGlGuk+lQ1fnmwe9kKu3V/I5m7YDQxK2//GqQ X-Received: by 10.220.110.202 with SMTP id o10mr5414629vcp.1.1376416988527; Tue, 13 Aug 2013 11:03:08 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp167823vcz; Tue, 13 Aug 2013 11:03:07 -0700 (PDT) X-Received: by 10.180.20.105 with SMTP id m9mr174272wie.44.1376416987247; Tue, 13 Aug 2013 11:03:07 -0700 (PDT) Received: from mnementh.archaic.org.uk (1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.1.0.0.b.8.0.1.0.0.2.ip6.arpa. [2001:8b0:1d0::1]) by mx.google.com with ESMTPS id t3si1343555wiw.73.2013.08.13.11.03.06 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 13 Aug 2013 11:03:07 -0700 (PDT) Received-SPF: neutral (google.com: 2001:8b0:1d0::1 is neither permitted nor denied by best guess record for domain of pm215@archaic.org.uk) client-ip=2001:8b0:1d0::1; Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1V9Ivv-00081z-Is; Tue, 13 Aug 2013 19:03:03 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, kvmarm@lists.cs.columbia.edu, =?UTF-8?q?Andreas=20F=C3=A4rber?= Subject: [RFC 2/2] target-arm: Provide '-cpu host' when running KVM Date: Tue, 13 Aug 2013 19:03:03 +0100 Message-Id: <1376416983-30838-3-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1376416983-30838-1-git-send-email-peter.maydell@linaro.org> References: <1376416983-30838-1-git-send-email-peter.maydell@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.43 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Implement '-cpu host' for ARM when we're using KVM, broadly in line with other KVM-supporting architectures. Signed-off-by: Peter Maydell --- 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;