Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm updates from Paolo Bonzini: "ARM: - Move the arch-specific code into arch/arm64/kvm - Start the post-32bit cleanup - Cherry-pick a few non-invasive pre-NV patches x86: - Rework of TLB flushing - Rework of event injection, especially with respect to nested virtualization - Nested AMD event injection facelift, building on the rework of generic code and fixing a lot of corner cases - Nested AMD live migration support - Optimization for TSC deadline MSR writes and IPIs - Various cleanups - Asynchronous page fault cleanups (from tglx, common topic branch with tip tree) - Interrupt-based delivery of asynchronous "page ready" events (host side) - Hyper-V MSRs and hypercalls for guest debugging - VMX preemption timer fixes s390: - Cleanups Generic: - switch vCPU thread wakeup from swait to rcuwait The other architectures, and the guest side of the asynchronous page fault work, will come next week" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (256 commits) KVM: selftests: fix rdtsc() for vmx_tsc_adjust_test KVM: check userspace_addr for all memslots KVM: selftests: update hyperv_cpuid with SynDBG tests x86/kvm/hyper-v: Add support for synthetic debugger via hypercalls x86/kvm/hyper-v: enable hypercalls regardless of hypercall page x86/kvm/hyper-v: Add support for synthetic debugger interface x86/hyper-v: Add synthetic debugger definitions KVM: selftests: VMX preemption timer migration test KVM: nVMX: Fix VMX preemption timer migration x86/kvm/hyper-v: Explicitly align hcall param for kvm_hyperv_exit KVM: x86/pmu: Support full width counting KVM: x86/pmu: Tweak kvm_pmu_get_msr to pass 'struct msr_data' in KVM: x86: announce KVM_FEATURE_ASYNC_PF_INT KVM: x86: acknowledgment mechanism for async pf page ready notifications KVM: x86: interrupt based APF 'page ready' event delivery KVM: introduce kvm_read_guest_offset_cached() KVM: rename kvm_arch_can_inject_async_page_present() to kvm_arch_can_dequeue_async_page_present() KVM: x86: extend struct kvm_vcpu_pv_apf_data with token info Revert "KVM: async_pf: Fix #DF due to inject "Page not Present" and "Page Ready" exceptions simultaneously" KVM: VMX: Replace zero-length array with flexible-array ...
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -215,21 +215,22 @@ static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
|
||||
return pmc;
|
||||
}
|
||||
|
||||
static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
|
||||
static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
struct kvm_pmc *pmc;
|
||||
u32 msr = msr_info->index;
|
||||
|
||||
/* MSR_PERFCTRn */
|
||||
pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_COUNTER);
|
||||
if (pmc) {
|
||||
*data = pmc_read_counter(pmc);
|
||||
msr_info->data = pmc_read_counter(pmc);
|
||||
return 0;
|
||||
}
|
||||
/* MSR_EVNTSELn */
|
||||
pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_EVNTSEL);
|
||||
if (pmc) {
|
||||
*data = pmc->eventsel;
|
||||
msr_info->data = pmc->eventsel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <asm/debugreg.h>
|
||||
#include <asm/kvm_para.h>
|
||||
#include <asm/irq_remapping.h>
|
||||
#include <asm/mce.h>
|
||||
#include <asm/spec-ctrl.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
|
||||
@@ -264,6 +265,7 @@ static int get_npt_level(struct kvm_vcpu *vcpu)
|
||||
|
||||
void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
vcpu->arch.efer = efer;
|
||||
|
||||
if (!npt_enabled) {
|
||||
@@ -274,8 +276,13 @@ void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
||||
efer &= ~EFER_LME;
|
||||
}
|
||||
|
||||
to_svm(vcpu)->vmcb->save.efer = efer | EFER_SVME;
|
||||
mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR);
|
||||
if (!(efer & EFER_SVME)) {
|
||||
svm_leave_nested(svm);
|
||||
svm_set_gif(svm, true);
|
||||
}
|
||||
|
||||
svm->vmcb->save.efer = efer | EFER_SVME;
|
||||
mark_dirty(svm->vmcb, VMCB_CR);
|
||||
}
|
||||
|
||||
static int is_external_interrupt(u32 info)
|
||||
@@ -318,9 +325,6 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
|
||||
if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP))
|
||||
return 0;
|
||||
} else {
|
||||
if (svm->next_rip - kvm_rip_read(vcpu) > MAX_INST_SIZE)
|
||||
pr_err("%s: ip 0x%lx next 0x%llx\n",
|
||||
__func__, kvm_rip_read(vcpu), svm->next_rip);
|
||||
kvm_rip_write(vcpu, svm->next_rip);
|
||||
}
|
||||
svm_set_interrupt_shadow(vcpu, 0);
|
||||
@@ -333,17 +337,8 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu)
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
unsigned nr = vcpu->arch.exception.nr;
|
||||
bool has_error_code = vcpu->arch.exception.has_error_code;
|
||||
bool reinject = vcpu->arch.exception.injected;
|
||||
u32 error_code = vcpu->arch.exception.error_code;
|
||||
|
||||
/*
|
||||
* If we are within a nested VM we'd better #VMEXIT and let the guest
|
||||
* handle the exception
|
||||
*/
|
||||
if (!reinject &&
|
||||
nested_svm_check_exception(svm, nr, has_error_code, error_code))
|
||||
return;
|
||||
|
||||
kvm_deliver_exception_payload(&svm->vcpu);
|
||||
|
||||
if (nr == BP_VECTOR && !nrips) {
|
||||
@@ -780,7 +775,7 @@ static __init void svm_adjust_mmio_mask(void)
|
||||
*/
|
||||
mask = (mask_bit < 52) ? rsvd_bits(mask_bit, 51) | PT_PRESENT_MASK : 0;
|
||||
|
||||
kvm_mmu_set_mmio_spte_mask(mask, mask, PT_WRITABLE_MASK | PT_USER_MASK);
|
||||
kvm_mmu_set_mmio_spte_mask(mask, PT_WRITABLE_MASK | PT_USER_MASK);
|
||||
}
|
||||
|
||||
static void svm_hardware_teardown(void)
|
||||
@@ -890,7 +885,7 @@ static __init int svm_hardware_setup(void)
|
||||
if (npt_enabled && !npt)
|
||||
npt_enabled = false;
|
||||
|
||||
kvm_configure_mmu(npt_enabled, PT_PDPE_LEVEL);
|
||||
kvm_configure_mmu(npt_enabled, PG_LEVEL_1G);
|
||||
pr_info("kvm: Nested Paging %sabled\n", npt_enabled ? "en" : "dis");
|
||||
|
||||
if (nrips) {
|
||||
@@ -953,16 +948,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
|
||||
seg->base = 0;
|
||||
}
|
||||
|
||||
static u64 svm_read_l1_tsc_offset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
if (is_guest_mode(vcpu))
|
||||
return svm->nested.hsave->control.tsc_offset;
|
||||
|
||||
return vcpu->arch.tsc_offset;
|
||||
}
|
||||
|
||||
static u64 svm_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
@@ -1208,6 +1193,7 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
|
||||
svm->avic_is_running = true;
|
||||
|
||||
svm->nested.hsave = page_address(hsave_page);
|
||||
clear_page(svm->nested.hsave);
|
||||
|
||||
svm->msrpm = page_address(msrpm_pages);
|
||||
svm_vcpu_init_msrpm(svm->msrpm);
|
||||
@@ -1364,12 +1350,13 @@ static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void svm_enable_vintr(struct vcpu_svm *svm)
|
||||
static void svm_set_vintr(struct vcpu_svm *svm)
|
||||
{
|
||||
struct vmcb_control_area *control;
|
||||
|
||||
/* The following fields are ignored when AVIC is enabled */
|
||||
WARN_ON(kvm_vcpu_apicv_active(&svm->vcpu));
|
||||
set_intercept(svm, INTERCEPT_VINTR);
|
||||
|
||||
/*
|
||||
* This is just a dummy VINTR to actually cause a vmexit to happen.
|
||||
@@ -1383,18 +1370,19 @@ static inline void svm_enable_vintr(struct vcpu_svm *svm)
|
||||
mark_dirty(svm->vmcb, VMCB_INTR);
|
||||
}
|
||||
|
||||
static void svm_set_vintr(struct vcpu_svm *svm)
|
||||
{
|
||||
set_intercept(svm, INTERCEPT_VINTR);
|
||||
if (is_intercept(svm, INTERCEPT_VINTR))
|
||||
svm_enable_vintr(svm);
|
||||
}
|
||||
|
||||
static void svm_clear_vintr(struct vcpu_svm *svm)
|
||||
{
|
||||
const u32 mask = V_TPR_MASK | V_GIF_ENABLE_MASK | V_GIF_MASK | V_INTR_MASKING_MASK;
|
||||
clr_intercept(svm, INTERCEPT_VINTR);
|
||||
|
||||
svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
|
||||
/* Drop int_ctl fields related to VINTR injection. */
|
||||
svm->vmcb->control.int_ctl &= mask;
|
||||
if (is_guest_mode(&svm->vcpu)) {
|
||||
WARN_ON((svm->vmcb->control.int_ctl & V_TPR_MASK) !=
|
||||
(svm->nested.ctl.int_ctl & V_TPR_MASK));
|
||||
svm->vmcb->control.int_ctl |= svm->nested.ctl.int_ctl & ~mask;
|
||||
}
|
||||
|
||||
mark_dirty(svm->vmcb, VMCB_INTR);
|
||||
}
|
||||
|
||||
@@ -1533,14 +1521,6 @@ static void svm_set_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt)
|
||||
mark_dirty(svm->vmcb, VMCB_DT);
|
||||
}
|
||||
|
||||
static void svm_decache_cr0_guest_bits(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
}
|
||||
|
||||
static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
}
|
||||
|
||||
static void update_cr0_intercept(struct vcpu_svm *svm)
|
||||
{
|
||||
ulong gcr0 = svm->vcpu.arch.cr0;
|
||||
@@ -1603,7 +1583,7 @@ int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
|
||||
return 1;
|
||||
|
||||
if (npt_enabled && ((old_cr4 ^ cr4) & X86_CR4_PGE))
|
||||
svm_flush_tlb(vcpu, true);
|
||||
svm_flush_tlb(vcpu);
|
||||
|
||||
vcpu->arch.cr4 = cr4;
|
||||
if (!npt_enabled)
|
||||
@@ -1842,6 +1822,25 @@ static bool is_erratum_383(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger machine check on the host. We assume all the MSRs are already set up
|
||||
* by the CPU and that we still run on the same CPU as the MCE occurred on.
|
||||
* We pass a fake environment to the machine check handler because we want
|
||||
* the guest to be always treated like user space, no matter what context
|
||||
* it used internally.
|
||||
*/
|
||||
static void kvm_machine_check(void)
|
||||
{
|
||||
#if defined(CONFIG_X86_MCE)
|
||||
struct pt_regs regs = {
|
||||
.cs = 3, /* Fake ring 3 no matter what the guest ran on */
|
||||
.flags = X86_EFLAGS_IF,
|
||||
};
|
||||
|
||||
do_machine_check(®s, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void svm_handle_mce(struct vcpu_svm *svm)
|
||||
{
|
||||
if (is_erratum_383()) {
|
||||
@@ -1860,11 +1859,7 @@ static void svm_handle_mce(struct vcpu_svm *svm)
|
||||
* On an #MC intercept the MCE handler is not called automatically in
|
||||
* the host. So do it by hand here.
|
||||
*/
|
||||
asm volatile (
|
||||
"int $0x12\n");
|
||||
/* not sure if we ever come back to this point */
|
||||
|
||||
return;
|
||||
kvm_machine_check();
|
||||
}
|
||||
|
||||
static int mc_interception(struct vcpu_svm *svm)
|
||||
@@ -1993,6 +1988,38 @@ static int vmrun_interception(struct vcpu_svm *svm)
|
||||
return nested_svm_vmrun(svm);
|
||||
}
|
||||
|
||||
void svm_set_gif(struct vcpu_svm *svm, bool value)
|
||||
{
|
||||
if (value) {
|
||||
/*
|
||||
* If VGIF is enabled, the STGI intercept is only added to
|
||||
* detect the opening of the SMI/NMI window; remove it now.
|
||||
* Likewise, clear the VINTR intercept, we will set it
|
||||
* again while processing KVM_REQ_EVENT if needed.
|
||||
*/
|
||||
if (vgif_enabled(svm))
|
||||
clr_intercept(svm, INTERCEPT_STGI);
|
||||
if (is_intercept(svm, SVM_EXIT_VINTR))
|
||||
svm_clear_vintr(svm);
|
||||
|
||||
enable_gif(svm);
|
||||
if (svm->vcpu.arch.smi_pending ||
|
||||
svm->vcpu.arch.nmi_pending ||
|
||||
kvm_cpu_has_injectable_intr(&svm->vcpu))
|
||||
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
|
||||
} else {
|
||||
disable_gif(svm);
|
||||
|
||||
/*
|
||||
* After a CLGI no interrupts should come. But if vGIF is
|
||||
* in use, we still rely on the VINTR intercept (rather than
|
||||
* STGI) to detect an open interrupt window.
|
||||
*/
|
||||
if (!vgif_enabled(svm))
|
||||
svm_clear_vintr(svm);
|
||||
}
|
||||
}
|
||||
|
||||
static int stgi_interception(struct vcpu_svm *svm)
|
||||
{
|
||||
int ret;
|
||||
@@ -2000,18 +2027,8 @@ static int stgi_interception(struct vcpu_svm *svm)
|
||||
if (nested_svm_check_permissions(svm))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If VGIF is enabled, the STGI intercept is only added to
|
||||
* detect the opening of the SMI/NMI window; remove it now.
|
||||
*/
|
||||
if (vgif_enabled(svm))
|
||||
clr_intercept(svm, INTERCEPT_STGI);
|
||||
|
||||
ret = kvm_skip_emulated_instruction(&svm->vcpu);
|
||||
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
|
||||
|
||||
enable_gif(svm);
|
||||
|
||||
svm_set_gif(svm, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2023,13 +2040,7 @@ static int clgi_interception(struct vcpu_svm *svm)
|
||||
return 1;
|
||||
|
||||
ret = kvm_skip_emulated_instruction(&svm->vcpu);
|
||||
|
||||
disable_gif(svm);
|
||||
|
||||
/* After a CLGI no interrupts should come */
|
||||
if (!kvm_vcpu_apicv_active(&svm->vcpu))
|
||||
svm_clear_vintr(svm);
|
||||
|
||||
svm_set_gif(svm, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2193,7 +2204,7 @@ static bool check_selective_cr0_intercepted(struct vcpu_svm *svm,
|
||||
bool ret = false;
|
||||
u64 intercept;
|
||||
|
||||
intercept = svm->nested.intercept;
|
||||
intercept = svm->nested.ctl.intercept;
|
||||
|
||||
if (!is_guest_mode(&svm->vcpu) ||
|
||||
(!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0))))
|
||||
@@ -2671,8 +2682,6 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
|
||||
*/
|
||||
svm_toggle_avic_for_irq_window(&svm->vcpu, true);
|
||||
|
||||
svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
|
||||
mark_dirty(svm->vmcb, VMCB_INTR);
|
||||
++svm->vcpu.stat.irq_window_exits;
|
||||
return 1;
|
||||
}
|
||||
@@ -2898,8 +2907,7 @@ static void svm_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2)
|
||||
*info2 = control->exit_info_2;
|
||||
}
|
||||
|
||||
static int handle_exit(struct kvm_vcpu *vcpu,
|
||||
enum exit_fastpath_completion exit_fastpath)
|
||||
static int handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
struct kvm_run *kvm_run = vcpu->run;
|
||||
@@ -2912,12 +2920,7 @@ static int handle_exit(struct kvm_vcpu *vcpu,
|
||||
if (npt_enabled)
|
||||
vcpu->arch.cr3 = svm->vmcb->save.cr3;
|
||||
|
||||
if (unlikely(svm->nested.exit_required)) {
|
||||
nested_svm_vmexit(svm);
|
||||
svm->nested.exit_required = false;
|
||||
|
||||
return 1;
|
||||
}
|
||||
svm_complete_interrupts(svm);
|
||||
|
||||
if (is_guest_mode(vcpu)) {
|
||||
int vmexit;
|
||||
@@ -2938,8 +2941,6 @@ static int handle_exit(struct kvm_vcpu *vcpu,
|
||||
return 1;
|
||||
}
|
||||
|
||||
svm_complete_interrupts(svm);
|
||||
|
||||
if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
|
||||
kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
|
||||
kvm_run->fail_entry.hardware_entry_failure_reason
|
||||
@@ -2957,10 +2958,10 @@ static int handle_exit(struct kvm_vcpu *vcpu,
|
||||
__func__, svm->vmcb->control.exit_int_info,
|
||||
exit_code);
|
||||
|
||||
if (exit_fastpath == EXIT_FASTPATH_SKIP_EMUL_INS) {
|
||||
kvm_skip_emulated_instruction(vcpu);
|
||||
if (exit_fastpath != EXIT_FASTPATH_NONE)
|
||||
return 1;
|
||||
} else if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
|
||||
|
||||
if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
|
||||
|| !svm_exit_handlers[exit_code]) {
|
||||
vcpu_unimpl(vcpu, "svm: unexpected exit reason 0x%x\n", exit_code);
|
||||
dump_vmcb(vcpu);
|
||||
@@ -3049,18 +3050,37 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
|
||||
set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
}
|
||||
|
||||
static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
|
||||
bool svm_nmi_blocked(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
struct vmcb *vmcb = svm->vmcb;
|
||||
int ret;
|
||||
ret = !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
|
||||
!(svm->vcpu.arch.hflags & HF_NMI_MASK);
|
||||
ret = ret && gif_set(svm) && nested_svm_nmi(svm);
|
||||
bool ret;
|
||||
|
||||
if (!gif_set(svm))
|
||||
return true;
|
||||
|
||||
if (is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
|
||||
return false;
|
||||
|
||||
ret = (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
|
||||
(svm->vcpu.arch.hflags & HF_NMI_MASK);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
if (svm->nested.nested_run_pending)
|
||||
return -EBUSY;
|
||||
|
||||
/* An NMI must not be injected into L2 if it's supposed to VM-Exit. */
|
||||
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
|
||||
return -EBUSY;
|
||||
|
||||
return !svm_nmi_blocked(vcpu);
|
||||
}
|
||||
|
||||
static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
@@ -3081,19 +3101,46 @@ static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
|
||||
}
|
||||
}
|
||||
|
||||
static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
|
||||
bool svm_interrupt_blocked(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
struct vmcb *vmcb = svm->vmcb;
|
||||
|
||||
if (!gif_set(svm) ||
|
||||
(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK))
|
||||
return 0;
|
||||
if (!gif_set(svm))
|
||||
return true;
|
||||
|
||||
if (is_guest_mode(vcpu) && (svm->vcpu.arch.hflags & HF_VINTR_MASK))
|
||||
return !!(svm->vcpu.arch.hflags & HF_HIF_MASK);
|
||||
else
|
||||
return !!(kvm_get_rflags(vcpu) & X86_EFLAGS_IF);
|
||||
if (is_guest_mode(vcpu)) {
|
||||
/* As long as interrupts are being delivered... */
|
||||
if ((svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK)
|
||||
? !(svm->nested.hsave->save.rflags & X86_EFLAGS_IF)
|
||||
: !(kvm_get_rflags(vcpu) & X86_EFLAGS_IF))
|
||||
return true;
|
||||
|
||||
/* ... vmexits aren't blocked by the interrupt shadow */
|
||||
if (nested_exit_on_intr(svm))
|
||||
return false;
|
||||
} else {
|
||||
if (!(kvm_get_rflags(vcpu) & X86_EFLAGS_IF))
|
||||
return true;
|
||||
}
|
||||
|
||||
return (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK);
|
||||
}
|
||||
|
||||
static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
if (svm->nested.nested_run_pending)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* An IRQ must not be injected into L2 if it's supposed to VM-Exit,
|
||||
* e.g. if the IRQ arrived asynchronously after checking nested events.
|
||||
*/
|
||||
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_intr(svm))
|
||||
return -EBUSY;
|
||||
|
||||
return !svm_interrupt_blocked(vcpu);
|
||||
}
|
||||
|
||||
static void enable_irq_window(struct kvm_vcpu *vcpu)
|
||||
@@ -3134,9 +3181,6 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
|
||||
return; /* STGI will cause a vm exit */
|
||||
}
|
||||
|
||||
if (svm->nested.exit_required)
|
||||
return; /* we're not going to run the guest yet */
|
||||
|
||||
/*
|
||||
* Something prevents NMI from been injected. Single step over possible
|
||||
* problem (IRET or exception injection or interrupt shadow)
|
||||
@@ -3156,10 +3200,17 @@ static int svm_set_identity_map_addr(struct kvm *kvm, u64 ident_addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa)
|
||||
void svm_flush_tlb(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
/*
|
||||
* Flush only the current ASID even if the TLB flush was invoked via
|
||||
* kvm_flush_remote_tlbs(). Although flushing remote TLBs requires all
|
||||
* ASIDs to be flushed, KVM uses a single ASID for L1 and L2, and
|
||||
* unconditionally does a TLB flush on both nested VM-Enter and nested
|
||||
* VM-Exit (via kvm_mmu_reset_context()).
|
||||
*/
|
||||
if (static_cpu_has(X86_FEATURE_FLUSHBYASID))
|
||||
svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
|
||||
else
|
||||
@@ -3279,23 +3330,27 @@ static void svm_cancel_injection(struct kvm_vcpu *vcpu)
|
||||
svm_complete_interrupts(svm);
|
||||
}
|
||||
|
||||
static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!is_guest_mode(vcpu) &&
|
||||
to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR &&
|
||||
to_svm(vcpu)->vmcb->control.exit_info_1)
|
||||
return handle_fastpath_set_msr_irqoff(vcpu);
|
||||
|
||||
return EXIT_FASTPATH_NONE;
|
||||
}
|
||||
|
||||
void __svm_vcpu_run(unsigned long vmcb_pa, unsigned long *regs);
|
||||
|
||||
static void svm_vcpu_run(struct kvm_vcpu *vcpu)
|
||||
static fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
fastpath_t exit_fastpath;
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
|
||||
svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
|
||||
svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
|
||||
|
||||
/*
|
||||
* A vmexit emulation is required before the vcpu can be executed
|
||||
* again.
|
||||
*/
|
||||
if (unlikely(svm->nested.exit_required))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Disable singlestep if we're injecting an interrupt/exception.
|
||||
* We don't want our modified rflags to be pushed on the stack where
|
||||
@@ -3387,6 +3442,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
|
||||
stgi();
|
||||
|
||||
/* Any pending NMI will happen here */
|
||||
exit_fastpath = svm_exit_handlers_fastpath(vcpu);
|
||||
|
||||
if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
|
||||
kvm_after_interrupt(&svm->vcpu);
|
||||
@@ -3394,12 +3450,17 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
|
||||
sync_cr8_to_lapic(vcpu);
|
||||
|
||||
svm->next_rip = 0;
|
||||
if (is_guest_mode(&svm->vcpu)) {
|
||||
sync_nested_vmcb_control(svm);
|
||||
svm->nested.nested_run_pending = 0;
|
||||
}
|
||||
|
||||
svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
|
||||
|
||||
/* if exit due to PF check for async PF */
|
||||
if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR)
|
||||
svm->vcpu.arch.apf.host_apf_reason = kvm_read_and_reset_pf_reason();
|
||||
svm->vcpu.arch.apf.host_apf_flags =
|
||||
kvm_read_and_reset_apf_flags();
|
||||
|
||||
if (npt_enabled) {
|
||||
vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR);
|
||||
@@ -3415,12 +3476,12 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
|
||||
svm_handle_mce(svm);
|
||||
|
||||
mark_all_clean(svm->vmcb);
|
||||
return exit_fastpath;
|
||||
}
|
||||
|
||||
static void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, unsigned long root)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
bool update_guest_cr3 = true;
|
||||
unsigned long cr3;
|
||||
|
||||
cr3 = __sme_set(root);
|
||||
@@ -3429,18 +3490,13 @@ static void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, unsigned long root)
|
||||
mark_dirty(svm->vmcb, VMCB_NPT);
|
||||
|
||||
/* Loading L2's CR3 is handled by enter_svm_guest_mode. */
|
||||
if (is_guest_mode(vcpu))
|
||||
update_guest_cr3 = false;
|
||||
else if (test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail))
|
||||
cr3 = vcpu->arch.cr3;
|
||||
else /* CR3 is already up-to-date. */
|
||||
update_guest_cr3 = false;
|
||||
if (!test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail))
|
||||
return;
|
||||
cr3 = vcpu->arch.cr3;
|
||||
}
|
||||
|
||||
if (update_guest_cr3) {
|
||||
svm->vmcb->save.cr3 = cr3;
|
||||
mark_dirty(svm->vmcb, VMCB_CR);
|
||||
}
|
||||
svm->vmcb->save.cr3 = cr3;
|
||||
mark_dirty(svm->vmcb, VMCB_CR);
|
||||
}
|
||||
|
||||
static int is_disabled(void)
|
||||
@@ -3475,7 +3531,7 @@ static bool svm_cpu_has_accelerated_tpr(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool svm_has_emulated_msr(int index)
|
||||
static bool svm_has_emulated_msr(u32 index)
|
||||
{
|
||||
switch (index) {
|
||||
case MSR_IA32_MCG_EXT_CTL:
|
||||
@@ -3628,7 +3684,7 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
|
||||
info->intercept == x86_intercept_clts)
|
||||
break;
|
||||
|
||||
intercept = svm->nested.intercept;
|
||||
intercept = svm->nested.ctl.intercept;
|
||||
|
||||
if (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0)))
|
||||
break;
|
||||
@@ -3716,13 +3772,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu,
|
||||
enum exit_fastpath_completion *exit_fastpath)
|
||||
static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!is_guest_mode(vcpu) &&
|
||||
to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR &&
|
||||
to_svm(vcpu)->vmcb->control.exit_info_1)
|
||||
*exit_fastpath = handle_fastpath_set_msr_irqoff(vcpu);
|
||||
}
|
||||
|
||||
static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
|
||||
@@ -3737,23 +3788,28 @@ static void svm_setup_mce(struct kvm_vcpu *vcpu)
|
||||
vcpu->arch.mcg_cap &= 0x1ff;
|
||||
}
|
||||
|
||||
static int svm_smi_allowed(struct kvm_vcpu *vcpu)
|
||||
bool svm_smi_blocked(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
/* Per APM Vol.2 15.22.2 "Response to SMI" */
|
||||
if (!gif_set(svm))
|
||||
return 0;
|
||||
return true;
|
||||
|
||||
if (is_guest_mode(&svm->vcpu) &&
|
||||
svm->nested.intercept & (1ULL << INTERCEPT_SMI)) {
|
||||
/* TODO: Might need to set exit_info_1 and exit_info_2 here */
|
||||
svm->vmcb->control.exit_code = SVM_EXIT_SMI;
|
||||
svm->nested.exit_required = true;
|
||||
return 0;
|
||||
}
|
||||
return is_smm(vcpu);
|
||||
}
|
||||
|
||||
return 1;
|
||||
static int svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
if (svm->nested.nested_run_pending)
|
||||
return -EBUSY;
|
||||
|
||||
/* An SMI must not be injected into L2 if it's supposed to VM-Exit. */
|
||||
if (for_injection && is_guest_mode(vcpu) && nested_exit_on_smi(svm))
|
||||
return -EBUSY;
|
||||
|
||||
return !svm_smi_blocked(vcpu);
|
||||
}
|
||||
|
||||
static int svm_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
|
||||
@@ -3793,12 +3849,13 @@ static int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
|
||||
if (kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb), &map) == -EINVAL)
|
||||
return 1;
|
||||
nested_vmcb = map.hva;
|
||||
enter_svm_guest_mode(svm, vmcb, nested_vmcb, &map);
|
||||
enter_svm_guest_mode(svm, vmcb, nested_vmcb);
|
||||
kvm_vcpu_unmap(&svm->vcpu, &map, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_smi_window(struct kvm_vcpu *vcpu)
|
||||
static void enable_smi_window(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
@@ -3806,9 +3863,9 @@ static int enable_smi_window(struct kvm_vcpu *vcpu)
|
||||
if (vgif_enabled(svm))
|
||||
set_intercept(svm, INTERCEPT_STGI);
|
||||
/* STGI will cause a vm exit */
|
||||
return 1;
|
||||
} else {
|
||||
/* We must be in SMM; RSM will cause a vmexit anyway. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
|
||||
@@ -3818,6 +3875,13 @@ static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
|
||||
bool smap = cr4 & X86_CR4_SMAP;
|
||||
bool is_user = svm_get_cpl(vcpu) == 3;
|
||||
|
||||
/*
|
||||
* If RIP is invalid, go ahead with emulation which will cause an
|
||||
* internal error exit.
|
||||
*/
|
||||
if (!kvm_vcpu_gfn_to_memslot(vcpu, kvm_rip_read(vcpu) >> PAGE_SHIFT))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Detect and workaround Errata 1096 Fam_17h_00_0Fh.
|
||||
*
|
||||
@@ -3876,9 +3940,9 @@ static bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu)
|
||||
/*
|
||||
* TODO: Last condition latch INIT signals on vCPU when
|
||||
* vCPU is in guest-mode and vmcb12 defines intercept on INIT.
|
||||
* To properly emulate the INIT intercept, SVM should implement
|
||||
* kvm_x86_ops.check_nested_events() and call nested_svm_vmexit()
|
||||
* there if an INIT signal is pending.
|
||||
* To properly emulate the INIT intercept,
|
||||
* svm_check_nested_events() should call nested_svm_vmexit()
|
||||
* if an INIT signal is pending.
|
||||
*/
|
||||
return !gif_set(svm) ||
|
||||
(svm->vmcb->control.intercept & (1ULL << INTERCEPT_INIT));
|
||||
@@ -3932,8 +3996,6 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
|
||||
.set_segment = svm_set_segment,
|
||||
.get_cpl = svm_get_cpl,
|
||||
.get_cs_db_l_bits = kvm_get_cs_db_l_bits,
|
||||
.decache_cr0_guest_bits = svm_decache_cr0_guest_bits,
|
||||
.decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
|
||||
.set_cr0 = svm_set_cr0,
|
||||
.set_cr4 = svm_set_cr4,
|
||||
.set_efer = svm_set_efer,
|
||||
@@ -3947,8 +4009,10 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
|
||||
.get_rflags = svm_get_rflags,
|
||||
.set_rflags = svm_set_rflags,
|
||||
|
||||
.tlb_flush = svm_flush_tlb,
|
||||
.tlb_flush_all = svm_flush_tlb,
|
||||
.tlb_flush_current = svm_flush_tlb,
|
||||
.tlb_flush_gva = svm_flush_tlb_gva,
|
||||
.tlb_flush_guest = svm_flush_tlb,
|
||||
|
||||
.run = svm_vcpu_run,
|
||||
.handle_exit = handle_exit,
|
||||
@@ -3989,7 +4053,6 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
|
||||
|
||||
.has_wbinvd_exit = svm_has_wbinvd_exit,
|
||||
|
||||
.read_l1_tsc_offset = svm_read_l1_tsc_offset,
|
||||
.write_l1_tsc_offset = svm_write_l1_tsc_offset,
|
||||
|
||||
.load_mmu_pgd = svm_load_mmu_pgd,
|
||||
@@ -4002,6 +4065,8 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
|
||||
.sched_in = svm_sched_in,
|
||||
|
||||
.pmu_ops = &amd_pmu_ops,
|
||||
.nested_ops = &svm_nested_ops,
|
||||
|
||||
.deliver_posted_interrupt = svm_deliver_avic_intr,
|
||||
.dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt,
|
||||
.update_pi_irte = svm_update_pi_irte,
|
||||
@@ -4016,14 +4081,9 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
|
||||
.mem_enc_reg_region = svm_register_enc_region,
|
||||
.mem_enc_unreg_region = svm_unregister_enc_region,
|
||||
|
||||
.nested_enable_evmcs = NULL,
|
||||
.nested_get_evmcs_version = NULL,
|
||||
|
||||
.need_emulation_on_page_fault = svm_need_emulation_on_page_fault,
|
||||
|
||||
.apic_init_signal_blocked = svm_apic_init_signal_blocked,
|
||||
|
||||
.check_nested_events = svm_check_nested_events,
|
||||
};
|
||||
|
||||
static struct kvm_x86_init_ops svm_init_ops __initdata = {
|
||||
|
@@ -86,25 +86,17 @@ struct nested_state {
|
||||
u64 hsave_msr;
|
||||
u64 vm_cr_msr;
|
||||
u64 vmcb;
|
||||
u32 host_intercept_exceptions;
|
||||
|
||||
/* These are the merged vectors */
|
||||
u32 *msrpm;
|
||||
|
||||
/* gpa pointers to the real vectors */
|
||||
u64 vmcb_msrpm;
|
||||
u64 vmcb_iopm;
|
||||
/* A VMRUN has started but has not yet been performed, so
|
||||
* we cannot inject a nested vmexit yet. */
|
||||
bool nested_run_pending;
|
||||
|
||||
/* A VMEXIT is required but not yet emulated */
|
||||
bool exit_required;
|
||||
|
||||
/* cache for intercepts of the guest */
|
||||
u32 intercept_cr;
|
||||
u32 intercept_dr;
|
||||
u32 intercept_exceptions;
|
||||
u64 intercept;
|
||||
|
||||
/* Nested Paging related state */
|
||||
u64 nested_cr3;
|
||||
/* cache for control fields of the guest */
|
||||
struct vmcb_control_area ctl;
|
||||
};
|
||||
|
||||
struct vcpu_svm {
|
||||
@@ -360,8 +352,12 @@ u32 svm_msrpm_offset(u32 msr);
|
||||
void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer);
|
||||
void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
|
||||
int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
|
||||
void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa);
|
||||
void svm_flush_tlb(struct kvm_vcpu *vcpu);
|
||||
void disable_nmi_singlestep(struct vcpu_svm *svm);
|
||||
bool svm_smi_blocked(struct kvm_vcpu *vcpu);
|
||||
bool svm_nmi_blocked(struct kvm_vcpu *vcpu);
|
||||
bool svm_interrupt_blocked(struct kvm_vcpu *vcpu);
|
||||
void svm_set_gif(struct vcpu_svm *svm, bool value);
|
||||
|
||||
/* nested.c */
|
||||
|
||||
@@ -369,28 +365,31 @@ void disable_nmi_singlestep(struct vcpu_svm *svm);
|
||||
#define NESTED_EXIT_DONE 1 /* Exit caused nested vmexit */
|
||||
#define NESTED_EXIT_CONTINUE 2 /* Further checks needed */
|
||||
|
||||
/* This function returns true if it is save to enable the nmi window */
|
||||
static inline bool nested_svm_nmi(struct vcpu_svm *svm)
|
||||
{
|
||||
if (!is_guest_mode(&svm->vcpu))
|
||||
return true;
|
||||
|
||||
if (!(svm->nested.intercept & (1ULL << INTERCEPT_NMI)))
|
||||
return true;
|
||||
|
||||
svm->vmcb->control.exit_code = SVM_EXIT_NMI;
|
||||
svm->nested.exit_required = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool svm_nested_virtualize_tpr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK);
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
return is_guest_mode(vcpu) && (svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK);
|
||||
}
|
||||
|
||||
static inline bool nested_exit_on_smi(struct vcpu_svm *svm)
|
||||
{
|
||||
return (svm->nested.ctl.intercept & (1ULL << INTERCEPT_SMI));
|
||||
}
|
||||
|
||||
static inline bool nested_exit_on_intr(struct vcpu_svm *svm)
|
||||
{
|
||||
return (svm->nested.ctl.intercept & (1ULL << INTERCEPT_INTR));
|
||||
}
|
||||
|
||||
static inline bool nested_exit_on_nmi(struct vcpu_svm *svm)
|
||||
{
|
||||
return (svm->nested.ctl.intercept & (1ULL << INTERCEPT_NMI));
|
||||
}
|
||||
|
||||
void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
|
||||
struct vmcb *nested_vmcb, struct kvm_host_map *map);
|
||||
struct vmcb *nested_vmcb);
|
||||
void svm_leave_nested(struct vcpu_svm *svm);
|
||||
int nested_svm_vmrun(struct vcpu_svm *svm);
|
||||
void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb);
|
||||
int nested_svm_vmexit(struct vcpu_svm *svm);
|
||||
@@ -398,8 +397,10 @@ int nested_svm_exit_handled(struct vcpu_svm *svm);
|
||||
int nested_svm_check_permissions(struct vcpu_svm *svm);
|
||||
int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
|
||||
bool has_error_code, u32 error_code);
|
||||
int svm_check_nested_events(struct kvm_vcpu *vcpu);
|
||||
int nested_svm_exit_special(struct vcpu_svm *svm);
|
||||
void sync_nested_vmcb_control(struct vcpu_svm *svm);
|
||||
|
||||
extern struct kvm_x86_nested_ops svm_nested_ops;
|
||||
|
||||
/* avic.c */
|
||||
|
||||
|
Reference in New Issue
Block a user