|
@@ -187,6 +187,7 @@ struct vmcs {
|
|
|
*/
|
|
|
struct loaded_vmcs {
|
|
|
struct vmcs *vmcs;
|
|
|
+ struct vmcs *shadow_vmcs;
|
|
|
int cpu;
|
|
|
int launched;
|
|
|
struct list_head loaded_vmcss_on_cpu_link;
|
|
@@ -411,7 +412,6 @@ struct nested_vmx {
|
|
|
* memory during VMXOFF, VMCLEAR, VMPTRLD.
|
|
|
*/
|
|
|
struct vmcs12 *cached_vmcs12;
|
|
|
- struct vmcs *current_shadow_vmcs;
|
|
|
/*
|
|
|
* Indicates if the shadow vmcs must be updated with the
|
|
|
* data hold by vmcs12
|
|
@@ -421,7 +421,6 @@ struct nested_vmx {
|
|
|
/* vmcs02_list cache of VMCSs recently used to run L2 guests */
|
|
|
struct list_head vmcs02_pool;
|
|
|
int vmcs02_num;
|
|
|
- u64 vmcs01_tsc_offset;
|
|
|
bool change_vmcs01_virtual_x2apic_mode;
|
|
|
/* L2 must run next, and mustn't decide to exit to L1. */
|
|
|
bool nested_run_pending;
|
|
@@ -1419,6 +1418,8 @@ static void vmcs_clear(struct vmcs *vmcs)
|
|
|
static inline void loaded_vmcs_init(struct loaded_vmcs *loaded_vmcs)
|
|
|
{
|
|
|
vmcs_clear(loaded_vmcs->vmcs);
|
|
|
+ if (loaded_vmcs->shadow_vmcs && loaded_vmcs->launched)
|
|
|
+ vmcs_clear(loaded_vmcs->shadow_vmcs);
|
|
|
loaded_vmcs->cpu = -1;
|
|
|
loaded_vmcs->launched = 0;
|
|
|
}
|
|
@@ -2604,20 +2605,6 @@ static u64 guest_read_tsc(struct kvm_vcpu *vcpu)
|
|
|
return kvm_scale_tsc(vcpu, host_tsc) + tsc_offset;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Like guest_read_tsc, but always returns L1's notion of the timestamp
|
|
|
- * counter, even if a nested guest (L2) is currently running.
|
|
|
- */
|
|
|
-static u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
|
|
|
-{
|
|
|
- u64 tsc_offset;
|
|
|
-
|
|
|
- tsc_offset = is_guest_mode(vcpu) ?
|
|
|
- to_vmx(vcpu)->nested.vmcs01_tsc_offset :
|
|
|
- vmcs_read64(TSC_OFFSET);
|
|
|
- return host_tsc + tsc_offset;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* writes 'offset' into guest's timestamp counter offset register
|
|
|
*/
|
|
@@ -2631,7 +2618,6 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
|
|
|
* to the newly set TSC to get L2's TSC.
|
|
|
*/
|
|
|
struct vmcs12 *vmcs12;
|
|
|
- to_vmx(vcpu)->nested.vmcs01_tsc_offset = offset;
|
|
|
/* recalculate vmcs02.TSC_OFFSET: */
|
|
|
vmcs12 = get_vmcs12(vcpu);
|
|
|
vmcs_write64(TSC_OFFSET, offset +
|
|
@@ -2644,19 +2630,6 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void vmx_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment)
|
|
|
-{
|
|
|
- u64 offset = vmcs_read64(TSC_OFFSET);
|
|
|
-
|
|
|
- vmcs_write64(TSC_OFFSET, offset + adjustment);
|
|
|
- if (is_guest_mode(vcpu)) {
|
|
|
- /* Even when running L2, the adjustment needs to apply to L1 */
|
|
|
- to_vmx(vcpu)->nested.vmcs01_tsc_offset += adjustment;
|
|
|
- } else
|
|
|
- trace_kvm_write_tsc_offset(vcpu->vcpu_id, offset,
|
|
|
- offset + adjustment);
|
|
|
-}
|
|
|
-
|
|
|
static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 1, 0);
|
|
@@ -3562,6 +3535,7 @@ static void free_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
|
|
|
loaded_vmcs_clear(loaded_vmcs);
|
|
|
free_vmcs(loaded_vmcs->vmcs);
|
|
|
loaded_vmcs->vmcs = NULL;
|
|
|
+ WARN_ON(loaded_vmcs->shadow_vmcs != NULL);
|
|
|
}
|
|
|
|
|
|
static void free_kvm_area(void)
|
|
@@ -6696,6 +6670,7 @@ static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx)
|
|
|
if (!item)
|
|
|
return NULL;
|
|
|
item->vmcs02.vmcs = alloc_vmcs();
|
|
|
+ item->vmcs02.shadow_vmcs = NULL;
|
|
|
if (!item->vmcs02.vmcs) {
|
|
|
kfree(item);
|
|
|
return NULL;
|
|
@@ -7072,7 +7047,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
|
|
|
shadow_vmcs->revision_id |= (1u << 31);
|
|
|
/* init shadow vmcs */
|
|
|
vmcs_clear(shadow_vmcs);
|
|
|
- vmx->nested.current_shadow_vmcs = shadow_vmcs;
|
|
|
+ vmx->vmcs01.shadow_vmcs = shadow_vmcs;
|
|
|
}
|
|
|
|
|
|
INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
|
|
@@ -7174,8 +7149,11 @@ static void free_nested(struct vcpu_vmx *vmx)
|
|
|
free_page((unsigned long)vmx->nested.msr_bitmap);
|
|
|
vmx->nested.msr_bitmap = NULL;
|
|
|
}
|
|
|
- if (enable_shadow_vmcs)
|
|
|
- free_vmcs(vmx->nested.current_shadow_vmcs);
|
|
|
+ if (enable_shadow_vmcs) {
|
|
|
+ vmcs_clear(vmx->vmcs01.shadow_vmcs);
|
|
|
+ free_vmcs(vmx->vmcs01.shadow_vmcs);
|
|
|
+ vmx->vmcs01.shadow_vmcs = NULL;
|
|
|
+ }
|
|
|
kfree(vmx->nested.cached_vmcs12);
|
|
|
/* Unpin physical memory we referred to in current vmcs02 */
|
|
|
if (vmx->nested.apic_access_page) {
|
|
@@ -7352,7 +7330,7 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
|
|
|
int i;
|
|
|
unsigned long field;
|
|
|
u64 field_value;
|
|
|
- struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
|
|
|
+ struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
|
|
|
const unsigned long *fields = shadow_read_write_fields;
|
|
|
const int num_fields = max_shadow_read_write_fields;
|
|
|
|
|
@@ -7401,7 +7379,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
|
|
|
int i, q;
|
|
|
unsigned long field;
|
|
|
u64 field_value = 0;
|
|
|
- struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
|
|
|
+ struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
|
|
|
|
|
|
vmcs_load(shadow_vmcs);
|
|
|
|
|
@@ -7591,7 +7569,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
|
|
|
vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
|
|
|
SECONDARY_EXEC_SHADOW_VMCS);
|
|
|
vmcs_write64(VMCS_LINK_POINTER,
|
|
|
- __pa(vmx->nested.current_shadow_vmcs));
|
|
|
+ __pa(vmx->vmcs01.shadow_vmcs));
|
|
|
vmx->nested.sync_shadow_vmcs = true;
|
|
|
}
|
|
|
}
|
|
@@ -7659,7 +7637,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
types = (vmx->nested.nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6;
|
|
|
|
|
|
- if (!(types & (1UL << type))) {
|
|
|
+ if (type >= 32 || !(types & (1 << type))) {
|
|
|
nested_vmx_failValid(vcpu,
|
|
|
VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
|
|
|
skip_emulated_instruction(vcpu);
|
|
@@ -7722,7 +7700,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
types = (vmx->nested.nested_vmx_vpid_caps >> 8) & 0x7;
|
|
|
|
|
|
- if (!(types & (1UL << type))) {
|
|
|
+ if (type >= 32 || !(types & (1 << type))) {
|
|
|
nested_vmx_failValid(vcpu,
|
|
|
VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
|
|
|
skip_emulated_instruction(vcpu);
|
|
@@ -9156,6 +9134,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
|
|
|
|
|
|
vmx->loaded_vmcs = &vmx->vmcs01;
|
|
|
vmx->loaded_vmcs->vmcs = alloc_vmcs();
|
|
|
+ vmx->loaded_vmcs->shadow_vmcs = NULL;
|
|
|
if (!vmx->loaded_vmcs->vmcs)
|
|
|
goto free_msrs;
|
|
|
if (!vmm_exclusive)
|
|
@@ -10061,9 +10040,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
|
|
|
|
|
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
|
|
|
vmcs_write64(TSC_OFFSET,
|
|
|
- vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset);
|
|
|
+ vcpu->arch.tsc_offset + vmcs12->tsc_offset);
|
|
|
else
|
|
|
- vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
|
|
|
+ vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
|
|
|
if (kvm_has_tsc_control)
|
|
|
decache_tsc_multiplier(vmx);
|
|
|
|
|
@@ -10293,8 +10272,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
|
|
|
|
|
enter_guest_mode(vcpu);
|
|
|
|
|
|
- vmx->nested.vmcs01_tsc_offset = vmcs_read64(TSC_OFFSET);
|
|
|
-
|
|
|
if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
|
|
|
vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
|
|
|
|
|
@@ -10818,7 +10795,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
|
|
|
load_vmcs12_host_state(vcpu, vmcs12);
|
|
|
|
|
|
/* Update any VMCS fields that might have changed while L2 ran */
|
|
|
- vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
|
|
|
+ vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
|
|
|
if (vmx->hv_deadline_tsc == -1)
|
|
|
vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
|
|
|
PIN_BASED_VMX_PREEMPTION_TIMER);
|
|
@@ -11339,8 +11316,6 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
|
|
|
.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
|
|
|
|
|
|
.write_tsc_offset = vmx_write_tsc_offset,
|
|
|
- .adjust_tsc_offset_guest = vmx_adjust_tsc_offset_guest,
|
|
|
- .read_l1_tsc = vmx_read_l1_tsc,
|
|
|
|
|
|
.set_tdp_cr3 = vmx_set_cr3,
|
|
|
|