From 6a430de8147a60edf2b43c809f83d64ed507b4ea Mon Sep 17 00:00:00 2001 From: Wu Zhou Date: Fri, 2 Sep 2022 19:53:34 +0800 Subject: [PATCH] hv: remove CPU frequency control from guests The design of ACRN CPU performance management is to let hardware do the autonomous frequency selection(or set to a fixed value), and remove guest's ability to control CPU frequency. This patch is to remove guest's ability to control CPU frequency by removing the guests' HWP/EIST CPUIDs and blocking the related MSR accesses. Including: - Remove CPUID.06H:EAX[7..11] (HWP) - Remove CPUID.01H:ECX[7] (EIST) - Inject #GP(0) upon accesses to MSR_IA32_PM_ENABLE, MSR_IA32_HWP_CAPABILITIES, MSR_IA32_HWP_REQUEST, MSR_IA32_HWP_STATUS, MSR_IA32_HWP_INTERRUPT, MSR_IA32_HWP_REQUEST_PKG - Emulate MSR_IA32_PERF_CTL. Value written to MSR_IA32_PERF_CTL is just stored for reading. This is like how the native environment would behavior when EIST is disabled from BIOS. - Emulate MSR_IA32_PERF_STATUS by filling it with base frequency state. This is consistent with Windows, which displays current frequency as base frequency when running in VM. - Hide the IA32_MISC_ENABLE bit 16 (EIST enable) from guests. This bit is dependent to CPUID.01H:ECX[7] according to SDM. - Remove CPID.06H:ECX[0] (hardware coordination feedback) - Inject #GP(0) upon accesses to IA32_MPERF, IA32_APERF Also DM do not need to generate _PSS/_PPC for post-launched VMs anymore. This is done by letting hypercall HC_PM_GET_CPU_STATE sub command ACRN_PMCMD_GET_PX_CNT and ACRN_PMCMD_GET_PX_DATA return (-1). Tracked-On: #8168 Signed-off-by: Wu Zhou Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vcpuid.c | 9 +++ hypervisor/arch/x86/guest/vmcs.c | 2 + hypervisor/arch/x86/guest/vmsr.c | 62 ++++++++++++++++++-- hypervisor/common/hypercall.c | 14 +++++ hypervisor/include/arch/x86/asm/cpuid.h | 12 ++++ hypervisor/include/arch/x86/asm/guest/vcpu.h | 2 +- hypervisor/include/arch/x86/asm/msr.h | 2 +- 7 files changed, 96 insertions(+), 7 deletions(-) diff --git a/hypervisor/arch/x86/guest/vcpuid.c b/hypervisor/arch/x86/guest/vcpuid.c index 580098719..f5c3c5867 100644 --- a/hypervisor/arch/x86/guest/vcpuid.c +++ b/hypervisor/arch/x86/guest/vcpuid.c @@ -115,6 +115,13 @@ static void init_vcpuid_entry(uint32_t leaf, uint32_t subleaf, entry->flags = flags; switch (leaf) { + + case 0x06U: + cpuid_subleaf(leaf, subleaf, &entry->eax, &entry->ebx, &entry->ecx, &entry->edx); + entry->eax &= ~(CPUID_EAX_HWP | CPUID_EAX_HWP_N | CPUID_EAX_HWP_AW | CPUID_EAX_HWP_EPP | CPUID_EAX_HWP_PLR); + entry->ecx &= ~CPUID_ECX_HCFC; + break; + case 0x07U: if (subleaf == 0U) { uint64_t cr4_reserved_mask = get_cr4_reserved_bits(); @@ -627,6 +634,8 @@ static void guest_cpuid_01h(struct acrn_vcpu *vcpu, uint32_t *eax, uint32_t *ebx /* mask Safer Mode Extension */ *ecx &= ~CPUID_ECX_SMX; + *ecx &= ~CPUID_ECX_EST; + /* mask SDBG for silicon debug */ *ecx &= ~CPUID_ECX_SDBG; diff --git a/hypervisor/arch/x86/guest/vmcs.c b/hypervisor/arch/x86/guest/vmcs.c index 684507d7d..9c6c06214 100644 --- a/hypervisor/arch/x86/guest/vmcs.c +++ b/hypervisor/arch/x86/guest/vmcs.c @@ -55,6 +55,8 @@ static void init_guest_vmx(struct acrn_vcpu *vcpu, uint64_t cr0, uint64_t cr3, /* init guest ia32_misc_enable value for guest read */ vcpu_set_guest_msr(vcpu, MSR_IA32_MISC_ENABLE, msr_read(MSR_IA32_MISC_ENABLE)); + vcpu_set_guest_msr(vcpu, MSR_IA32_PERF_CTL, msr_read(MSR_IA32_PERF_CTL)); + /* fixed values */ exec_vmwrite32(VMX_GUEST_IA32_SYSENTER_CS, 0U); exec_vmwrite(VMX_GUEST_IA32_SYSENTER_ESP, 0UL); diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index 6509d34b0..840e1dfcb 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -51,6 +51,7 @@ static uint32_t emulated_guest_msrs[NUM_EMULATED_MSRS] = { MSR_IA32_BIOS_SIGN_ID, MSR_IA32_TIME_STAMP_COUNTER, MSR_IA32_APIC_BASE, + MSR_IA32_PERF_STATUS, MSR_IA32_PERF_CTL, MSR_IA32_FEATURE_CONTROL, @@ -256,6 +257,29 @@ static const uint32_t unsupported_msrs[] = { MSR_IA32_PL2_SSP, MSR_IA32_PL3_SSP, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR, + + /* HWP disabled: + * CPUID.06H.EAX[7] + * CPUID.06H.EAX[9] + * CPUID.06H:EAX[10] + */ + MSR_IA32_PM_ENABLE, + MSR_IA32_HWP_CAPABILITIES, + MSR_IA32_HWP_REQUEST, + MSR_IA32_HWP_STATUS, + /* HWP_Notification disabled: + * CPUID.06H:EAX[8] + */ + MSR_IA32_HWP_INTERRUPT, + /* HWP_package_level disabled: + * CPUID.06H:EAX[11] + */ + MSR_IA32_HWP_REQUEST_PKG, + /* Hardware Coordination Feedback Capability disabled: + * CPUID.06H:ECX[0] + */ + MSR_IA32_MPERF, + MSR_IA32_APERF, }; /* emulated_guest_msrs[] shares same indexes with array vcpu->arch->guest_msrs[] */ @@ -550,6 +574,26 @@ static int32_t write_pat_msr(struct acrn_vcpu *vcpu, uint64_t value) return ret; } +/* + * @brief get emulated IA32_PERF_STATUS reg value + * + * Use the base frequency state of pCPU as the emulated reg field: + * - IA32_PERF_STATUS[15:0] Current performance State Value + * + * Assuming (base frequency ratio << 8) is a valid state value for all CPU models. + */ +static uint64_t get_perf_status(void) +{ + uint32_t eax, ecx, unused; + /* + * CPUID.16H:eax[15:0] Base CPU Frequency (MHz) + * CPUID.16H:ecx[15:0] Bus Frequency (MHz) + * ratio = CPU_frequency/bus_frequency + */ + cpuid_subleaf(0x16U, 0U, &eax, &unused, &ecx, &unused); + return (uint64_t)(((eax/ecx) & 0xFFU) << 8); +} + /** * @pre vcpu != NULL */ @@ -624,9 +668,14 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu) v = get_microcode_version(); break; } + case MSR_IA32_PERF_STATUS: + { + v = get_perf_status(); + break; + } case MSR_IA32_PERF_CTL: { - v = msr_read(msr); + v = vcpu_get_guest_msr(vcpu, MSR_IA32_PERF_CTL); break; } case MSR_IA32_PAT: @@ -664,6 +713,8 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu) case MSR_IA32_MISC_ENABLE: { v = vcpu_get_guest_msr(vcpu, MSR_IA32_MISC_ENABLE); + /* As CPUID.01H:ECX[7] is removed from guests, guests should not see EIST enable bit. */ + v &= ~MSR_IA32_MISC_ENABLE_EIST; break; } case MSR_IA32_SGXLEPUBKEYHASH0: @@ -999,12 +1050,13 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu) } break; } + case MSR_IA32_PERF_STATUS: + { + break; + } case MSR_IA32_PERF_CTL: { - if (validate_pstate(vcpu->vm, v) != 0) { - break; - } - msr_write(msr, v); + vcpu_set_guest_msr(vcpu, MSR_IA32_PERF_CTL, v); break; } case MSR_IA32_PAT: diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index e27eaf7e5..9d2ed892a 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -1027,6 +1027,12 @@ int32_t hcall_reset_ptdev_intr_info(struct acrn_vcpu *vcpu, struct acrn_vm *targ return ret; } +static bool is_pt_pstate(__unused const struct acrn_vm *vm) +{ + /* Currently VM's CPU frequency is managed in hypervisor. So no pass through for all VMs. */ + return false; +} + /** * @brief Get VCPU Power state. * @@ -1047,6 +1053,10 @@ int32_t hcall_get_cpu_pm_state(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm if (is_created_vm(target_vm)) { switch (cmd & PMCMD_TYPE_MASK) { case ACRN_PMCMD_GET_PX_CNT: { + if (!is_pt_pstate(target_vm)) { + break; + } + ret = copy_to_gpa(vm, &(target_vm->pm.px_cnt), param2, sizeof(target_vm->pm.px_cnt)); break; } @@ -1054,6 +1064,10 @@ int32_t hcall_get_cpu_pm_state(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm uint8_t pn; struct acrn_pstate_data *px_data; + if (!is_pt_pstate(target_vm)) { + break; + } + /* For now we put px data as per-vm, * If it is stored as per-cpu in the future, * we need to check PMCMD_VCPUID_MASK in cmd. diff --git a/hypervisor/include/arch/x86/asm/cpuid.h b/hypervisor/include/arch/x86/asm/cpuid.h index 491758bab..7f41a10c2 100644 --- a/hypervisor/include/arch/x86/asm/cpuid.h +++ b/hypervisor/include/arch/x86/asm/cpuid.h @@ -72,6 +72,18 @@ #define CPUID_EDX_TM1 (1U<<29U) #define CPUID_EDX_IA64 (1U<<30U) #define CPUID_EDX_PBE (1U<<31U) +/* CPUID.06H:EAX.HWP */ +#define CPUID_EAX_HWP (1U<<7U) +/* CPUID.06H:EAX.HWP_Notification */ +#define CPUID_EAX_HWP_N (1U<<8U) +/* CPUID.06H:EAX.HWP_Activity_Window */ +#define CPUID_EAX_HWP_AW (1U<<9U) +/* CPUID.06H:EAX.HWP_Energy_Performance_Preference */ +#define CPUID_EAX_HWP_EPP (1U<<10U) +/* CPUID.06H:EAX.HWP_Package_Level_Request */ +#define CPUID_EAX_HWP_PLR (1U<<11U) +/* CPUID.06H:ECX.Hardware_Coordination_Feedback_Capability */ +#define CPUID_ECX_HCFC (1U<<0U) /* CPUID.07H:EBX.FSGSBASE*/ #define CPUID_EBX_FSGSBASE (1U<<0U) /* CPUID.07H:EBX.TSC_ADJUST*/ diff --git a/hypervisor/include/arch/x86/asm/guest/vcpu.h b/hypervisor/include/arch/x86/asm/guest/vcpu.h index 87f6930a6..95527e432 100644 --- a/hypervisor/include/arch/x86/asm/guest/vcpu.h +++ b/hypervisor/include/arch/x86/asm/guest/vcpu.h @@ -173,7 +173,7 @@ enum reset_mode; #define SECURE_WORLD 1 #define NUM_WORLD_MSRS 2U -#define NUM_COMMON_MSRS 23U +#define NUM_COMMON_MSRS 24U #ifdef CONFIG_VCAT_ENABLED #define NUM_CAT_L2_MSRS MAX_CACHE_CLOS_NUM_ENTRIES diff --git a/hypervisor/include/arch/x86/asm/msr.h b/hypervisor/include/arch/x86/asm/msr.h index da82c7c3e..44ed375ff 100644 --- a/hypervisor/include/arch/x86/asm/msr.h +++ b/hypervisor/include/arch/x86/asm/msr.h @@ -575,7 +575,7 @@ #define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1UL << 11U) #define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1UL << 12U) #define MSR_IA32_MISC_ENABLE_TM2_ENABLE (1UL << 13U) -#define MSR_IA32_MISC_ENABLE_EITS (1UL << 16U) +#define MSR_IA32_MISC_ENABLE_EIST (1UL << 16U) #define MSR_IA32_MISC_ENABLE_MONITOR_ENA (1UL << 18U) #define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1UL << 22U) #define MSR_IA32_MISC_ENABLE_xTPR (1UL << 23U)