|
@@ -418,6 +418,8 @@ struct vcpu_vmx {
|
|
|
u64 msr_host_kernel_gs_base;
|
|
|
u64 msr_guest_kernel_gs_base;
|
|
|
#endif
|
|
|
+ u32 vm_entry_controls_shadow;
|
|
|
+ u32 vm_exit_controls_shadow;
|
|
|
/*
|
|
|
* loaded_vmcs points to the VMCS currently used in this vcpu. For a
|
|
|
* non-nested (L1) guest, it always points to vmcs01. For a nested
|
|
@@ -1056,7 +1058,9 @@ static inline bool is_exception(u32 intr_info)
|
|
|
== (INTR_TYPE_HARD_EXCEPTION | INTR_INFO_VALID_MASK);
|
|
|
}
|
|
|
|
|
|
-static void nested_vmx_vmexit(struct kvm_vcpu *vcpu);
|
|
|
+static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
|
|
|
+ u32 exit_intr_info,
|
|
|
+ unsigned long exit_qualification);
|
|
|
static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu,
|
|
|
struct vmcs12 *vmcs12,
|
|
|
u32 reason, unsigned long qualification);
|
|
@@ -1326,6 +1330,62 @@ static void vmcs_set_bits(unsigned long field, u32 mask)
|
|
|
vmcs_writel(field, vmcs_readl(field) | mask);
|
|
|
}
|
|
|
|
|
|
+static inline void vm_entry_controls_init(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ vmcs_write32(VM_ENTRY_CONTROLS, val);
|
|
|
+ vmx->vm_entry_controls_shadow = val;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void vm_entry_controls_set(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ if (vmx->vm_entry_controls_shadow != val)
|
|
|
+ vm_entry_controls_init(vmx, val);
|
|
|
+}
|
|
|
+
|
|
|
+static inline u32 vm_entry_controls_get(struct vcpu_vmx *vmx)
|
|
|
+{
|
|
|
+ return vmx->vm_entry_controls_shadow;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static inline void vm_entry_controls_setbit(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ vm_entry_controls_set(vmx, vm_entry_controls_get(vmx) | val);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void vm_entry_controls_clearbit(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ vm_entry_controls_set(vmx, vm_entry_controls_get(vmx) & ~val);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void vm_exit_controls_init(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ vmcs_write32(VM_EXIT_CONTROLS, val);
|
|
|
+ vmx->vm_exit_controls_shadow = val;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void vm_exit_controls_set(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ if (vmx->vm_exit_controls_shadow != val)
|
|
|
+ vm_exit_controls_init(vmx, val);
|
|
|
+}
|
|
|
+
|
|
|
+static inline u32 vm_exit_controls_get(struct vcpu_vmx *vmx)
|
|
|
+{
|
|
|
+ return vmx->vm_exit_controls_shadow;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static inline void vm_exit_controls_setbit(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ vm_exit_controls_set(vmx, vm_exit_controls_get(vmx) | val);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void vm_exit_controls_clearbit(struct vcpu_vmx *vmx, u32 val)
|
|
|
+{
|
|
|
+ vm_exit_controls_set(vmx, vm_exit_controls_get(vmx) & ~val);
|
|
|
+}
|
|
|
+
|
|
|
static void vmx_segment_cache_clear(struct vcpu_vmx *vmx)
|
|
|
{
|
|
|
vmx->segment_cache.bitmask = 0;
|
|
@@ -1410,11 +1470,11 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
|
|
|
vmcs_write32(EXCEPTION_BITMAP, eb);
|
|
|
}
|
|
|
|
|
|
-static void clear_atomic_switch_msr_special(unsigned long entry,
|
|
|
- unsigned long exit)
|
|
|
+static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
|
|
|
+ unsigned long entry, unsigned long exit)
|
|
|
{
|
|
|
- vmcs_clear_bits(VM_ENTRY_CONTROLS, entry);
|
|
|
- vmcs_clear_bits(VM_EXIT_CONTROLS, exit);
|
|
|
+ vm_entry_controls_clearbit(vmx, entry);
|
|
|
+ vm_exit_controls_clearbit(vmx, exit);
|
|
|
}
|
|
|
|
|
|
static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
|
|
@@ -1425,14 +1485,15 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
|
|
|
switch (msr) {
|
|
|
case MSR_EFER:
|
|
|
if (cpu_has_load_ia32_efer) {
|
|
|
- clear_atomic_switch_msr_special(VM_ENTRY_LOAD_IA32_EFER,
|
|
|
+ clear_atomic_switch_msr_special(vmx,
|
|
|
+ VM_ENTRY_LOAD_IA32_EFER,
|
|
|
VM_EXIT_LOAD_IA32_EFER);
|
|
|
return;
|
|
|
}
|
|
|
break;
|
|
|
case MSR_CORE_PERF_GLOBAL_CTRL:
|
|
|
if (cpu_has_load_perf_global_ctrl) {
|
|
|
- clear_atomic_switch_msr_special(
|
|
|
+ clear_atomic_switch_msr_special(vmx,
|
|
|
VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
|
|
|
VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL);
|
|
|
return;
|
|
@@ -1453,14 +1514,15 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr)
|
|
|
vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr);
|
|
|
}
|
|
|
|
|
|
-static void add_atomic_switch_msr_special(unsigned long entry,
|
|
|
- unsigned long exit, unsigned long guest_val_vmcs,
|
|
|
- unsigned long host_val_vmcs, u64 guest_val, u64 host_val)
|
|
|
+static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx,
|
|
|
+ unsigned long entry, unsigned long exit,
|
|
|
+ unsigned long guest_val_vmcs, unsigned long host_val_vmcs,
|
|
|
+ u64 guest_val, u64 host_val)
|
|
|
{
|
|
|
vmcs_write64(guest_val_vmcs, guest_val);
|
|
|
vmcs_write64(host_val_vmcs, host_val);
|
|
|
- vmcs_set_bits(VM_ENTRY_CONTROLS, entry);
|
|
|
- vmcs_set_bits(VM_EXIT_CONTROLS, exit);
|
|
|
+ vm_entry_controls_setbit(vmx, entry);
|
|
|
+ vm_exit_controls_setbit(vmx, exit);
|
|
|
}
|
|
|
|
|
|
static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
|
|
@@ -1472,7 +1534,8 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
|
|
|
switch (msr) {
|
|
|
case MSR_EFER:
|
|
|
if (cpu_has_load_ia32_efer) {
|
|
|
- add_atomic_switch_msr_special(VM_ENTRY_LOAD_IA32_EFER,
|
|
|
+ add_atomic_switch_msr_special(vmx,
|
|
|
+ VM_ENTRY_LOAD_IA32_EFER,
|
|
|
VM_EXIT_LOAD_IA32_EFER,
|
|
|
GUEST_IA32_EFER,
|
|
|
HOST_IA32_EFER,
|
|
@@ -1482,7 +1545,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
|
|
|
break;
|
|
|
case MSR_CORE_PERF_GLOBAL_CTRL:
|
|
|
if (cpu_has_load_perf_global_ctrl) {
|
|
|
- add_atomic_switch_msr_special(
|
|
|
+ add_atomic_switch_msr_special(vmx,
|
|
|
VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
|
|
|
VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL,
|
|
|
GUEST_IA32_PERF_GLOBAL_CTRL,
|
|
@@ -1906,7 +1969,9 @@ static int nested_vmx_check_exception(struct kvm_vcpu *vcpu, unsigned nr)
|
|
|
if (!(vmcs12->exception_bitmap & (1u << nr)))
|
|
|
return 0;
|
|
|
|
|
|
- nested_vmx_vmexit(vcpu);
|
|
|
+ nested_vmx_vmexit(vcpu, to_vmx(vcpu)->exit_reason,
|
|
|
+ vmcs_read32(VM_EXIT_INTR_INFO),
|
|
|
+ vmcs_readl(EXIT_QUALIFICATION));
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -2279,6 +2344,7 @@ static __init void nested_vmx_setup_ctls_msrs(void)
|
|
|
rdmsr(MSR_IA32_VMX_MISC, nested_vmx_misc_low, nested_vmx_misc_high);
|
|
|
nested_vmx_misc_low &= VMX_MISC_PREEMPTION_TIMER_RATE_MASK |
|
|
|
VMX_MISC_SAVE_EFER_LMA;
|
|
|
+ nested_vmx_misc_low |= VMX_MISC_ACTIVITY_HLT;
|
|
|
nested_vmx_misc_high = 0;
|
|
|
}
|
|
|
|
|
@@ -2295,32 +2361,10 @@ static inline u64 vmx_control_msr(u32 low, u32 high)
|
|
|
return low | ((u64)high << 32);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * If we allow our guest to use VMX instructions (i.e., nested VMX), we should
|
|
|
- * also let it use VMX-specific MSRs.
|
|
|
- * vmx_get_vmx_msr() and vmx_set_vmx_msr() return 1 when we handled a
|
|
|
- * VMX-specific MSR, or 0 when we haven't (and the caller should handle it
|
|
|
- * like all other MSRs).
|
|
|
- */
|
|
|
+/* Returns 0 on success, non-0 otherwise. */
|
|
|
static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
|
|
|
{
|
|
|
- if (!nested_vmx_allowed(vcpu) && msr_index >= MSR_IA32_VMX_BASIC &&
|
|
|
- msr_index <= MSR_IA32_VMX_TRUE_ENTRY_CTLS) {
|
|
|
- /*
|
|
|
- * According to the spec, processors which do not support VMX
|
|
|
- * should throw a #GP(0) when VMX capability MSRs are read.
|
|
|
- */
|
|
|
- kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
switch (msr_index) {
|
|
|
- case MSR_IA32_FEATURE_CONTROL:
|
|
|
- if (nested_vmx_allowed(vcpu)) {
|
|
|
- *pdata = to_vmx(vcpu)->nested.msr_ia32_feature_control;
|
|
|
- break;
|
|
|
- }
|
|
|
- return 0;
|
|
|
case MSR_IA32_VMX_BASIC:
|
|
|
/*
|
|
|
* This MSR reports some information about VMX support. We
|
|
@@ -2387,34 +2431,9 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
|
|
|
*pdata = nested_vmx_ept_caps;
|
|
|
break;
|
|
|
default:
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|
|
-{
|
|
|
- u32 msr_index = msr_info->index;
|
|
|
- u64 data = msr_info->data;
|
|
|
- bool host_initialized = msr_info->host_initiated;
|
|
|
-
|
|
|
- if (!nested_vmx_allowed(vcpu))
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (msr_index == MSR_IA32_FEATURE_CONTROL) {
|
|
|
- if (!host_initialized &&
|
|
|
- to_vmx(vcpu)->nested.msr_ia32_feature_control
|
|
|
- & FEATURE_CONTROL_LOCKED)
|
|
|
- return 0;
|
|
|
- to_vmx(vcpu)->nested.msr_ia32_feature_control = data;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * No need to treat VMX capability MSRs specially: If we don't handle
|
|
|
- * them, handle_wrmsr will #GP(0), which is correct (they are readonly)
|
|
|
- */
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2460,13 +2479,20 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
|
|
|
case MSR_IA32_SYSENTER_ESP:
|
|
|
data = vmcs_readl(GUEST_SYSENTER_ESP);
|
|
|
break;
|
|
|
+ case MSR_IA32_FEATURE_CONTROL:
|
|
|
+ if (!nested_vmx_allowed(vcpu))
|
|
|
+ return 1;
|
|
|
+ data = to_vmx(vcpu)->nested.msr_ia32_feature_control;
|
|
|
+ break;
|
|
|
+ case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
|
|
|
+ if (!nested_vmx_allowed(vcpu))
|
|
|
+ return 1;
|
|
|
+ return vmx_get_vmx_msr(vcpu, msr_index, pdata);
|
|
|
case MSR_TSC_AUX:
|
|
|
if (!to_vmx(vcpu)->rdtscp_enabled)
|
|
|
return 1;
|
|
|
/* Otherwise falls through */
|
|
|
default:
|
|
|
- if (vmx_get_vmx_msr(vcpu, msr_index, pdata))
|
|
|
- return 0;
|
|
|
msr = find_msr_entry(to_vmx(vcpu), msr_index);
|
|
|
if (msr) {
|
|
|
data = msr->data;
|
|
@@ -2479,6 +2505,8 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void vmx_leave_nested(struct kvm_vcpu *vcpu);
|
|
|
+
|
|
|
/*
|
|
|
* Writes msr value into into the appropriate "register".
|
|
|
* Returns 0 on success, non-0 otherwise.
|
|
@@ -2533,6 +2561,17 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|
|
case MSR_IA32_TSC_ADJUST:
|
|
|
ret = kvm_set_msr_common(vcpu, msr_info);
|
|
|
break;
|
|
|
+ case MSR_IA32_FEATURE_CONTROL:
|
|
|
+ if (!nested_vmx_allowed(vcpu) ||
|
|
|
+ (to_vmx(vcpu)->nested.msr_ia32_feature_control &
|
|
|
+ FEATURE_CONTROL_LOCKED && !msr_info->host_initiated))
|
|
|
+ return 1;
|
|
|
+ vmx->nested.msr_ia32_feature_control = data;
|
|
|
+ if (msr_info->host_initiated && data == 0)
|
|
|
+ vmx_leave_nested(vcpu);
|
|
|
+ break;
|
|
|
+ case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
|
|
|
+ return 1; /* they are read-only */
|
|
|
case MSR_TSC_AUX:
|
|
|
if (!vmx->rdtscp_enabled)
|
|
|
return 1;
|
|
@@ -2541,8 +2580,6 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|
|
return 1;
|
|
|
/* Otherwise falls through */
|
|
|
default:
|
|
|
- if (vmx_set_vmx_msr(vcpu, msr_info))
|
|
|
- break;
|
|
|
msr = find_msr_entry(vmx, msr_index);
|
|
|
if (msr) {
|
|
|
msr->data = data;
|
|
@@ -3182,14 +3219,10 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|
|
vmx_load_host_state(to_vmx(vcpu));
|
|
|
vcpu->arch.efer = efer;
|
|
|
if (efer & EFER_LMA) {
|
|
|
- vmcs_write32(VM_ENTRY_CONTROLS,
|
|
|
- vmcs_read32(VM_ENTRY_CONTROLS) |
|
|
|
- VM_ENTRY_IA32E_MODE);
|
|
|
+ vm_entry_controls_setbit(to_vmx(vcpu), VM_ENTRY_IA32E_MODE);
|
|
|
msr->data = efer;
|
|
|
} else {
|
|
|
- vmcs_write32(VM_ENTRY_CONTROLS,
|
|
|
- vmcs_read32(VM_ENTRY_CONTROLS) &
|
|
|
- ~VM_ENTRY_IA32E_MODE);
|
|
|
+ vm_entry_controls_clearbit(to_vmx(vcpu), VM_ENTRY_IA32E_MODE);
|
|
|
|
|
|
msr->data = efer & ~EFER_LME;
|
|
|
}
|
|
@@ -3217,9 +3250,7 @@ static void enter_lmode(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
static void exit_lmode(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
- vmcs_write32(VM_ENTRY_CONTROLS,
|
|
|
- vmcs_read32(VM_ENTRY_CONTROLS)
|
|
|
- & ~VM_ENTRY_IA32E_MODE);
|
|
|
+ vm_entry_controls_clearbit(to_vmx(vcpu), VM_ENTRY_IA32E_MODE);
|
|
|
vmx_set_efer(vcpu, vcpu->arch.efer & ~EFER_LMA);
|
|
|
}
|
|
|
|
|
@@ -4346,10 +4377,11 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
|
|
|
++vmx->nmsrs;
|
|
|
}
|
|
|
|
|
|
- vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
|
|
|
+
|
|
|
+ vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl);
|
|
|
|
|
|
/* 22.2.1, 20.8.1 */
|
|
|
- vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl);
|
|
|
+ vm_entry_controls_init(vmx, vmcs_config.vmentry_ctrl);
|
|
|
|
|
|
vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
|
|
|
set_cr4_guest_host_mask(vmx);
|
|
@@ -4588,15 +4620,12 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
|
|
|
static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
if (is_guest_mode(vcpu)) {
|
|
|
- struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
|
|
-
|
|
|
if (to_vmx(vcpu)->nested.nested_run_pending)
|
|
|
return 0;
|
|
|
if (nested_exit_on_nmi(vcpu)) {
|
|
|
- nested_vmx_vmexit(vcpu);
|
|
|
- vmcs12->vm_exit_reason = EXIT_REASON_EXCEPTION_NMI;
|
|
|
- vmcs12->vm_exit_intr_info = NMI_VECTOR |
|
|
|
- INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK;
|
|
|
+ nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
|
|
|
+ NMI_VECTOR | INTR_TYPE_NMI_INTR |
|
|
|
+ INTR_INFO_VALID_MASK, 0);
|
|
|
/*
|
|
|
* The NMI-triggered VM exit counts as injection:
|
|
|
* clear this one and block further NMIs.
|
|
@@ -4618,15 +4647,11 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
|
|
|
static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
if (is_guest_mode(vcpu)) {
|
|
|
- struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
|
|
-
|
|
|
if (to_vmx(vcpu)->nested.nested_run_pending)
|
|
|
return 0;
|
|
|
if (nested_exit_on_intr(vcpu)) {
|
|
|
- nested_vmx_vmexit(vcpu);
|
|
|
- vmcs12->vm_exit_reason =
|
|
|
- EXIT_REASON_EXTERNAL_INTERRUPT;
|
|
|
- vmcs12->vm_exit_intr_info = 0;
|
|
|
+ nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT,
|
|
|
+ 0, 0);
|
|
|
/*
|
|
|
* fall through to normal code, but now in L1, not L2
|
|
|
*/
|
|
@@ -4812,7 +4837,8 @@ static int handle_exception(struct kvm_vcpu *vcpu)
|
|
|
dr6 = vmcs_readl(EXIT_QUALIFICATION);
|
|
|
if (!(vcpu->guest_debug &
|
|
|
(KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
|
|
|
- vcpu->arch.dr6 = dr6 | DR6_FIXED_1;
|
|
|
+ vcpu->arch.dr6 &= ~15;
|
|
|
+ vcpu->arch.dr6 |= dr6;
|
|
|
kvm_queue_exception(vcpu, DB_VECTOR);
|
|
|
return 1;
|
|
|
}
|
|
@@ -5080,14 +5106,27 @@ static int handle_dr(struct kvm_vcpu *vcpu)
|
|
|
reg = DEBUG_REG_ACCESS_REG(exit_qualification);
|
|
|
if (exit_qualification & TYPE_MOV_FROM_DR) {
|
|
|
unsigned long val;
|
|
|
- if (!kvm_get_dr(vcpu, dr, &val))
|
|
|
- kvm_register_write(vcpu, reg, val);
|
|
|
+
|
|
|
+ if (kvm_get_dr(vcpu, dr, &val))
|
|
|
+ return 1;
|
|
|
+ kvm_register_write(vcpu, reg, val);
|
|
|
} else
|
|
|
- kvm_set_dr(vcpu, dr, vcpu->arch.regs[reg]);
|
|
|
+ if (kvm_set_dr(vcpu, dr, vcpu->arch.regs[reg]))
|
|
|
+ return 1;
|
|
|
+
|
|
|
skip_emulated_instruction(vcpu);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+static u64 vmx_get_dr6(struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ return vcpu->arch.dr6;
|
|
|
+}
|
|
|
+
|
|
|
+static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
|
|
|
{
|
|
|
vmcs_writel(GUEST_DR7, val);
|
|
@@ -6460,11 +6499,8 @@ static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
|
|
|
int size;
|
|
|
u8 b;
|
|
|
|
|
|
- if (nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING))
|
|
|
- return 1;
|
|
|
-
|
|
|
if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
|
|
|
- return 0;
|
|
|
+ return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING);
|
|
|
|
|
|
exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
|
|
|
|
|
@@ -6628,6 +6664,13 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
|
|
|
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
|
|
u32 exit_reason = vmx->exit_reason;
|
|
|
|
|
|
+ trace_kvm_nested_vmexit(kvm_rip_read(vcpu), exit_reason,
|
|
|
+ vmcs_readl(EXIT_QUALIFICATION),
|
|
|
+ vmx->idt_vectoring_info,
|
|
|
+ intr_info,
|
|
|
+ vmcs_read32(VM_EXIT_INTR_ERROR_CODE),
|
|
|
+ KVM_ISA_VMX);
|
|
|
+
|
|
|
if (vmx->nested.nested_run_pending)
|
|
|
return 0;
|
|
|
|
|
@@ -6777,7 +6820,9 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
|
|
|
return handle_invalid_guest_state(vcpu);
|
|
|
|
|
|
if (is_guest_mode(vcpu) && nested_vmx_exit_handled(vcpu)) {
|
|
|
- nested_vmx_vmexit(vcpu);
|
|
|
+ nested_vmx_vmexit(vcpu, exit_reason,
|
|
|
+ vmcs_read32(VM_EXIT_INTR_INFO),
|
|
|
+ vmcs_readl(EXIT_QUALIFICATION));
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -7332,8 +7377,8 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
|
|
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
|
|
|
|
|
free_vpid(vmx);
|
|
|
- free_nested(vmx);
|
|
|
free_loaded_vmcs(vmx->loaded_vmcs);
|
|
|
+ free_nested(vmx);
|
|
|
kfree(vmx->guest_msrs);
|
|
|
kvm_vcpu_uninit(vcpu);
|
|
|
kmem_cache_free(kvm_vcpu_cache, vmx);
|
|
@@ -7518,15 +7563,14 @@ static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
|
|
|
static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu,
|
|
|
struct x86_exception *fault)
|
|
|
{
|
|
|
- struct vmcs12 *vmcs12;
|
|
|
- nested_vmx_vmexit(vcpu);
|
|
|
- vmcs12 = get_vmcs12(vcpu);
|
|
|
+ struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
|
|
+ u32 exit_reason;
|
|
|
|
|
|
if (fault->error_code & PFERR_RSVD_MASK)
|
|
|
- vmcs12->vm_exit_reason = EXIT_REASON_EPT_MISCONFIG;
|
|
|
+ exit_reason = EXIT_REASON_EPT_MISCONFIG;
|
|
|
else
|
|
|
- vmcs12->vm_exit_reason = EXIT_REASON_EPT_VIOLATION;
|
|
|
- vmcs12->exit_qualification = vcpu->arch.exit_qualification;
|
|
|
+ exit_reason = EXIT_REASON_EPT_VIOLATION;
|
|
|
+ nested_vmx_vmexit(vcpu, exit_reason, 0, vcpu->arch.exit_qualification);
|
|
|
vmcs12->guest_physical_address = fault->address;
|
|
|
}
|
|
|
|
|
@@ -7564,7 +7608,9 @@ static void vmx_inject_page_fault_nested(struct kvm_vcpu *vcpu,
|
|
|
|
|
|
/* TODO: also check PFEC_MATCH/MASK, not just EB.PF. */
|
|
|
if (vmcs12->exception_bitmap & (1u << PF_VECTOR))
|
|
|
- nested_vmx_vmexit(vcpu);
|
|
|
+ nested_vmx_vmexit(vcpu, to_vmx(vcpu)->exit_reason,
|
|
|
+ vmcs_read32(VM_EXIT_INTR_INFO),
|
|
|
+ vmcs_readl(EXIT_QUALIFICATION));
|
|
|
else
|
|
|
kvm_inject_page_fault(vcpu, fault);
|
|
|
}
|
|
@@ -7706,6 +7752,11 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
|
|
else
|
|
|
vmcs_write64(APIC_ACCESS_ADDR,
|
|
|
page_to_phys(vmx->nested.apic_access_page));
|
|
|
+ } else if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) {
|
|
|
+ exec_control |=
|
|
|
+ SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
|
|
|
+ vmcs_write64(APIC_ACCESS_ADDR,
|
|
|
+ page_to_phys(vcpu->kvm->arch.apic_access_page));
|
|
|
}
|
|
|
|
|
|
vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
|
|
@@ -7759,12 +7810,12 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
|
|
exit_control = vmcs_config.vmexit_ctrl;
|
|
|
if (vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER)
|
|
|
exit_control |= VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
|
|
|
- vmcs_write32(VM_EXIT_CONTROLS, exit_control);
|
|
|
+ vm_exit_controls_init(vmx, exit_control);
|
|
|
|
|
|
/* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are
|
|
|
* emulated by vmx_set_efer(), below.
|
|
|
*/
|
|
|
- vmcs_write32(VM_ENTRY_CONTROLS,
|
|
|
+ vm_entry_controls_init(vmx,
|
|
|
(vmcs12->vm_entry_controls & ~VM_ENTRY_LOAD_IA32_EFER &
|
|
|
~VM_ENTRY_IA32E_MODE) |
|
|
|
(vmcs_config.vmentry_ctrl & ~VM_ENTRY_IA32E_MODE));
|
|
@@ -7882,7 +7933,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE) {
|
|
|
+ if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE &&
|
|
|
+ vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT) {
|
|
|
nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
|
|
|
return 1;
|
|
|
}
|
|
@@ -7994,8 +8046,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
|
|
|
|
|
enter_guest_mode(vcpu);
|
|
|
|
|
|
- vmx->nested.nested_run_pending = 1;
|
|
|
-
|
|
|
vmx->nested.vmcs01_tsc_offset = vmcs_read64(TSC_OFFSET);
|
|
|
|
|
|
cpu = get_cpu();
|
|
@@ -8011,6 +8061,11 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
|
|
|
|
|
prepare_vmcs02(vcpu, vmcs12);
|
|
|
|
|
|
+ if (vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT)
|
|
|
+ return kvm_emulate_halt(vcpu);
|
|
|
+
|
|
|
+ vmx->nested.nested_run_pending = 1;
|
|
|
+
|
|
|
/*
|
|
|
* Note no nested_vmx_succeed or nested_vmx_fail here. At this point
|
|
|
* we are no longer running L1, and VMLAUNCH/VMRESUME has not yet
|
|
@@ -8110,7 +8165,9 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu,
|
|
|
* exit-information fields only. Other fields are modified by L1 with VMWRITE,
|
|
|
* which already writes to vmcs12 directly.
|
|
|
*/
|
|
|
-static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
|
|
+static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
|
|
+ u32 exit_reason, u32 exit_intr_info,
|
|
|
+ unsigned long exit_qualification)
|
|
|
{
|
|
|
/* update guest state fields: */
|
|
|
vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
|
|
@@ -8162,6 +8219,10 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
|
|
vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
|
|
|
vmcs12->guest_pending_dbg_exceptions =
|
|
|
vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS);
|
|
|
+ if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED)
|
|
|
+ vmcs12->guest_activity_state = GUEST_ACTIVITY_HLT;
|
|
|
+ else
|
|
|
+ vmcs12->guest_activity_state = GUEST_ACTIVITY_ACTIVE;
|
|
|
|
|
|
if ((vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER) &&
|
|
|
(vmcs12->vm_exit_controls & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER))
|
|
@@ -8186,7 +8247,7 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
|
|
|
|
|
vmcs12->vm_entry_controls =
|
|
|
(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
|
|
|
- (vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_IA32E_MODE);
|
|
|
+ (vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
|
|
|
|
|
|
/* TODO: These cannot have changed unless we have MSR bitmaps and
|
|
|
* the relevant bit asks not to trap the change */
|
|
@@ -8201,10 +8262,10 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
|
|
|
|
|
/* update exit information fields: */
|
|
|
|
|
|
- vmcs12->vm_exit_reason = to_vmx(vcpu)->exit_reason;
|
|
|
- vmcs12->exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
|
|
|
+ vmcs12->vm_exit_reason = exit_reason;
|
|
|
+ vmcs12->exit_qualification = exit_qualification;
|
|
|
|
|
|
- vmcs12->vm_exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
|
|
|
+ vmcs12->vm_exit_intr_info = exit_intr_info;
|
|
|
if ((vmcs12->vm_exit_intr_info &
|
|
|
(INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK)) ==
|
|
|
(INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK))
|
|
@@ -8370,7 +8431,9 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
|
|
|
* and modify vmcs12 to make it see what it would expect to see there if
|
|
|
* L2 was its real guest. Must only be called when in L2 (is_guest_mode())
|
|
|
*/
|
|
|
-static void nested_vmx_vmexit(struct kvm_vcpu *vcpu)
|
|
|
+static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
|
|
|
+ u32 exit_intr_info,
|
|
|
+ unsigned long exit_qualification)
|
|
|
{
|
|
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
|
|
int cpu;
|
|
@@ -8380,7 +8443,15 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu)
|
|
|
WARN_ON_ONCE(vmx->nested.nested_run_pending);
|
|
|
|
|
|
leave_guest_mode(vcpu);
|
|
|
- prepare_vmcs12(vcpu, vmcs12);
|
|
|
+ prepare_vmcs12(vcpu, vmcs12, exit_reason, exit_intr_info,
|
|
|
+ exit_qualification);
|
|
|
+
|
|
|
+ trace_kvm_nested_vmexit_inject(vmcs12->vm_exit_reason,
|
|
|
+ vmcs12->exit_qualification,
|
|
|
+ vmcs12->idt_vectoring_info_field,
|
|
|
+ vmcs12->vm_exit_intr_info,
|
|
|
+ vmcs12->vm_exit_intr_error_code,
|
|
|
+ KVM_ISA_VMX);
|
|
|
|
|
|
cpu = get_cpu();
|
|
|
vmx->loaded_vmcs = &vmx->vmcs01;
|
|
@@ -8389,6 +8460,8 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu)
|
|
|
vcpu->cpu = cpu;
|
|
|
put_cpu();
|
|
|
|
|
|
+ vm_entry_controls_init(vmx, vmcs_read32(VM_ENTRY_CONTROLS));
|
|
|
+ vm_exit_controls_init(vmx, vmcs_read32(VM_EXIT_CONTROLS));
|
|
|
vmx_segment_cache_clear(vmx);
|
|
|
|
|
|
/* if no vmcs02 cache requested, remove the one we used */
|
|
@@ -8423,6 +8496,16 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu)
|
|
|
vmx->nested.sync_shadow_vmcs = true;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Forcibly leave nested mode in order to be able to reset the VCPU later on.
|
|
|
+ */
|
|
|
+static void vmx_leave_nested(struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ if (is_guest_mode(vcpu))
|
|
|
+ nested_vmx_vmexit(vcpu, -1, 0, 0);
|
|
|
+ free_nested(to_vmx(vcpu));
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* L1's failure to enter L2 is a subset of a normal exit, as explained in
|
|
|
* 23.7 "VM-entry failures during or after loading guest state" (this also
|
|
@@ -8486,6 +8569,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
|
|
|
.set_idt = vmx_set_idt,
|
|
|
.get_gdt = vmx_get_gdt,
|
|
|
.set_gdt = vmx_set_gdt,
|
|
|
+ .get_dr6 = vmx_get_dr6,
|
|
|
+ .set_dr6 = vmx_set_dr6,
|
|
|
.set_dr7 = vmx_set_dr7,
|
|
|
.cache_reg = vmx_cache_reg,
|
|
|
.get_rflags = vmx_get_rflags,
|