mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-20 12:42:54 +00:00
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 <zide.chen@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
parent
6b998580d6
commit
a958fea7a4
@ -17,12 +17,13 @@ enum rw_mode {
|
|||||||
static const uint32_t emulated_guest_msrs[NUM_GUEST_MSRS] = {
|
static const uint32_t emulated_guest_msrs[NUM_GUEST_MSRS] = {
|
||||||
/*
|
/*
|
||||||
* MSRs that trusty may touch and need isolation between secure and normal world
|
* 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
|
* MSR_IA32_KERNEL_GS_BASE, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_EIP
|
||||||
*
|
*
|
||||||
* Number of entries: NUM_WORLD_MSRS
|
* Number of entries: NUM_WORLD_MSRS
|
||||||
*/
|
*/
|
||||||
MSR_IA32_PAT,
|
MSR_IA32_PAT,
|
||||||
|
MSR_IA32_TSC_ADJUST,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MSRs don't need isolation between worlds
|
* 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++) {
|
for (msr = MSR_IA32_L3_MASK_0; msr < MSR_IA32_BNDCFGS; msr++) {
|
||||||
enable_msr_interception(msr_bitmap, msr, READ_WRITE);
|
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 */
|
/* 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);
|
err = vlapic_rdmsr(vcpu, msr, &v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSR_IA32_TIME_STAMP_COUNTER:
|
case MSR_IA32_TSC_ADJUST:
|
||||||
{
|
{
|
||||||
/* Add the TSC_offset to host TSC to get guest TSC */
|
v = vcpu_get_guest_msr(vcpu, MSR_IA32_TSC_ADJUST);
|
||||||
v = rdtsc() + exec_vmread64(VMX_TSC_OFFSET_FULL);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSR_IA32_MTRR_CAP:
|
case MSR_IA32_MTRR_CAP:
|
||||||
@ -405,6 +408,49 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||||||
return err;
|
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 wrmsr_vmexit_handler(struct acrn_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
int32_t err = 0;
|
int32_t err = 0;
|
||||||
@ -425,10 +471,14 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||||||
err = vlapic_wrmsr(vcpu, msr, v);
|
err = vlapic_wrmsr(vcpu, msr, v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MSR_IA32_TSC_ADJUST:
|
||||||
|
{
|
||||||
|
set_guest_tsc_adjust(vcpu, v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MSR_IA32_TIME_STAMP_COUNTER:
|
case MSR_IA32_TIME_STAMP_COUNTER:
|
||||||
{
|
{
|
||||||
/*Caculate TSC offset from changed TSC MSR value*/
|
set_guest_tsc(vcpu, v);
|
||||||
exec_vmwrite64(VMX_TSC_OFFSET_FULL, v - rdtsc());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSR_IA32_MTRR_DEF_TYPE:
|
case MSR_IA32_MTRR_DEF_TYPE:
|
||||||
|
@ -167,6 +167,7 @@ static void save_world_ctx(struct acrn_vcpu *vcpu, struct ext_context *ext_ctx)
|
|||||||
(void)vcpu_get_rip(vcpu);
|
(void)vcpu_get_rip(vcpu);
|
||||||
|
|
||||||
/* VMCS GUEST field */
|
/* 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_cr0 = exec_vmread(VMX_GUEST_CR0);
|
||||||
ext_ctx->vmx_cr4 = exec_vmread(VMX_GUEST_CR4);
|
ext_ctx->vmx_cr4 = exec_vmread(VMX_GUEST_CR4);
|
||||||
ext_ctx->vmx_cr0_read_shadow = exec_vmread(VMX_CR0_READ_SHADOW);
|
ext_ctx->vmx_cr0_read_shadow = exec_vmread(VMX_CR0_READ_SHADOW);
|
||||||
|
@ -165,7 +165,7 @@ struct ext_context {
|
|||||||
#define NORMAL_WORLD 0
|
#define NORMAL_WORLD 0
|
||||||
#define SECURE_WORLD 1
|
#define SECURE_WORLD 1
|
||||||
|
|
||||||
#define NUM_WORLD_MSRS 1U
|
#define NUM_WORLD_MSRS 2U
|
||||||
#define NUM_COMMON_MSRS 6U
|
#define NUM_COMMON_MSRS 6U
|
||||||
#define NUM_GUEST_MSRS (NUM_WORLD_MSRS + NUM_COMMON_MSRS)
|
#define NUM_GUEST_MSRS (NUM_WORLD_MSRS + NUM_COMMON_MSRS)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user