KVM: nVMX: Allow to disable VM_{ENTRY_LOAD,EXIT_SAVE}_DEBUG_CONTROLS
Allow L1 to "leak" its debug controls into L2, i.e. permit cleared VM_{ENTRY_LOAD,EXIT_SAVE}_DEBUG_CONTROLS. This requires to manually transfer the state of DR7 and IA32_DEBUGCTLMSR from L1 into L2 as both run on different VMCS. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
560b7ee12c
commit
2996fca069
|
@ -383,6 +383,9 @@ struct nested_vmx {
|
||||||
|
|
||||||
struct hrtimer preemption_timer;
|
struct hrtimer preemption_timer;
|
||||||
bool preemption_timer_expired;
|
bool preemption_timer_expired;
|
||||||
|
|
||||||
|
/* to migrate it to L2 if VM_ENTRY_LOAD_DEBUG_CONTROLS is off */
|
||||||
|
u64 vmcs01_debugctl;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define POSTED_INTR_ON 0
|
#define POSTED_INTR_ON 0
|
||||||
|
@ -2243,7 +2246,9 @@ static u32 nested_vmx_true_procbased_ctls_low;
|
||||||
static u32 nested_vmx_secondary_ctls_low, nested_vmx_secondary_ctls_high;
|
static u32 nested_vmx_secondary_ctls_low, nested_vmx_secondary_ctls_high;
|
||||||
static u32 nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high;
|
static u32 nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high;
|
||||||
static u32 nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high;
|
static u32 nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high;
|
||||||
|
static u32 nested_vmx_true_exit_ctls_low;
|
||||||
static u32 nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high;
|
static u32 nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high;
|
||||||
|
static u32 nested_vmx_true_entry_ctls_low;
|
||||||
static u32 nested_vmx_misc_low, nested_vmx_misc_high;
|
static u32 nested_vmx_misc_low, nested_vmx_misc_high;
|
||||||
static u32 nested_vmx_ept_caps;
|
static u32 nested_vmx_ept_caps;
|
||||||
static __init void nested_vmx_setup_ctls_msrs(void)
|
static __init void nested_vmx_setup_ctls_msrs(void)
|
||||||
|
@ -2289,6 +2294,10 @@ static __init void nested_vmx_setup_ctls_msrs(void)
|
||||||
if (vmx_mpx_supported())
|
if (vmx_mpx_supported())
|
||||||
nested_vmx_exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS;
|
nested_vmx_exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS;
|
||||||
|
|
||||||
|
/* We support free control of debug control saving. */
|
||||||
|
nested_vmx_true_exit_ctls_low = nested_vmx_exit_ctls_low &
|
||||||
|
~VM_EXIT_SAVE_DEBUG_CONTROLS;
|
||||||
|
|
||||||
/* entry controls */
|
/* entry controls */
|
||||||
rdmsr(MSR_IA32_VMX_ENTRY_CTLS,
|
rdmsr(MSR_IA32_VMX_ENTRY_CTLS,
|
||||||
nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high);
|
nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high);
|
||||||
|
@ -2303,6 +2312,10 @@ static __init void nested_vmx_setup_ctls_msrs(void)
|
||||||
if (vmx_mpx_supported())
|
if (vmx_mpx_supported())
|
||||||
nested_vmx_entry_ctls_high |= VM_ENTRY_LOAD_BNDCFGS;
|
nested_vmx_entry_ctls_high |= VM_ENTRY_LOAD_BNDCFGS;
|
||||||
|
|
||||||
|
/* We support free control of debug control loading. */
|
||||||
|
nested_vmx_true_entry_ctls_low = nested_vmx_entry_ctls_low &
|
||||||
|
~VM_ENTRY_LOAD_DEBUG_CONTROLS;
|
||||||
|
|
||||||
/* cpu-based controls */
|
/* cpu-based controls */
|
||||||
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS,
|
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS,
|
||||||
nested_vmx_procbased_ctls_low, nested_vmx_procbased_ctls_high);
|
nested_vmx_procbased_ctls_low, nested_vmx_procbased_ctls_high);
|
||||||
|
@ -2409,11 +2422,17 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
|
||||||
nested_vmx_procbased_ctls_high);
|
nested_vmx_procbased_ctls_high);
|
||||||
break;
|
break;
|
||||||
case MSR_IA32_VMX_TRUE_EXIT_CTLS:
|
case MSR_IA32_VMX_TRUE_EXIT_CTLS:
|
||||||
|
*pdata = vmx_control_msr(nested_vmx_true_exit_ctls_low,
|
||||||
|
nested_vmx_exit_ctls_high);
|
||||||
|
break;
|
||||||
case MSR_IA32_VMX_EXIT_CTLS:
|
case MSR_IA32_VMX_EXIT_CTLS:
|
||||||
*pdata = vmx_control_msr(nested_vmx_exit_ctls_low,
|
*pdata = vmx_control_msr(nested_vmx_exit_ctls_low,
|
||||||
nested_vmx_exit_ctls_high);
|
nested_vmx_exit_ctls_high);
|
||||||
break;
|
break;
|
||||||
case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
|
case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
|
||||||
|
*pdata = vmx_control_msr(nested_vmx_true_entry_ctls_low,
|
||||||
|
nested_vmx_entry_ctls_high);
|
||||||
|
break;
|
||||||
case MSR_IA32_VMX_ENTRY_CTLS:
|
case MSR_IA32_VMX_ENTRY_CTLS:
|
||||||
*pdata = vmx_control_msr(nested_vmx_entry_ctls_low,
|
*pdata = vmx_control_msr(nested_vmx_entry_ctls_low,
|
||||||
nested_vmx_entry_ctls_high);
|
nested_vmx_entry_ctls_high);
|
||||||
|
@ -7836,7 +7855,13 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
||||||
vmcs_writel(GUEST_GDTR_BASE, vmcs12->guest_gdtr_base);
|
vmcs_writel(GUEST_GDTR_BASE, vmcs12->guest_gdtr_base);
|
||||||
vmcs_writel(GUEST_IDTR_BASE, vmcs12->guest_idtr_base);
|
vmcs_writel(GUEST_IDTR_BASE, vmcs12->guest_idtr_base);
|
||||||
|
|
||||||
vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl);
|
if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) {
|
||||||
|
kvm_set_dr(vcpu, 7, vmcs12->guest_dr7);
|
||||||
|
vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl);
|
||||||
|
} else {
|
||||||
|
kvm_set_dr(vcpu, 7, vcpu->arch.dr7);
|
||||||
|
vmcs_write64(GUEST_IA32_DEBUGCTL, vmx->nested.vmcs01_debugctl);
|
||||||
|
}
|
||||||
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
|
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
|
||||||
vmcs12->vm_entry_intr_info_field);
|
vmcs12->vm_entry_intr_info_field);
|
||||||
vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
|
vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
|
||||||
|
@ -7846,7 +7871,6 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
||||||
vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
|
vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
|
||||||
vmcs12->guest_interruptibility_info);
|
vmcs12->guest_interruptibility_info);
|
||||||
vmcs_write32(GUEST_SYSENTER_CS, vmcs12->guest_sysenter_cs);
|
vmcs_write32(GUEST_SYSENTER_CS, vmcs12->guest_sysenter_cs);
|
||||||
kvm_set_dr(vcpu, 7, vmcs12->guest_dr7);
|
|
||||||
vmx_set_rflags(vcpu, vmcs12->guest_rflags);
|
vmx_set_rflags(vcpu, vmcs12->guest_rflags);
|
||||||
vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS,
|
vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS,
|
||||||
vmcs12->guest_pending_dbg_exceptions);
|
vmcs12->guest_pending_dbg_exceptions);
|
||||||
|
@ -8143,9 +8167,11 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
||||||
!vmx_control_verify(vmcs12->pin_based_vm_exec_control,
|
!vmx_control_verify(vmcs12->pin_based_vm_exec_control,
|
||||||
nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high) ||
|
nested_vmx_pinbased_ctls_low, nested_vmx_pinbased_ctls_high) ||
|
||||||
!vmx_control_verify(vmcs12->vm_exit_controls,
|
!vmx_control_verify(vmcs12->vm_exit_controls,
|
||||||
nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high) ||
|
nested_vmx_true_exit_ctls_low,
|
||||||
|
nested_vmx_exit_ctls_high) ||
|
||||||
!vmx_control_verify(vmcs12->vm_entry_controls,
|
!vmx_control_verify(vmcs12->vm_entry_controls,
|
||||||
nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high))
|
nested_vmx_true_entry_ctls_low,
|
||||||
|
nested_vmx_entry_ctls_high))
|
||||||
{
|
{
|
||||||
nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
|
nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -8222,6 +8248,9 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
||||||
|
|
||||||
vmx->nested.vmcs01_tsc_offset = vmcs_read64(TSC_OFFSET);
|
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);
|
||||||
|
|
||||||
cpu = get_cpu();
|
cpu = get_cpu();
|
||||||
vmx->loaded_vmcs = vmcs02;
|
vmx->loaded_vmcs = vmcs02;
|
||||||
vmx_vcpu_put(vcpu);
|
vmx_vcpu_put(vcpu);
|
||||||
|
@ -8399,7 +8428,6 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
||||||
vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
|
vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
|
||||||
vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
|
vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
|
||||||
|
|
||||||
kvm_get_dr(vcpu, 7, (unsigned long *)&vmcs12->guest_dr7);
|
|
||||||
vmcs12->guest_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
|
vmcs12->guest_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
|
||||||
vmcs12->guest_rip = kvm_register_read(vcpu, VCPU_REGS_RIP);
|
vmcs12->guest_rip = kvm_register_read(vcpu, VCPU_REGS_RIP);
|
||||||
vmcs12->guest_rflags = vmcs_readl(GUEST_RFLAGS);
|
vmcs12->guest_rflags = vmcs_readl(GUEST_RFLAGS);
|
||||||
|
@ -8478,9 +8506,13 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
||||||
(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
|
(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
|
||||||
(vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
|
(vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
|
||||||
|
|
||||||
|
if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS) {
|
||||||
|
kvm_get_dr(vcpu, 7, (unsigned long *)&vmcs12->guest_dr7);
|
||||||
|
vmcs12->guest_ia32_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: These cannot have changed unless we have MSR bitmaps and
|
/* TODO: These cannot have changed unless we have MSR bitmaps and
|
||||||
* the relevant bit asks not to trap the change */
|
* the relevant bit asks not to trap the change */
|
||||||
vmcs12->guest_ia32_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
|
|
||||||
if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_PAT)
|
if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_PAT)
|
||||||
vmcs12->guest_ia32_pat = vmcs_read64(GUEST_IA32_PAT);
|
vmcs12->guest_ia32_pat = vmcs_read64(GUEST_IA32_PAT);
|
||||||
if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_EFER)
|
if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_IA32_EFER)
|
||||||
|
|
Loading…
Reference in New Issue