Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/vmm/intel/vmx_msr.c
Show First 20 Lines • Show All 310 Lines • ▼ Show 20 Lines | vmx_msr_init(void) | ||||
*/ | */ | ||||
for (i = 0; i < 8; i++) | for (i = 0; i < 8; i++) | ||||
turbo_ratio_limit = (turbo_ratio_limit << 8) | ratio; | turbo_ratio_limit = (turbo_ratio_limit << 8) | ratio; | ||||
} | } | ||||
void | void | ||||
vmx_msr_guest_init(struct vmx *vmx, int vcpuid) | vmx_msr_guest_init(struct vmx *vmx, int vcpuid) | ||||
{ | { | ||||
uint64_t *guest_msrs; | struct vmx_vcpu *vmx_vcpu = &vmx->vcpus[vcpuid]; | ||||
guest_msrs = vmx->guest_msrs[vcpuid]; | |||||
/* | /* | ||||
* The permissions bitmap is shared between all vcpus so initialize it | * The permissions bitmap is shared between all vcpus so initialize it | ||||
* once when initializing the vBSP. | * once when initializing the vBSP. | ||||
*/ | */ | ||||
if (vcpuid == 0) { | if (vcpuid == 0) { | ||||
guest_msr_rw(vmx, MSR_LSTAR); | guest_msr_rw(vmx, MSR_LSTAR); | ||||
guest_msr_rw(vmx, MSR_CSTAR); | guest_msr_rw(vmx, MSR_CSTAR); | ||||
guest_msr_rw(vmx, MSR_STAR); | guest_msr_rw(vmx, MSR_STAR); | ||||
guest_msr_rw(vmx, MSR_SF_MASK); | guest_msr_rw(vmx, MSR_SF_MASK); | ||||
guest_msr_rw(vmx, MSR_KGSBASE); | guest_msr_rw(vmx, MSR_KGSBASE); | ||||
} | } | ||||
/* | /* | ||||
* Initialize guest IA32_PAT MSR with default value after reset. | * Initialize guest IA32_PAT MSR with default value after reset. | ||||
*/ | */ | ||||
guest_msrs[IDX_MSR_PAT] = PAT_VALUE(0, PAT_WRITE_BACK) | | vmx_vcpu->guest_msrs[IDX_MSR_PAT] = PAT_VALUE(0, PAT_WRITE_BACK) | | ||||
PAT_VALUE(1, PAT_WRITE_THROUGH) | | PAT_VALUE(1, PAT_WRITE_THROUGH) | | ||||
PAT_VALUE(2, PAT_UNCACHED) | | PAT_VALUE(2, PAT_UNCACHED) | | ||||
PAT_VALUE(3, PAT_UNCACHEABLE) | | PAT_VALUE(3, PAT_UNCACHEABLE) | | ||||
PAT_VALUE(4, PAT_WRITE_BACK) | | PAT_VALUE(4, PAT_WRITE_BACK) | | ||||
PAT_VALUE(5, PAT_WRITE_THROUGH) | | PAT_VALUE(5, PAT_WRITE_THROUGH) | | ||||
PAT_VALUE(6, PAT_UNCACHED) | | PAT_VALUE(6, PAT_UNCACHED) | | ||||
PAT_VALUE(7, PAT_UNCACHEABLE); | PAT_VALUE(7, PAT_UNCACHEABLE); | ||||
return; | return; | ||||
} | } | ||||
void | void | ||||
vmx_msr_guest_enter(struct vmx *vmx, int vcpuid) | vmx_msr_guest_enter(struct vmx *vmx, int vcpuid) | ||||
{ | { | ||||
uint64_t *guest_msrs = vmx->guest_msrs[vcpuid]; | struct vmx_vcpu *vmx_vcpu = &vmx->vcpus[vcpuid]; | ||||
/* Save host MSRs (in particular, KGSBASE) and restore guest MSRs */ | /* Save host MSRs (in particular, KGSBASE) and restore guest MSRs */ | ||||
update_pcb_bases(curpcb); | update_pcb_bases(curpcb); | ||||
wrmsr(MSR_LSTAR, guest_msrs[IDX_MSR_LSTAR]); | wrmsr(MSR_LSTAR, vmx_vcpu->guest_msrs[IDX_MSR_LSTAR]); | ||||
wrmsr(MSR_CSTAR, guest_msrs[IDX_MSR_CSTAR]); | wrmsr(MSR_CSTAR, vmx_vcpu->guest_msrs[IDX_MSR_CSTAR]); | ||||
wrmsr(MSR_STAR, guest_msrs[IDX_MSR_STAR]); | wrmsr(MSR_STAR, vmx_vcpu->guest_msrs[IDX_MSR_STAR]); | ||||
wrmsr(MSR_SF_MASK, guest_msrs[IDX_MSR_SF_MASK]); | wrmsr(MSR_SF_MASK, vmx_vcpu->guest_msrs[IDX_MSR_SF_MASK]); | ||||
wrmsr(MSR_KGSBASE, guest_msrs[IDX_MSR_KGSBASE]); | wrmsr(MSR_KGSBASE, vmx_vcpu->guest_msrs[IDX_MSR_KGSBASE]); | ||||
} | } | ||||
void | void | ||||
vmx_msr_guest_enter_tsc_aux(struct vmx *vmx, int vcpuid) | vmx_msr_guest_enter_tsc_aux(struct vmx *vmx, int vcpuid) | ||||
{ | { | ||||
uint64_t guest_tsc_aux = vmx->guest_msrs[vcpuid][IDX_MSR_TSC_AUX]; | struct vmx_vcpu *vmx_vcpu = &vmx->vcpus[vcpuid]; | ||||
uint64_t guest_tsc_aux = vmx_vcpu->guest_msrs[IDX_MSR_TSC_AUX]; | |||||
uint32_t host_aux = cpu_auxmsr(); | uint32_t host_aux = cpu_auxmsr(); | ||||
if (vmx_have_msr_tsc_aux(vmx) && guest_tsc_aux != host_aux) | if (vmx_have_msr_tsc_aux(vmx) && guest_tsc_aux != host_aux) | ||||
wrmsr(MSR_TSC_AUX, guest_tsc_aux); | wrmsr(MSR_TSC_AUX, guest_tsc_aux); | ||||
} | } | ||||
void | void | ||||
vmx_msr_guest_exit(struct vmx *vmx, int vcpuid) | vmx_msr_guest_exit(struct vmx *vmx, int vcpuid) | ||||
{ | { | ||||
uint64_t *guest_msrs = vmx->guest_msrs[vcpuid]; | struct vmx_vcpu *vmx_vcpu = &vmx->vcpus[vcpuid]; | ||||
/* Save guest MSRs */ | /* Save guest MSRs */ | ||||
guest_msrs[IDX_MSR_LSTAR] = rdmsr(MSR_LSTAR); | vmx_vcpu->guest_msrs[IDX_MSR_LSTAR] = rdmsr(MSR_LSTAR); | ||||
guest_msrs[IDX_MSR_CSTAR] = rdmsr(MSR_CSTAR); | vmx_vcpu->guest_msrs[IDX_MSR_CSTAR] = rdmsr(MSR_CSTAR); | ||||
guest_msrs[IDX_MSR_STAR] = rdmsr(MSR_STAR); | vmx_vcpu->guest_msrs[IDX_MSR_STAR] = rdmsr(MSR_STAR); | ||||
guest_msrs[IDX_MSR_SF_MASK] = rdmsr(MSR_SF_MASK); | vmx_vcpu->guest_msrs[IDX_MSR_SF_MASK] = rdmsr(MSR_SF_MASK); | ||||
guest_msrs[IDX_MSR_KGSBASE] = rdmsr(MSR_KGSBASE); | vmx_vcpu->guest_msrs[IDX_MSR_KGSBASE] = rdmsr(MSR_KGSBASE); | ||||
/* Restore host MSRs */ | /* Restore host MSRs */ | ||||
wrmsr(MSR_LSTAR, host_msrs[IDX_MSR_LSTAR]); | wrmsr(MSR_LSTAR, host_msrs[IDX_MSR_LSTAR]); | ||||
wrmsr(MSR_CSTAR, host_msrs[IDX_MSR_CSTAR]); | wrmsr(MSR_CSTAR, host_msrs[IDX_MSR_CSTAR]); | ||||
wrmsr(MSR_STAR, host_msrs[IDX_MSR_STAR]); | wrmsr(MSR_STAR, host_msrs[IDX_MSR_STAR]); | ||||
wrmsr(MSR_SF_MASK, host_msrs[IDX_MSR_SF_MASK]); | wrmsr(MSR_SF_MASK, host_msrs[IDX_MSR_SF_MASK]); | ||||
/* MSR_KGSBASE will be restored on the way back to userspace */ | /* MSR_KGSBASE will be restored on the way back to userspace */ | ||||
} | } | ||||
void | void | ||||
vmx_msr_guest_exit_tsc_aux(struct vmx *vmx, int vcpuid) | vmx_msr_guest_exit_tsc_aux(struct vmx *vmx, int vcpuid) | ||||
{ | { | ||||
uint64_t guest_tsc_aux = vmx->guest_msrs[vcpuid][IDX_MSR_TSC_AUX]; | struct vmx_vcpu *vmx_vcpu = &vmx->vcpus[vcpuid]; | ||||
uint64_t guest_tsc_aux = vmx_vcpu->guest_msrs[IDX_MSR_TSC_AUX]; | |||||
uint32_t host_aux = cpu_auxmsr(); | uint32_t host_aux = cpu_auxmsr(); | ||||
if (vmx_have_msr_tsc_aux(vmx) && guest_tsc_aux != host_aux) | if (vmx_have_msr_tsc_aux(vmx) && guest_tsc_aux != host_aux) | ||||
/* | /* | ||||
* Note that it is not necessary to save the guest value | * Note that it is not necessary to save the guest value | ||||
* here; vmx->guest_msrs[vcpuid][IDX_MSR_TSC_AUX] always | * here; vmx->guest_msrs[vcpuid][IDX_MSR_TSC_AUX] always | ||||
* contains the current value since it is updated whenever | * contains the current value since it is updated whenever | ||||
* the guest writes to it (which is expected to be very | * the guest writes to it (which is expected to be very | ||||
* rare). | * rare). | ||||
*/ | */ | ||||
wrmsr(MSR_TSC_AUX, host_aux); | wrmsr(MSR_TSC_AUX, host_aux); | ||||
} | } | ||||
int | int | ||||
vmx_rdmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t *val, bool *retu) | vmx_rdmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t *val, bool *retu) | ||||
{ | { | ||||
const uint64_t *guest_msrs; | struct vmx_vcpu *vmx_vcpu = &vmx->vcpus[vcpuid]; | ||||
int error; | int error; | ||||
guest_msrs = vmx->guest_msrs[vcpuid]; | |||||
error = 0; | error = 0; | ||||
switch (num) { | switch (num) { | ||||
case MSR_MCG_CAP: | case MSR_MCG_CAP: | ||||
case MSR_MCG_STATUS: | case MSR_MCG_STATUS: | ||||
*val = 0; | *val = 0; | ||||
break; | break; | ||||
case MSR_MTRRcap: | case MSR_MTRRcap: | ||||
case MSR_MTRRdefType: | case MSR_MTRRdefType: | ||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7: | case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7: | ||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: | case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: | ||||
case MSR_MTRR64kBase: | case MSR_MTRR64kBase: | ||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1: | case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1: | ||||
if (vm_rdmtrr(&vmx->mtrr[vcpuid], num, val) != 0) { | if (vm_rdmtrr(&vmx_vcpu->mtrr, num, val) != 0) { | ||||
vm_inject_gp(vmx->vm, vcpuid); | vm_inject_gp(vmx->vm, vcpuid); | ||||
} | } | ||||
break; | break; | ||||
case MSR_IA32_MISC_ENABLE: | case MSR_IA32_MISC_ENABLE: | ||||
*val = misc_enable; | *val = misc_enable; | ||||
break; | break; | ||||
case MSR_PLATFORM_INFO: | case MSR_PLATFORM_INFO: | ||||
*val = platform_info; | *val = platform_info; | ||||
break; | break; | ||||
case MSR_TURBO_RATIO_LIMIT: | case MSR_TURBO_RATIO_LIMIT: | ||||
case MSR_TURBO_RATIO_LIMIT1: | case MSR_TURBO_RATIO_LIMIT1: | ||||
*val = turbo_ratio_limit; | *val = turbo_ratio_limit; | ||||
break; | break; | ||||
case MSR_PAT: | case MSR_PAT: | ||||
*val = guest_msrs[IDX_MSR_PAT]; | *val = vmx_vcpu->guest_msrs[IDX_MSR_PAT]; | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
vmx_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val, bool *retu) | vmx_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val, bool *retu) | ||||
{ | { | ||||
uint64_t *guest_msrs; | struct vmx_vcpu *vmx_vcpu = &vmx->vcpus[vcpuid]; | ||||
uint64_t changed; | uint64_t changed; | ||||
int error; | int error; | ||||
guest_msrs = vmx->guest_msrs[vcpuid]; | |||||
error = 0; | error = 0; | ||||
switch (num) { | switch (num) { | ||||
case MSR_MCG_CAP: | case MSR_MCG_CAP: | ||||
case MSR_MCG_STATUS: | case MSR_MCG_STATUS: | ||||
break; /* ignore writes */ | break; /* ignore writes */ | ||||
case MSR_MTRRcap: | case MSR_MTRRcap: | ||||
case MSR_MTRRdefType: | case MSR_MTRRdefType: | ||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7: | case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7: | ||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: | case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: | ||||
case MSR_MTRR64kBase: | case MSR_MTRR64kBase: | ||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1: | case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1: | ||||
if (vm_wrmtrr(&vmx->mtrr[vcpuid], num, val) != 0) { | if (vm_wrmtrr(&vmx_vcpu->mtrr, num, val) != 0) { | ||||
vm_inject_gp(vmx->vm, vcpuid); | vm_inject_gp(vmx->vm, vcpuid); | ||||
} | } | ||||
break; | break; | ||||
case MSR_IA32_MISC_ENABLE: | case MSR_IA32_MISC_ENABLE: | ||||
changed = val ^ misc_enable; | changed = val ^ misc_enable; | ||||
/* | /* | ||||
* If the host has disabled the NX feature then the guest | * If the host has disabled the NX feature then the guest | ||||
* also cannot use it. However, a Linux guest will try to | * also cannot use it. However, a Linux guest will try to | ||||
Show All 9 Lines | case MSR_IA32_MISC_ENABLE: | ||||
* Punt to userspace if any other bits are being modified. | * Punt to userspace if any other bits are being modified. | ||||
*/ | */ | ||||
if (changed) | if (changed) | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
case MSR_PAT: | case MSR_PAT: | ||||
if (pat_valid(val)) | if (pat_valid(val)) | ||||
guest_msrs[IDX_MSR_PAT] = val; | vmx_vcpu->guest_msrs[IDX_MSR_PAT] = val; | ||||
else | else | ||||
vm_inject_gp(vmx->vm, vcpuid); | vm_inject_gp(vmx->vm, vcpuid); | ||||
break; | break; | ||||
case MSR_TSC: | case MSR_TSC: | ||||
error = vmx_set_tsc_offset(vmx, vcpuid, val - rdtsc()); | error = vmx_set_tsc_offset(vmx, vcpuid, val - rdtsc()); | ||||
break; | break; | ||||
case MSR_TSC_AUX: | case MSR_TSC_AUX: | ||||
if (vmx_have_msr_tsc_aux(vmx)) | if (vmx_have_msr_tsc_aux(vmx)) | ||||
/* | /* | ||||
* vmx_msr_guest_enter_tsc_aux() will apply this | * vmx_msr_guest_enter_tsc_aux() will apply this | ||||
* value when it is called immediately before guest | * value when it is called immediately before guest | ||||
* entry. | * entry. | ||||
*/ | */ | ||||
guest_msrs[IDX_MSR_TSC_AUX] = val; | vmx_vcpu->guest_msrs[IDX_MSR_TSC_AUX] = val; | ||||
else | else | ||||
vm_inject_gp(vmx->vm, vcpuid); | vm_inject_gp(vmx->vm, vcpuid); | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } |