aboutsummaryrefslogtreecommitdiff
path: root/target/arm/hvf/hvf.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/hvf/hvf.c')
-rw-r--r--target/arm/hvf/hvf.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 110a9d547d..51b7250612 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -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)
{
}