hv: Support WAITPKG instructions in guest VM

TPAUSE, UMONITOR or UMWAIT instructions execution in guest VM cause
a #UD if "enable user wait and pause" (bit 26) of VMX_PROCBASED_CTLS2
is not set. To fix this issue, set the bit 26 of VMX_PROCBASED_CTLS2.

Besides, these WAITPKG instructions uses MSR_IA32_UMWAIT_CONTROL. So
load corresponding vMSR value during context switch in of a vCPU.

Please note, the TPAUSE or UMWAIT instruction causes a VM exit if the
"RDTSC exiting" and "enable user wait and pause" are both 1. In ACRN
hypervisor, "RDTSC exiting" is always 0. So TPAUSE or UMWAIT doesn't
cause a VM exit.

Performance impact:
    MSR_IA32_UMWAIT_CONTROL read costs ~19 cycles;
    MSR_IA32_UMWAIT_CONTROL write costs ~63 cycles.

Tracked-On: #6006
Signed-off-by: Shuo A Liu <shuo.a.liu@intel.com>
This commit is contained in:
Shuo A Liu 2021-05-11 18:54:14 +08:00 committed by wenlingz
parent ebadf00de8
commit 3fffa68665
7 changed files with 36 additions and 2 deletions

View File

@ -857,6 +857,7 @@ static void context_switch_in(struct thread_object *next)
{
struct acrn_vcpu *vcpu = container_of(next, struct acrn_vcpu, thread_obj);
struct ext_context *ectx = &(vcpu->arch.contexts[vcpu->arch.cur_context].ext_ctx);
uint64_t vmsr_val;
load_vmcs(vcpu);
@ -866,6 +867,13 @@ static void context_switch_in(struct thread_object *next)
msr_write(MSR_IA32_FMASK, ectx->ia32_fmask);
msr_write(MSR_IA32_KERNEL_GS_BASE, ectx->ia32_kernel_gs_base);
if (pcpu_has_cap(X86_FEATURE_WAITPKG)) {
vmsr_val = vcpu_get_guest_msr(vcpu, MSR_IA32_UMWAIT_CONTROL);
if (vmsr_val != msr_read(MSR_IA32_UMWAIT_CONTROL)) {
msr_write(MSR_IA32_UMWAIT_CONTROL, vmsr_val);
}
}
load_iwkey(vcpu);
rstore_xsave_area(vcpu, ectx);

View File

@ -319,7 +319,7 @@ static void init_exec_ctrl(struct acrn_vcpu *vcpu)
value32 = check_vmx_ctrl(MSR_IA32_VMX_PROCBASED_CTLS2,
VMX_PROCBASED_CTLS2_VAPIC | VMX_PROCBASED_CTLS2_EPT |VMX_PROCBASED_CTLS2_VPID |
VMX_PROCBASED_CTLS2_RDTSCP | VMX_PROCBASED_CTLS2_UNRESTRICT |
VMX_PROCBASED_CTLS2_PAUSE_LOOP);
VMX_PROCBASED_CTLS2_PAUSE_LOOP | VMX_PROCBASED_CTLS2_UWAIT_PAUSE);
/* SDM Vol3, 25.3, setting "enable INVPCID" VM-execution to 1 with "INVLPG exiting" disabled,
* passes-through INVPCID instruction to guest if the instruction is supported.

View File

@ -16,6 +16,7 @@
#include <asm/sgx.h>
#include <asm/guest/guest_pm.h>
#include <asm/guest/ucode.h>
#include <asm/cpufeatures.h>
#include <asm/rdt.h>
#include <trace.h>
#include <logmsg.h>
@ -40,6 +41,7 @@ static const uint32_t emulated_guest_msrs[NUM_GUEST_MSRS] = {
* MSRs don't need isolation between worlds
* Number of entries: NUM_COMMON_MSRS
*/
MSR_IA32_UMWAIT_CONTROL,
MSR_IA32_TSC_DEADLINE,
MSR_IA32_BIOS_UPDT_TRIG,
MSR_IA32_BIOS_SIGN_ID,
@ -553,6 +555,16 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu)
}
break;
}
case MSR_IA32_UMWAIT_CONTROL:
{
/* Feature X86_FEATURE_WAITPKG is always presented */
if (pcpu_has_cap(X86_FEATURE_WAITPKG)) {
v = vcpu_get_guest_msr(vcpu, msr);
} else {
err = -EACCES;
}
break;
}
case MSR_TEST_CTL:
{
/* If has MSR_TEST_CTL, give emulated value
@ -905,6 +917,17 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu)
}
break;
}
case MSR_IA32_UMWAIT_CONTROL:
{
/* Feature X86_FEATURE_WAITPKG is always presented */
if (pcpu_has_cap(X86_FEATURE_WAITPKG)) {
vcpu_set_guest_msr(vcpu, msr, v);
msr_write(msr, v);
} else {
err = -EACCES;
}
break;
}
case MSR_TEST_CTL:
{
/* If VM has MSR_TEST_CTL, ignore write operation

View File

@ -80,6 +80,7 @@
#define X86_FEATURE_CLFLUSHOPT ((FEAT_7_0_EBX << 5U) + 23U)
/* Intel-defined CPU features, CPUID level 0x00000007 (ECX)*/
#define X86_FEATURE_WAITPKG ((FEAT_7_0_ECX << 5U) + 5U)
#define X86_FEATURE_KEYLOCKER ((FEAT_7_0_ECX << 5U) + 23U)
/* Intel-defined CPU features, CPUID level 0x00000007 (EDX)*/

View File

@ -171,7 +171,7 @@ enum reset_mode;
#define SECURE_WORLD 1
#define NUM_WORLD_MSRS 2U
#define NUM_COMMON_MSRS 21U
#define NUM_COMMON_MSRS 22U
#define NUM_GUEST_MSRS (NUM_WORLD_MSRS + NUM_COMMON_MSRS)
#define EOI_EXIT_BITMAP_SIZE 256U

View File

@ -42,6 +42,7 @@
#define MSR_IA32_PMC6 0x000000C7U
#define MSR_IA32_PMC7 0x000000C8U
#define MSR_IA32_CORE_CAPABILITIES 0x000000CFU
#define MSR_IA32_UMWAIT_CONTROL 0x000000E1U
/* Max. qualified performance clock counter */
#define MSR_IA32_MPERF 0x000000E7U
/* Actual performance clock counter */

View File

@ -317,6 +317,7 @@
#define VMX_PROCBASED_CTLS2_RDSEED (1U<<16U)
#define VMX_PROCBASED_CTLS2_EPT_VE (1U<<18U)
#define VMX_PROCBASED_CTLS2_XSVE_XRSTR (1U<<20U)
#define VMX_PROCBASED_CTLS2_UWAIT_PAUSE (1U<<26U)
#define VMX_PROCBASED_CTLS3_LOADIWKEY (1U<<0U)
/* MSR_IA32_VMX_EPT_VPID_CAP: EPT and VPID capability bits */