mirror of
https://github.com/qemu/qemu.git
synced 2026-04-13 17:52:25 +00:00
whpx: arm64: implement -cpu host
Logic to fetch MIDR_EL1 for cpu 0 adapted from:
e6de17e72e/Source/Windows/Common/CPUFeatures.cpp (L62)
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
committed by
Peter Maydell
parent
293984563e
commit
f7fa2b8808
@@ -26,10 +26,13 @@
|
||||
#include "qemu/units.h"
|
||||
#include "system/kvm.h"
|
||||
#include "system/hvf.h"
|
||||
#include "system/whpx.h"
|
||||
#include "system/hw_accel.h"
|
||||
#include "system/qtest.h"
|
||||
#include "system/tcg.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "hvf_arm.h"
|
||||
#include "whpx_arm.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "hw/core/qdev-properties.h"
|
||||
#include "internals.h"
|
||||
@@ -521,7 +524,7 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
|
||||
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, 0);
|
||||
isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 0);
|
||||
|
||||
if (kvm_enabled() || hvf_enabled()) {
|
||||
if (hwaccel_enabled()) {
|
||||
/*
|
||||
* Exit early if PAuth is enabled and fall through to disable it.
|
||||
* The algorithm selection properties are not present.
|
||||
@@ -598,10 +601,10 @@ void aarch64_add_pauth_properties(Object *obj)
|
||||
|
||||
/* Default to PAUTH on, with the architected algorithm on TCG. */
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property);
|
||||
if (kvm_enabled() || hvf_enabled()) {
|
||||
if (hwaccel_enabled()) {
|
||||
/*
|
||||
* Mirror PAuth support from the probed sysregs back into the
|
||||
* property for KVM or hvf. Is it just a bit backward? Yes it is!
|
||||
* property for HW accel. Is it just a bit backward? Yes it is!
|
||||
* Note that prop_pauth is true whether the host CPU supports the
|
||||
* architected QARMA5 algorithm or the IMPDEF one. We don't
|
||||
* provide the separate pauth-impdef property for KVM or hvf,
|
||||
@@ -769,6 +772,8 @@ static void aarch64_host_initfn(Object *obj)
|
||||
}
|
||||
#elif defined(CONFIG_HVF)
|
||||
hvf_arm_set_cpu_features_from_host(cpu);
|
||||
#elif defined(CONFIG_WHPX)
|
||||
whpx_arm_set_cpu_features_from_host(cpu);
|
||||
#else
|
||||
g_assert_not_reached();
|
||||
#endif
|
||||
@@ -779,8 +784,8 @@ static void aarch64_host_initfn(Object *obj)
|
||||
|
||||
static void aarch64_max_initfn(Object *obj)
|
||||
{
|
||||
if (kvm_enabled() || hvf_enabled()) {
|
||||
/* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
|
||||
if (hwaccel_enabled()) {
|
||||
/* When hardware acceleration enabled, '-cpu max' is identical to '-cpu host' */
|
||||
aarch64_host_initfn(obj);
|
||||
return;
|
||||
}
|
||||
@@ -799,7 +804,7 @@ static const ARMCPUInfo aarch64_cpus[] = {
|
||||
{ .name = "cortex-a57", .initfn = aarch64_a57_initfn },
|
||||
{ .name = "cortex-a53", .initfn = aarch64_a53_initfn },
|
||||
{ .name = "max", .initfn = aarch64_max_initfn },
|
||||
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
|
||||
#if defined(CONFIG_KVM) || defined(CONFIG_HVF) || defined(CONFIG_WHPX)
|
||||
{ .name = "host", .initfn = aarch64_host_initfn },
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
#include "target/arm/cpu-qom.h"
|
||||
|
||||
uint32_t whpx_arm_get_ipa_bit_size(void);
|
||||
void whpx_arm_set_cpu_features_from_host(ARMCPU *cpu);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user