From a958fea7a45d51355228dd9bb04ce4579f69d43b Mon Sep 17 00:00:00 2001 From: Zide Chen Date: Mon, 17 Sep 2018 16:01:14 -0700 Subject: [PATCH] hv: emulate IA32_TSC_ADJUST MSR Intercept IA32_TSC_ADJUST MSR so that writing IA32_TSC_ADJUST from the guests won't impact the TSC in root mode or potentially other vCPUs in the same pCPU. - MSR TSC_ADJUST needs to be isolated between normal and secure world, so it's included in NUM_WORLD_MSRS. - Upon writing to either IA32_TSC_ADJUST or IA32_TSC from the guests, don't write to physical MSRS so it won't impact the host side, but update the TSC offset VM-execution control. - don't need to intercept rdmsr for IA32_TIME_STAMP_COUNTER. - add the missing statement in save_world_ctx() to save the tsc_offset during world switch. Tracked-On: #1867 Signed-off-by: Zide Chen Acked-by: Anthony Xu --- hypervisor/arch/x86/guest/vmsr.c | 62 +++++++++++++++++++++--- hypervisor/arch/x86/trusty.c | 1 + hypervisor/include/arch/x86/guest/vcpu.h | 2 +- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index 4c836e6c2..6efefa0d3 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -17,12 +17,13 @@ enum rw_mode { static const uint32_t emulated_guest_msrs[NUM_GUEST_MSRS] = { /* * MSRs that trusty may touch and need isolation between secure and normal world - * This may include MSR_IA32_TSC_ADJUST, MSR_IA32_STAR, MSR_IA32_LSTAR, MSR_IA32_FMASK, + * This may include MSR_IA32_STAR, MSR_IA32_LSTAR, MSR_IA32_FMASK, * MSR_IA32_KERNEL_GS_BASE, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_EIP * * Number of entries: NUM_WORLD_MSRS */ MSR_IA32_PAT, + MSR_IA32_TSC_ADJUST, /* * MSRs don't need isolation between worlds @@ -307,6 +308,9 @@ void init_msr_emulation(struct acrn_vcpu *vcpu) for (msr = MSR_IA32_L3_MASK_0; msr < MSR_IA32_BNDCFGS; msr++) { enable_msr_interception(msr_bitmap, msr, READ_WRITE); } + + /* don't need to intercept rdmsr for these MSRs */ + enable_msr_interception(msr_bitmap, MSR_IA32_TIME_STAMP_COUNTER, WRITE); } /* Setup MSR bitmap - Intel SDM Vol3 24.6.9 */ @@ -334,10 +338,9 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu) err = vlapic_rdmsr(vcpu, msr, &v); break; } - case MSR_IA32_TIME_STAMP_COUNTER: + case MSR_IA32_TSC_ADJUST: { - /* Add the TSC_offset to host TSC to get guest TSC */ - v = rdtsc() + exec_vmread64(VMX_TSC_OFFSET_FULL); + v = vcpu_get_guest_msr(vcpu, MSR_IA32_TSC_ADJUST); break; } case MSR_IA32_MTRR_CAP: @@ -405,6 +408,49 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu) return err; } +/* + * Intel SDM 17.17.3: If an execution of WRMSR to the + * IA32_TIME_STAMP_COUNTER MSR adds (or subtracts) value X from the + * TSC, the logical processor also adds (or subtracts) value X from + * the IA32_TSC_ADJUST MSR. + */ +static void set_guest_tsc(struct acrn_vcpu *vcpu, uint64_t guest_tsc) +{ + uint64_t tsc_delta, tsc_offset_delta, tsc_adjust; + + tsc_delta = guest_tsc - rdtsc(); + + /* the delta between new and existing TSC_OFFSET */ + tsc_offset_delta = tsc_delta - exec_vmread64(VMX_TSC_OFFSET_FULL); + + /* apply this delta to TSC_ADJUST */ + tsc_adjust = vcpu_get_guest_msr(vcpu, MSR_IA32_TSC_ADJUST); + vcpu_set_guest_msr(vcpu, MSR_IA32_TSC_ADJUST, tsc_adjust + tsc_offset_delta); + + /* write to VMCS because rdtsc and rdtscp are not intercepted */ + exec_vmwrite64(VMX_TSC_OFFSET_FULL, tsc_delta); +} + +/* + * Intel SDM 17.17.3: "If an execution of WRMSR to the IA32_TSC_ADJUST + * MSR adds (or subtracts) value X from that MSR, the logical + * processor also adds (or subtracts) value X from the TSC." + */ +static void set_guest_tsc_adjust(struct acrn_vcpu *vcpu, uint64_t tsc_adjust) +{ + uint64_t tsc_offset, tsc_adjust_delta; + + /* delta of the new and existing IA32_TSC_ADJUST */ + tsc_adjust_delta = tsc_adjust - vcpu_get_guest_msr(vcpu, MSR_IA32_TSC_ADJUST); + + /* apply this delta to existing TSC_OFFSET */ + tsc_offset = exec_vmread64(VMX_TSC_OFFSET_FULL); + exec_vmwrite64(VMX_TSC_OFFSET_FULL, tsc_offset + tsc_adjust_delta); + + /* IA32_TSC_ADJUST is supposed to carry the value it's written to */ + vcpu_set_guest_msr(vcpu, MSR_IA32_TSC_ADJUST, tsc_adjust); +} + int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu) { int32_t err = 0; @@ -425,10 +471,14 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu) err = vlapic_wrmsr(vcpu, msr, v); break; } + case MSR_IA32_TSC_ADJUST: + { + set_guest_tsc_adjust(vcpu, v); + break; + } case MSR_IA32_TIME_STAMP_COUNTER: { - /*Caculate TSC offset from changed TSC MSR value*/ - exec_vmwrite64(VMX_TSC_OFFSET_FULL, v - rdtsc()); + set_guest_tsc(vcpu, v); break; } case MSR_IA32_MTRR_DEF_TYPE: diff --git a/hypervisor/arch/x86/trusty.c b/hypervisor/arch/x86/trusty.c index 70a0d89cf..968dd47dd 100644 --- a/hypervisor/arch/x86/trusty.c +++ b/hypervisor/arch/x86/trusty.c @@ -167,6 +167,7 @@ static void save_world_ctx(struct acrn_vcpu *vcpu, struct ext_context *ext_ctx) (void)vcpu_get_rip(vcpu); /* VMCS GUEST field */ + ext_ctx->tsc_offset = exec_vmread(VMX_TSC_OFFSET_FULL); ext_ctx->vmx_cr0 = exec_vmread(VMX_GUEST_CR0); ext_ctx->vmx_cr4 = exec_vmread(VMX_GUEST_CR4); ext_ctx->vmx_cr0_read_shadow = exec_vmread(VMX_CR0_READ_SHADOW); diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index e2f3e717e..9cef09bfe 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -165,7 +165,7 @@ struct ext_context { #define NORMAL_WORLD 0 #define SECURE_WORLD 1 -#define NUM_WORLD_MSRS 1U +#define NUM_WORLD_MSRS 2U #define NUM_COMMON_MSRS 6U #define NUM_GUEST_MSRS (NUM_WORLD_MSRS + NUM_COMMON_MSRS)