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 <wu.zhou@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Wu Zhou 2022-09-02 19:53:34 +08:00 committed by acrnsi-robot
parent f0eddc6a4c
commit 6a430de814
7 changed files with 96 additions and 7 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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.

View File

@ -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*/

View File

@ -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

View File

@ -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)