|
|
|
@ -41,6 +41,17 @@ |
|
|
|
|
|
|
|
#include <winhvplatform.h> |
|
|
|
#include <winhvplatformdefs.h> |
|
|
|
#include <winreg.h> |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
typedef struct WHPXRegMatch { |
|
|
|
WHV_REGISTER_NAME reg; |
|
|
|
@ -668,6 +679,99 @@ static void clamp_id_aa64mmfr0_parange_to_ipa_size(ARMISARegisters *isar) |
|
|
|
SET_IDREG(isar, ID_AA64MMFR0, id_aa64mmfr0); |
|
|
|
} |
|
|
|
|
|
|
|
static uint64_t whpx_read_midr(void) |
|
|
|
{ |
|
|
|
HKEY key; |
|
|
|
uint64_t midr_el1; |
|
|
|
DWORD size = sizeof(midr_el1); |
|
|
|
const char *path = "Hardware\\Description\\System\\CentralProcessor\\0\\"; |
|
|
|
assert(!RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &key)); |
|
|
|
assert(!RegGetValueA(key, NULL, "CP 4000", RRF_RT_REG_QWORD, NULL, &midr_el1, &size)); |
|
|
|
RegCloseKey(key); |
|
|
|
return midr_el1; |
|
|
|
} |
|
|
|
|
|
|
|
static bool whpx_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) |
|
|
|
{ |
|
|
|
const struct isar_regs { |
|
|
|
WHV_REGISTER_NAME reg; |
|
|
|
uint64_t *val; |
|
|
|
} regs[] = { |
|
|
|
{ WHvArm64RegisterIdAa64Pfr0El1, &ahcf->isar.idregs[ID_AA64PFR0_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Pfr1El1, &ahcf->isar.idregs[ID_AA64PFR1_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Dfr0El1, &ahcf->isar.idregs[ID_AA64DFR0_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Dfr1El1 , &ahcf->isar.idregs[ID_AA64DFR1_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Isar0El1, &ahcf->isar.idregs[ID_AA64ISAR0_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Isar1El1, &ahcf->isar.idregs[ID_AA64ISAR1_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Isar2El1, &ahcf->isar.idregs[ID_AA64ISAR2_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Mmfr0El1, &ahcf->isar.idregs[ID_AA64MMFR0_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Mmfr1El1, &ahcf->isar.idregs[ID_AA64MMFR1_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Mmfr2El1, &ahcf->isar.idregs[ID_AA64MMFR2_EL1_IDX] }, |
|
|
|
{ WHvArm64RegisterIdAa64Mmfr3El1, &ahcf->isar.idregs[ID_AA64MMFR2_EL1_IDX] } |
|
|
|
}; |
|
|
|
|
|
|
|
int i; |
|
|
|
WHV_REGISTER_VALUE val; |
|
|
|
|
|
|
|
ahcf->dtb_compatible = "arm,armv8"; |
|
|
|
ahcf->features = (1ULL << ARM_FEATURE_V8) | |
|
|
|
(1ULL << ARM_FEATURE_NEON) | |
|
|
|
(1ULL << ARM_FEATURE_AARCH64) | |
|
|
|
(1ULL << ARM_FEATURE_PMU) | |
|
|
|
(1ULL << ARM_FEATURE_GENERIC_TIMER); |
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(regs); i++) { |
|
|
|
clean_whv_register_value(&val); |
|
|
|
whpx_get_global_reg(regs[i].reg, &val); |
|
|
|
*regs[i].val = val.Reg64; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* MIDR_EL1 is not a global register on WHPX |
|
|
|
* As such, read the CPU0 from the registry to get a consistent value. |
|
|
|
* Otherwise, on heterogenous systems, you'll get variance between CPUs. |
|
|
|
*/ |
|
|
|
ahcf->midr = whpx_read_midr(); |
|
|
|
|
|
|
|
clamp_id_aa64mmfr0_parange_to_ipa_size(&ahcf->isar); |
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable SVE, which is not supported by QEMU whpx yet. |
|
|
|
* Work needed for SVE support: |
|
|
|
* - SVE state save/restore |
|
|
|
* - any potentially needed VL management |
|
|
|
* Also disable SME at the same time. (not currently supported by Hyper-V) |
|
|
|
*/ |
|
|
|
SET_IDREG(&ahcf->isar, ID_AA64PFR0, |
|
|
|
GET_IDREG(&ahcf->isar, ID_AA64PFR0) & ~R_ID_AA64PFR0_SVE_MASK); |
|
|
|
|
|
|
|
SET_IDREG(&ahcf->isar, ID_AA64PFR1, |
|
|
|
GET_IDREG(&ahcf->isar, ID_AA64PFR1) & ~R_ID_AA64PFR1_SME_MASK); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
void whpx_arm_set_cpu_features_from_host(ARMCPU *cpu) |
|
|
|
{ |
|
|
|
if (!arm_host_cpu_features.dtb_compatible) { |
|
|
|
if (!whpx_enabled() || |
|
|
|
!whpx_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; |
|
|
|
} |
|
|
|
|
|
|
|
int whpx_init_vcpu(CPUState *cpu) |
|
|
|
{ |
|
|
|
HRESULT hr; |
|
|
|
|