From patchwork Fri Mar 9 17:26:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 131203 Delivered-To: patch@linaro.org Received: by 10.46.66.2 with SMTP id p2csp1292029lja; Fri, 9 Mar 2018 10:08:38 -0800 (PST) X-Google-Smtp-Source: AG47ELvuu/3x/mkqQm2vgJuJX/RrGzQG2cOW6aGkNfQh5JfIDxyyLaD1RMJFmgqlEmNuzy4MxBnP X-Received: by 10.129.235.3 with SMTP id n3mr19866067ywm.472.1520618918681; Fri, 09 Mar 2018 10:08:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520618918; cv=none; d=google.com; s=arc-20160816; b=U/+ITxFOSOTYitZqVH5ClYxW2YjH4P5EKEJm96WcZAfwT/6IeTjaezYDzSbsKk3uq+ 1rjtplcwHsl4F8C00G2XDDwej7HkbPVKV2v7E5/zoXiVs7htFOWCIXmbuAiNfrr477CW pgueBQYeIIkk4M5hy199uxzlPRW3i9h/y72jve4JAF1KnSLZ9PoZFwvAGQ2yF6ek0/Wt ir3xZeTJZWLUeloXd1Keu159WVI/JupDD9gRXG1inuE9zXFQVaxlyh5UriNgktadwVik dWJxnwjF0jKLyCWlBqhso4aF9PNc56WZVQCB0GsIgLODP60cItxiV6XC/74keVk3Pv3O D7vA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:to:from:arc-authentication-results; bh=GNUuaVeg+DuyJ/HtvbmRNuMaCQlPeCPoYv7KGo1Urfs=; b=JfjzLb0mB4KT//RR3UmM0+kkMqaUcuBFnEXmnn5I4YreKoM//Deg0kzNDcNn8aWpGe MlOMbrwfKnV8e7NLRO+nAp4DHWm8s6SdCwdIcbXxXVj2TJTebsKU/kH04LnM0NYAdqhj YisJPvBx8tFHmO9jElE/tmf07Q0FPXIs23zgWMtIHb9+c/3M5s6/HPH+FKOyD/U5kO0L ibWykDU9x3sTFfyfancK2RLbqDoRCYBRzLBUQYiB74OeWlfg63aFfNz00aLjXsEsOIIu TIPtAXDdml7i2NgRw5w63fryMRmRQecESfpPegrEzQKwP0jW9ZVvdA/TA5f27U5VHHjK yxpg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id z13si268576ywz.7.2018.03.09.10.08.38 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 09 Mar 2018 10:08:38 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:47118 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1euMRa-0001gW-21 for patch@linaro.org; Fri, 09 Mar 2018 13:08:38 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59587) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1euLmt-0008PY-A7 for qemu-devel@nongnu.org; Fri, 09 Mar 2018 12:26:38 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1euLmr-00065B-Qu for qemu-devel@nongnu.org; Fri, 09 Mar 2018 12:26:35 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:47000) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1euLmr-00064P-Fj for qemu-devel@nongnu.org; Fri, 09 Mar 2018 12:26:33 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1euLmq-00076i-Gp for qemu-devel@nongnu.org; Fri, 09 Mar 2018 17:26:32 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Date: Fri, 9 Mar 2018 17:26:11 +0000 Message-Id: <20180309172622.4277-15-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180309172622.4277-1-peter.maydell@linaro.org> References: <20180309172622.4277-1-peter.maydell@linaro.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PULL 14/25] target/arm: Query host CPU features on-demand at instance init X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Currently we query the host CPU features in the class init function for the TYPE_ARM_HOST_CPU class, so that we can later copy them from the class object into the instance object in the object instance init function. This is awkward for implementing "-cpu max", which should work like "-cpu host" for KVM but like "cpu with all implemented features" for TCG. Move the place where we store the information about the host CPU from a class object to static variables in kvm.c, and then in the instance init function call a new kvm_arm_set_cpu_features_from_host() function which will query the host kernel if necessary and then fill in the CPU instance fields. This allows us to drop the special class struct and class init function for TYPE_ARM_HOST_CPU entirely. We can't delay the probe until realize, because the ARM instance_post_init hook needs to look at the feature bits we set, so we need to do it in the initfn. This is safe because the probing doesn't affect the actual VM state (it creates a separate scratch VM to do its testing), but the probe might fail. Because we can't report errors in retrieving the host features in the initfn, we check this belatedly in the realize function (the intervening code will be able to cope with the relevant fields in the CPU structure being zero). Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-id: 20180308130626.12393-2-peter.maydell@linaro.org --- target/arm/cpu.h | 5 +++++ target/arm/kvm_arm.h | 35 ++++++++++++++++++++++++----------- target/arm/cpu.c | 13 +++++++++++++ target/arm/kvm.c | 36 +++++++++++++++++++----------------- target/arm/kvm32.c | 8 ++++---- target/arm/kvm64.c | 8 ++++---- 6 files changed, 69 insertions(+), 36 deletions(-) -- 2.16.2 diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 36711cdb50..1e7e1f8a7e 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -745,6 +745,11 @@ struct ARMCPU { /* Uniprocessor system with MP extensions */ bool mp_is_up; + /* True if we tried kvm_arm_host_cpu_features() during CPU instance_init + * and the probe failed (so we need to report the error in realize) + */ + bool host_cpu_probe_failed; + /* Specify the number of cores in this CPU cluster. Used for the L2CTLR * register. */ diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index cfb7e5af72..1e2364007d 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -152,20 +152,16 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try, 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 >*/ +/** + * ARMHostCPUFeatures: information about the host CPU (identified + * by asking the host kernel) + */ +typedef struct ARMHostCPUFeatures { uint64_t features; uint32_t target; const char *dtb_compatible; -} ARMHostCPUClass; +} ARMHostCPUFeatures; /** * kvm_arm_get_host_cpu_features: @@ -174,8 +170,16 @@ typedef struct ARMHostCPUClass { * 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); +bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); +/** + * kvm_arm_set_cpu_features_from_host: + * @cpu: ARMCPU to set the features for + * + * Set up the ARMCPU struct fields up to match the information probed + * from the host CPU. + */ +void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); /** * kvm_arm_sync_mpstate_to_kvm @@ -200,6 +204,15 @@ void kvm_arm_pmu_init(CPUState *cs); #else +static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) +{ + /* This should never actually be called in the "not KVM" case, + * but set up the fields to indicate an error anyway. + */ + cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE; + cpu->host_cpu_probe_failed = true; +} + static inline int kvm_arm_vgic_probe(void) { return 0; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 3e4e9f1873..5809225a36 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -725,6 +725,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) int pagebits; Error *local_err = NULL; + /* If we needed to query the host kernel for the CPU features + * then it's possible that might have failed in the initfn, but + * this is the first point where we can report it. + */ + if (cpu->host_cpu_probe_failed) { + if (!kvm_enabled()) { + error_setg(errp, "The 'host' CPU type can only be used with KVM"); + } else { + error_setg(errp, "Failed to retrieve host CPU features"); + } + return; + } + cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 1219d0062b..1c0e57690a 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -33,6 +33,8 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { static bool cap_has_mp_state; +static ARMHostCPUFeatures arm_host_cpu_features; + int kvm_arm_vcpu_init(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); @@ -129,30 +131,32 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray) } } -static void kvm_arm_host_cpu_class_init(ObjectClass *oc, void *data) +void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) { - ARMHostCPUClass *ahcc = ARM_HOST_CPU_CLASS(oc); + CPUARMState *env = &cpu->env; - /* 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(); + if (!arm_host_cpu_features.dtb_compatible) { + if (!kvm_enabled() || + !kvm_arm_get_host_cpu_features(&arm_host_cpu_features)) { + /* We can't report this error yet, so flag that we need to + * in arm_cpu_realizefn(). + */ + cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE; + cpu->host_cpu_probe_failed = true; + return; + } } + + cpu->kvm_target = arm_host_cpu_features.target; + cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible; + env->features = arm_host_cpu_features.features; } 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; + kvm_arm_set_cpu_features_from_host(cpu); } static const TypeInfo host_arm_cpu_type_info = { @@ -163,8 +167,6 @@ static const TypeInfo host_arm_cpu_type_info = { .parent = TYPE_ARM_CPU, #endif .instance_init = kvm_arm_host_cpu_initfn, - .class_init = kvm_arm_host_cpu_class_init, - .class_size = sizeof(ARMHostCPUClass), }; int kvm_arch_init(MachineState *ms, KVMState *s) diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index f77c9c494b..1740cda47d 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -28,7 +28,7 @@ static inline void set_feature(uint64_t *features, int feature) *features |= 1ULL << feature; } -bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) +bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) { /* Identify the feature bits corresponding to the host CPU, and * fill out the ARMHostCPUClass fields accordingly. To do this @@ -74,13 +74,13 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) return false; } - ahcc->target = init.target; + ahcf->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"; + ahcf->dtb_compatible = "arm,arm-v7"; for (i = 0; i < ARRAY_SIZE(idregs); i++) { ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &idregs[i]); @@ -132,7 +132,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) set_feature(&features, ARM_FEATURE_VFP4); } - ahcc->features = features; + ahcf->features = features; return true; } diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index ac728494a4..e0b8246283 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -443,7 +443,7 @@ static inline void unset_feature(uint64_t *features, int feature) *features &= ~(1ULL << feature); } -bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) +bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) { /* Identify the feature bits corresponding to the host CPU, and * fill out the ARMHostCPUClass fields accordingly. To do this @@ -471,8 +471,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) return false; } - ahcc->target = init.target; - ahcc->dtb_compatible = "arm,arm-v8"; + ahcf->target = init.target; + ahcf->dtb_compatible = "arm,arm-v8"; kvm_arm_destroy_scratch_host_vcpu(fdarray); @@ -486,7 +486,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) set_feature(&features, ARM_FEATURE_AARCH64); set_feature(&features, ARM_FEATURE_PMU); - ahcc->features = features; + ahcf->features = features; return true; }