@@ -39,6 +39,7 @@
#include "sysemu/tcg.h"
#include "sysemu/hw_accel.h"
#include "kvm_arm.h"
+#include "hvf_arm.h"
#include "disas/capstone.h"
#include "fpu/softfloat.h"
@@ -1400,8 +1401,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
* 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");
+ if (!kvm_enabled() && !hvf_enabled()) {
+ error_setg(errp, "The 'host' CPU type can only be used with KVM or HVF");
} else {
error_setg(errp, "Failed to retrieve host CPU features");
}
@@ -2061,15 +2062,19 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
#endif /* CONFIG_TCG */
}
-#ifdef CONFIG_KVM
+#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
static void arm_host_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+#ifdef CONFIG_KVM
kvm_arm_set_cpu_features_from_host(cpu);
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
aarch64_add_sve_properties(obj);
}
+#else
+ hvf_arm_set_cpu_features_from_host(cpu);
+#endif
arm_cpu_post_init(obj);
}
@@ -2129,7 +2134,7 @@ static void arm_cpu_register_types(void)
{
type_register_static(&arm_cpu_type_info);
-#ifdef CONFIG_KVM
+#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
type_register_static(&host_arm_cpu_type_info);
#endif
}
@@ -3015,6 +3015,8 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
#define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
#define CPU_RESOLVING_TYPE TYPE_ARM_CPU
+#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
+
#define cpu_signal_handler cpu_arm_signal_handler
#define cpu_list arm_cpu_list
@@ -17,6 +17,7 @@
#include "sysemu/hvf.h"
#include "sysemu/hvf_int.h"
#include "sysemu/hw_accel.h"
+#include "hvf_arm.h"
#include <mach/mach_time.h>
@@ -54,6 +55,16 @@ typedef struct HVFVTimer {
static HVFVTimer vtimer;
+typedef struct ARMHostCPUFeatures {
+ ARMISARegisters isar;
+ uint64_t features;
+ uint64_t midr;
+ uint32_t reset_sctlr;
+ const char *dtb_compatible;
+} ARMHostCPUFeatures;
+
+static ARMHostCPUFeatures arm_host_cpu_features;
+
struct hvf_reg_match {
int reg;
uint64_t offset;
@@ -416,6 +427,90 @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt)
return val;
}
+static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+{
+ ARMISARegisters host_isar = {};
+ const struct isar_regs {
+ int reg;
+ uint64_t *val;
+ } regs[] = {
+ { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.id_aa64pfr0 },
+ { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.id_aa64pfr1 },
+ { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 },
+ { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 },
+ { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.id_aa64isar0 },
+ { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.id_aa64isar1 },
+ { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.id_aa64mmfr0 },
+ { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.id_aa64mmfr1 },
+ { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.id_aa64mmfr2 },
+ };
+ hv_vcpu_t fd;
+ hv_return_t r = HV_SUCCESS;
+ hv_vcpu_exit_t *exit;
+ int i;
+
+ ahcf->dtb_compatible = "arm,arm-v8";
+ ahcf->features = (1ULL << ARM_FEATURE_V8) |
+ (1ULL << ARM_FEATURE_NEON) |
+ (1ULL << ARM_FEATURE_AARCH64) |
+ (1ULL << ARM_FEATURE_PMU) |
+ (1ULL << ARM_FEATURE_GENERIC_TIMER);
+
+ /* We set up a small vcpu to extract host registers */
+
+ if (hv_vcpu_create(&fd, &exit, NULL) != HV_SUCCESS) {
+ return false;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, regs[i].val);
+ }
+ r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &ahcf->midr);
+ r |= hv_vcpu_destroy(fd);
+
+ ahcf->isar = host_isar;
+
+ /*
+ * A scratch vCPU returns SCTLR 0, so let's fill our default with the M1
+ * boot SCTLR from https://github.com/AsahiLinux/m1n1/issues/97
+ */
+ ahcf->reset_sctlr = 0x30100180;
+ /*
+ * SPAN is disabled by default when SCTLR.SPAN=1. To improve compatibility,
+ * let's disable it on boot and then allow guest software to turn it on by
+ * setting it to 0.
+ */
+ ahcf->reset_sctlr |= 0x00800000;
+
+ /* Make sure we don't advertise AArch32 support for EL0/EL1 */
+ if ((host_isar.id_aa64pfr0 & 0xff) != 0x11) {
+ return false;
+ }
+
+ return r == HV_SUCCESS;
+}
+
+void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu)
+{
+ if (!arm_host_cpu_features.dtb_compatible) {
+ if (!hvf_enabled() ||
+ !hvf_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->host_cpu_probe_failed = true;
+ return;
+ }
+ }
+
+ cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
+ cpu->isar = arm_host_cpu_features.isar;
+ cpu->env.features = arm_host_cpu_features.features;
+ cpu->midr = arm_host_cpu_features.midr;
+ cpu->reset_sctlr = arm_host_cpu_features.reset_sctlr;
+}
+
void hvf_arch_vcpu_destroy(CPUState *cpu)
{
}
new file mode 100644
@@ -0,0 +1,19 @@
+/*
+ * QEMU Hypervisor.framework (HVF) support -- ARM specifics
+ *
+ * Copyright (c) 2021 Alexander Graf
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_HVF_ARM_H
+#define QEMU_HVF_ARM_H
+
+#include "qemu/accel.h"
+#include "cpu.h"
+
+void hvf_arm_set_cpu_features_from_host(struct ARMCPU *cpu);
+
+#endif
@@ -214,8 +214,6 @@ 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
-
/**
* ARMHostCPUFeatures: information about the host CPU (identified
* by asking the host kernel)