// SPDX-License-Identifier: GPL-2.0-only /* * Kernel-based Virtual Machine driver for Linux * * AMD SVM support * * Copyright (C) 2006 Qumranet, Inc. * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * Authors: * Yaniv Kamay <yaniv@qumranet.com> * Avi Kivity <avi@qumranet.com>
*/
if (vmcb->control.exit_code != SVM_EXIT_NPF) { /* * TODO: track the cause of the nested page fault, and * correctly fill in the high bits of exit_info_1.
*/
vmcb->control.exit_code = SVM_EXIT_NPF;
vmcb->control.exit_code_hi = 0;
vmcb->control.exit_info_1 = (1ULL << 32);
vmcb->control.exit_info_2 = fault->address;
}
/* * Note, nCR3 is "assumed" to be 32-byte aligned, i.e. the CPU ignores * nCR3[4:0] when loading PDPTEs from memory.
*/
ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(cr3), &pdpte,
(cr3 & GENMASK(11, 5)) + index * 8, 8); if (ret) return 0; return pdpte;
}
/* * The NPT format depends on L1's CR4 and EFER, which is in vmcb01. Note, * when called via KVM_SET_NESTED_STATE, that state may _not_ match current * vCPU state. CR0.WP is explicitly ignored, while CR0.PG is required.
*/
kvm_init_shadow_npt_mmu(vcpu, X86_CR0_PG, svm->vmcb01.ptr->save.cr4,
svm->vmcb01.ptr->save.efer,
svm->nested.ctl.nested_cr3);
vcpu->arch.mmu->get_guest_pgd = nested_svm_get_tdp_cr3;
vcpu->arch.mmu->get_pdptr = nested_svm_get_tdp_pdptr;
vcpu->arch.mmu->inject_page_fault = nested_svm_inject_npf_exit;
vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu;
}
c = &svm->vmcb->control;
h = &svm->vmcb01.ptr->control;
g = &svm->nested.ctl;
for (i = 0; i < MAX_INTERCEPT; i++)
c->intercepts[i] = h->intercepts[i];
if (g->int_ctl & V_INTR_MASKING_MASK) { /* * If L2 is active and V_INTR_MASKING is enabled in vmcb12, * disable intercept of CR8 writes as L2's CR8 does not affect * any interrupt KVM may want to inject. * * Similarly, disable intercept of virtual interrupts (used to * detect interrupt windows) if the saved RFLAGS.IF is '0', as * the effective RFLAGS.IF for L1 interrupts will never be set * while L2 is running (L2's RFLAGS.IF doesn't affect L1 IRQs).
*/
vmcb_clr_intercept(c, INTERCEPT_CR8_WRITE); if (!(svm->vmcb01.ptr->save.rflags & X86_EFLAGS_IF))
vmcb_clr_intercept(c, INTERCEPT_VINTR);
}
/* * We want to see VMMCALLs from a nested guest only when Hyper-V L2 TLB * flush feature is enabled.
*/ if (!nested_svm_l2_tlb_flush_enabled(&svm->vcpu))
vmcb_clr_intercept(c, INTERCEPT_VMMCALL);
for (i = 0; i < MAX_INTERCEPT; i++)
c->intercepts[i] |= g->intercepts[i];
/* If SMI is not intercepted, ignore guest SMI intercept as well */ if (!intercept_smi)
vmcb_clr_intercept(c, INTERCEPT_SMI);
if (nested_vmcb_needs_vls_intercept(svm)) { /* * If the virtual VMLOAD/VMSAVE is not enabled for the L2, * we must intercept these instructions to correctly * emulate them in case L1 doesn't intercept them.
*/
vmcb_set_intercept(c, INTERCEPT_VMLOAD);
vmcb_set_intercept(c, INTERCEPT_VMSAVE);
} else {
WARN_ON(!(c->virt_ext & VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK));
}
}
/* * This array (and its actual size) holds the set of offsets (indexing by chunk * size) to process when merging vmcb12's MSRPM with vmcb01's MSRPM. Note, the * set of MSRs for which interception is disabled in vmcb01 is per-vCPU, e.g. * based on CPUID features. This array only tracks MSRs that *might* be passed * through to the guest. * * Hardcode the capacity of the array based on the maximum number of _offsets_. * MSRs are batched together, so there are fewer offsets than MSRs.
*/ staticint nested_svm_msrpm_merge_offsets[7] __ro_after_init; staticint nested_svm_nr_msrpm_merge_offsets __ro_after_init; typedefunsignedlong nsvm_msrpm_merge_t;
/* * Merge L0's (KVM) and L1's (Nested VMCB) MSR permission bitmaps. The function * is optimized in that it only merges the parts where KVM MSR permission bitmap * may contain zero bits.
*/ staticbool nested_svm_merge_msrpm(struct kvm_vcpu *vcpu)
{ struct vcpu_svm *svm = to_svm(vcpu);
nsvm_msrpm_merge_t *msrpm02 = svm->nested.msrpm;
nsvm_msrpm_merge_t *msrpm01 = svm->msrpm; int i;
/* * MSR bitmap update can be skipped when: * - MSR bitmap for L1 hasn't changed. * - Nested hypervisor (L1) is attempting to launch the same L2 as * before. * - Nested hypervisor (L1) is using Hyper-V emulation interface and * tells KVM (L0) there were no changes in MSR bitmap for L2.
*/ #ifdef CONFIG_KVM_HYPERV if (!svm->nested.force_msr_bitmap_recalc) { struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments;
if (CC((control->nested_ctl & SVM_NESTED_CTL_NP_ENABLE) && !npt_enabled)) returnfalse;
if (CC(!nested_svm_check_bitmap_pa(vcpu, control->msrpm_base_pa,
MSRPM_SIZE))) returnfalse; if (CC(!nested_svm_check_bitmap_pa(vcpu, control->iopm_base_pa,
IOPM_SIZE))) returnfalse;
if (CC((control->int_ctl & V_NMI_ENABLE_MASK) &&
!vmcb12_is_intercept(control, INTERCEPT_NMI))) { returnfalse;
}
returntrue;
}
/* Common checks that apply to both L1 and L2 state. */ staticbool __nested_vmcb_check_save(struct kvm_vcpu *vcpu, struct vmcb_save_area_cached *save)
{ if (CC(!(save->efer & EFER_SVME))) returnfalse;
if (CC(!kvm_dr6_valid(save->dr6)) || CC(!kvm_dr7_valid(save->dr7))) returnfalse;
/* * These checks are also performed by KVM_SET_SREGS, * except that EFER.LMA is not checked by SVM against * CR0.PG && EFER.LME.
*/ if ((save->efer & EFER_LME) && (save->cr0 & X86_CR0_PG)) { if (CC(!(save->cr4 & X86_CR4_PAE)) ||
CC(!(save->cr0 & X86_CR0_PE)) ||
CC(!kvm_vcpu_is_legal_cr3(vcpu, save->cr3))) returnfalse;
}
/* Note, SVM doesn't have any additional restrictions on CR4. */ if (CC(!__kvm_is_valid_cr4(vcpu, save->cr4))) returnfalse;
if (CC(!kvm_valid_efer(vcpu, save->efer))) returnfalse;
/* Copy asid here because nested_vmcb_check_controls will check it. */
to->asid = from->asid;
to->msrpm_base_pa &= ~0x0fffULL;
to->iopm_base_pa &= ~0x0fffULL;
staticvoid __nested_copy_vmcb_save_to_cache(struct vmcb_save_area_cached *to, struct vmcb_save_area *from)
{ /* * Copy only fields that are validated, as we need them * to avoid TOC/TOU races.
*/
to->efer = from->efer;
to->cr0 = from->cr0;
to->cr3 = from->cr3;
to->cr4 = from->cr4;
/* * Synchronize fields that are written by the processor, so that * they can be copied back into the vmcb12.
*/ void nested_sync_control_from_vmcb02(struct vcpu_svm *svm)
{
u32 mask;
svm->nested.ctl.event_inj = svm->vmcb->control.event_inj;
svm->nested.ctl.event_inj_err = svm->vmcb->control.event_inj_err;
/* Only a few fields of int_ctl are written by the processor. */
mask = V_IRQ_MASK | V_TPR_MASK; /* * Don't sync vmcb02 V_IRQ back to vmcb12 if KVM (L0) is intercepting * virtual interrupts in order to request an interrupt window, as KVM * has usurped vmcb02's int_ctl. If an interrupt window opens before * the next VM-Exit, svm_clear_vintr() will restore vmcb12's int_ctl. * If no window opens, V_IRQ will be correctly preserved in vmcb12's * int_ctl (because it was never recognized while L2 was running).
*/ if (svm_is_intercept(svm, INTERCEPT_VINTR) &&
!test_bit(INTERCEPT_VINTR, (unsignedlong *)svm->nested.ctl.intercepts))
mask &= ~V_IRQ_MASK;
if (nested_vgif_enabled(svm))
mask |= V_GIF_MASK;
if (nested_vnmi_enabled(svm))
mask |= V_NMI_BLOCKING_MASK | V_NMI_PENDING_MASK;
/* * TODO: optimize unconditional TLB flush/MMU sync. A partial list of * things to fix before this can be conditional: * * - Flush TLBs for both L1 and L2 remote TLB flush * - Honor L1's request to flush an ASID on nested VMRUN * - Sync nested NPT MMU on VMRUN that flushes L2's ASID[*] * - Don't crush a pending TLB flush in vmcb02 on nested VMRUN * - Flush L1's ASID on KVM_REQ_TLB_FLUSH_GUEST * * [*] Unlike nested EPT, SVM's ASID management can invalidate nested * NPT guest-physical mappings on VMRUN.
*/
kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
}
/* * Load guest's/host's cr3 on nested vmentry or vmexit. @nested_npt is true * if we are emulating VM-Entry into a guest with NPT enabled.
*/ staticint nested_svm_load_cr3(struct kvm_vcpu *vcpu, unsignedlong cr3, bool nested_npt, bool reload_pdptrs)
{ if (CC(!kvm_vcpu_is_legal_cr3(vcpu, cr3))) return -EINVAL;
/* In case we don't even reach vcpu_run, the fields are not updated */
vmcb02->save.rax = vmcb12->save.rax;
vmcb02->save.rsp = vmcb12->save.rsp;
vmcb02->save.rip = vmcb12->save.rip;
/* These bits will be set properly on the first execution when new_vmc12 is true */ if (unlikely(new_vmcb12 || vmcb_is_dirty(vmcb12, VMCB_DR))) {
vmcb02->save.dr7 = svm->nested.save.dr7 | DR7_FIXED_1;
svm->vcpu.arch.dr6 = svm->nested.save.dr6 | DR6_ACTIVE_LOW;
vmcb_mark_dirty(vmcb02, VMCB_DR);
}
if (unlikely(guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
(svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK))) { /* * Reserved bits of DEBUGCTL are ignored. Be consistent with * svm_set_msr's definition of reserved bits.
*/
svm_copy_lbrs(vmcb02, vmcb12);
vmcb02->save.dbgctl &= ~DEBUGCTL_RESERVED_BITS;
} else {
svm_copy_lbrs(vmcb02, vmcb01);
}
svm_update_lbrv(&svm->vcpu);
}
if (vnmi) { if (vmcb01->control.int_ctl & V_NMI_PENDING_MASK) {
svm->vcpu.arch.nmi_pending++;
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
} if (nested_vnmi_enabled(svm))
int_ctl_vmcb12_bits |= (V_NMI_PENDING_MASK |
V_NMI_ENABLE_MASK |
V_NMI_BLOCKING_MASK);
}
/* Copied from vmcb01. msrpm_base can be overwritten later. */
vmcb02->control.nested_ctl = vmcb01->control.nested_ctl;
vmcb02->control.iopm_base_pa = vmcb01->control.iopm_base_pa;
vmcb02->control.msrpm_base_pa = vmcb01->control.msrpm_base_pa;
/* * Stash vmcb02's counter if the guest hasn't moved past the guilty * instruction; otherwise, reset the counter to '0'. * * In order to detect if L2 has made forward progress or not, track the * RIP at which a bus lock has occurred on a per-vmcb12 basis. If RIP * is changed, guest has clearly made forward progress, bus_lock_counter * still remained '1', so reset bus_lock_counter to '0'. Eg. In the * scenario, where a buslock happened in L1 before VMRUN, the bus lock * firmly happened on an instruction in the past. Even if vmcb01's * counter is still '1', (because the guilty instruction got patched), * the vCPU has clearly made forward progress and so KVM should reset * vmcb02's counter to '0'. * * If the RIP hasn't changed, stash the bus lock counter at nested VMRUN * to prevent the same guilty instruction from triggering a VM-Exit. Eg. * if userspace rate-limits the vCPU, then it's entirely possible that * L1's tick interrupt is pending by the time userspace re-runs the * vCPU. If KVM unconditionally clears the counter on VMRUN, then when * L1 re-enters L2, the same instruction will trigger a VM-Exit and the * entire cycle start over.
*/ if (vmcb02->save.rip && (svm->nested.ctl.bus_lock_rip == vmcb02->save.rip))
vmcb02->control.bus_lock_counter = 1; else
vmcb02->control.bus_lock_counter = 0;
/* Done at vmrun: asid. */
/* Also overwritten later if necessary. */
vmcb02->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
/* nested_cr3. */ if (nested_npt_enabled(svm))
nested_svm_init_mmu_context(vcpu);
/* * next_rip is consumed on VMRUN as the return address pushed on the * stack for injected soft exceptions/interrupts. If nrips is exposed * to L1, take it verbatim from vmcb12. If nrips is supported in * hardware but not exposed to L1, stuff the actual L2 RIP to emulate * what a nrips=0 CPU would do (L1 is responsible for advancing RIP * prior to injecting the event).
*/ if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
vmcb02->control.next_rip = svm->nested.ctl.next_rip; elseif (boot_cpu_has(X86_FEATURE_NRIPS))
vmcb02->control.next_rip = vmcb12_rip;
/* ... but ensure filtering is disabled if so requested. */ if (vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_PAUSE)) { if (!pause_count12)
vmcb02->control.pause_filter_count = 0; if (!pause_thresh12)
vmcb02->control.pause_filter_thresh = 0;
}
}
/* * Merge guest and host intercepts - must be called with vcpu in * guest-mode to take effect.
*/
recalc_intercepts(svm);
}
staticvoid nested_svm_copy_common_state(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
{ /* * Some VMCB state is shared between L1 and L2 and thus has to be * moved at the time of nested vmrun and vmexit. * * VMLOAD/VMSAVE state would also belong in this category, but KVM * always performs VMLOAD and VMSAVE from the VMCB01.
*/
to_vmcb->save.spec_ctrl = from_vmcb->save.spec_ctrl;
}
int enter_svm_guest_mode(struct kvm_vcpu *vcpu, u64 vmcb12_gpa, struct vmcb *vmcb12, bool from_vmrun)
{ struct vcpu_svm *svm = to_svm(vcpu); int ret;
if (!svm->nested.hsave_msr) {
kvm_inject_gp(vcpu, 0); return 1;
}
if (is_smm(vcpu)) {
kvm_queue_exception(vcpu, UD_VECTOR); return 1;
}
/* This fails when VP assist page is enabled but the supplied GPA is bogus */
ret = kvm_hv_verify_vp_assist(vcpu); if (ret) {
kvm_inject_gp(vcpu, 0); return ret;
}
/* * Since vmcb01 is not in use, we can use it to store some of the L1 * state.
*/
vmcb01->save.efer = vcpu->arch.efer;
vmcb01->save.cr0 = kvm_read_cr0(vcpu);
vmcb01->save.cr4 = vcpu->arch.cr4;
vmcb01->save.rflags = kvm_get_rflags(vcpu);
vmcb01->save.rip = kvm_rip_read(vcpu);
if (!npt_enabled)
vmcb01->save.cr3 = kvm_read_cr3(vcpu);
svm->nested.nested_run_pending = 1;
if (enter_svm_guest_mode(vcpu, vmcb12_gpa, vmcb12, true)) goto out_exit_err;
if (!kvm_pause_in_guest(vcpu->kvm)) {
vmcb01->control.pause_filter_count = vmcb02->control.pause_filter_count;
vmcb_mark_dirty(vmcb01, VMCB_INTERCEPTS);
}
/* * Invalidate bus_lock_rip unless KVM is still waiting for the guest * to make forward progress before re-enabling bus lock detection.
*/ if (!vmcb02->control.bus_lock_counter)
svm->nested.ctl.bus_lock_rip = INVALID_GPA;
/* * Rules for synchronizing int_ctl bits from vmcb02 to vmcb01: * * V_IRQ, V_IRQ_VECTOR, V_INTR_PRIO_MASK, V_IGN_TPR: If L1 doesn't * intercept interrupts, then KVM will use vmcb02's V_IRQ (and related * flags) to detect interrupt windows for L1 IRQs (even if L1 uses * virtual interrupt masking). Raise KVM_REQ_EVENT to ensure that * KVM re-requests an interrupt window if necessary, which implicitly * copies this bits from vmcb02 to vmcb01. * * V_TPR: If L1 doesn't use virtual interrupt masking, then L1's vTPR * is stored in vmcb02, but its value doesn't need to be copied from/to * vmcb01 because it is copied from/to the virtual APIC's TPR register * on each VM entry/exit. * * V_GIF: If nested vGIF is not used, KVM uses vmcb02's V_GIF for L1's * V_GIF. However, GIF is architecturally clear on each VM exit, thus * there is no need to copy V_GIF from vmcb02 to vmcb01.
*/ if (!nested_exit_on_intr(svm))
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
rc = nested_svm_load_cr3(vcpu, vmcb01->save.cr3, false, true); if (rc) return 1;
/* * Drop what we picked up for L2 via svm_complete_interrupts() so it * doesn't end up in L1.
*/
svm->vcpu.arch.nmi_injected = false;
kvm_clear_exception_queue(vcpu);
kvm_clear_interrupt_queue(vcpu);
/* * If we are here following the completion of a VMRUN that * is being single-stepped, queue the pending #DB intercept * right now so that it an be accounted for before we execute * L1's next instruction.
*/ if (unlikely(vmcb01->save.rflags & X86_EFLAGS_TF))
kvm_queue_exception(&(svm->vcpu), DB_VECTOR);
/* * Un-inhibit the AVIC right away, so that other vCPUs can start * to benefit from it right away.
*/ if (kvm_apicv_activated(vcpu->kvm))
__kvm_vcpu_update_apicv(vcpu);
/* * When last_vmcb12_gpa matches the current vmcb12 gpa, * some vmcb12 fields are not loaded if they are marked clean * in the vmcb12, since in this case they are up to date already. * * When the vmcb02 is freed, this optimization becomes invalid.
*/
svm->nested.last_vmcb12_gpa = INVALID_GPA;
if (ex->has_error_code)
vmcb->control.exit_info_1 = ex->error_code;
/* * EXITINFO2 is undefined for all exception intercepts other * than #PF.
*/ if (ex->vector == PF_VECTOR) { if (ex->has_payload)
vmcb->control.exit_info_2 = ex->payload; else
vmcb->control.exit_info_2 = vcpu->arch.cr2;
} elseif (ex->vector == DB_VECTOR) { /* See kvm_check_and_inject_events(). */
kvm_deliver_exception_payload(vcpu, ex);
staticint svm_check_nested_events(struct kvm_vcpu *vcpu)
{ struct kvm_lapic *apic = vcpu->arch.apic; struct vcpu_svm *svm = to_svm(vcpu); /* * Only a pending nested run blocks a pending exception. If there is a * previously injected event, the pending exception occurred while said * event was being delivered and thus needs to be handled.
*/ bool block_nested_exceptions = svm->nested.nested_run_pending; /* * New events (not exceptions) are only recognized at instruction * boundaries. If an event needs reinjection, then KVM is handling a * VM-Exit that occurred _during_ instruction execution; new events are * blocked until the instruction completes.
*/ bool block_nested_events = block_nested_exceptions ||
kvm_event_needs_reinjection(vcpu);
if (lapic_in_kernel(vcpu) &&
test_bit(KVM_APIC_INIT, &apic->pending_events)) { if (block_nested_events) return -EBUSY; if (!nested_exit_on_init(svm)) return 0;
nested_svm_simple_vmexit(svm, SVM_EXIT_INIT); return 0;
}
if (vcpu->arch.exception_vmexit.pending) { if (block_nested_exceptions) return -EBUSY;
nested_svm_inject_exception_vmexit(vcpu); return 0;
}
if (vcpu->arch.exception.pending) { if (block_nested_exceptions) return -EBUSY; return 0;
}
#ifdef CONFIG_KVM_SMM if (vcpu->arch.smi_pending && !svm_smi_blocked(vcpu)) { if (block_nested_events) return -EBUSY; if (!nested_exit_on_smi(svm)) return 0;
nested_svm_simple_vmexit(svm, SVM_EXIT_SMI); return 0;
} #endif
if (vcpu->arch.nmi_pending && !svm_nmi_blocked(vcpu)) { if (block_nested_events) return -EBUSY; if (!nested_exit_on_nmi(svm)) return 0;
nested_svm_simple_vmexit(svm, SVM_EXIT_NMI); return 0;
}
if (kvm_cpu_has_interrupt(vcpu) && !svm_interrupt_blocked(vcpu)) { if (block_nested_events) return -EBUSY; if (!nested_exit_on_intr(svm)) return 0;
trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
nested_svm_simple_vmexit(svm, SVM_EXIT_INTR); return 0;
}
if (!vcpu) return kvm_state.size + KVM_STATE_NESTED_SVM_VMCB_SIZE;
svm = to_svm(vcpu);
if (user_data_size < kvm_state.size) goto out;
/* First fill in the header and copy it out. */ if (is_guest_mode(vcpu)) {
kvm_state.hdr.svm.vmcb_pa = svm->nested.vmcb12_gpa;
kvm_state.size += KVM_STATE_NESTED_SVM_VMCB_SIZE;
kvm_state.flags |= KVM_STATE_NESTED_GUEST_MODE;
if (svm->nested.nested_run_pending)
kvm_state.flags |= KVM_STATE_NESTED_RUN_PENDING;
}
if (gif_set(svm))
kvm_state.flags |= KVM_STATE_NESTED_GIF_SET;
if (copy_to_user(user_kvm_nested_state, &kvm_state, sizeof(kvm_state))) return -EFAULT;
if (!is_guest_mode(vcpu)) goto out;
/* * Copy over the full size of the VMCB rather than just the size * of the structs.
*/ if (clear_user(user_vmcb, KVM_STATE_NESTED_SVM_VMCB_SIZE)) return -EFAULT;
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); if (!ctl) return -ENOMEM;
nested_copy_vmcb_cache_to_control(ctl, &svm->nested.ctl);
r = copy_to_user(&user_vmcb->control, ctl, sizeof(user_vmcb->control));
kfree(ctl); if (r) return -EFAULT;
if (copy_to_user(&user_vmcb->save, &svm->vmcb01.ptr->save, sizeof(user_vmcb->save))) return -EFAULT;
out: return kvm_state.size;
}
if (kvm_state->format != KVM_STATE_NESTED_FORMAT_SVM) return -EINVAL;
if (kvm_state->flags & ~(KVM_STATE_NESTED_GUEST_MODE |
KVM_STATE_NESTED_RUN_PENDING |
KVM_STATE_NESTED_GIF_SET)) return -EINVAL;
/* * If in guest mode, vcpu->arch.efer actually refers to the L2 guest's * EFER.SVME, but EFER.SVME still has to be 1 for VMRUN to succeed.
*/ if (!(vcpu->arch.efer & EFER_SVME)) { /* GIF=1 and no guest mode are required if SVME=0. */ if (kvm_state->flags != KVM_STATE_NESTED_GIF_SET) return -EINVAL;
}
/* SMM temporarily disables SVM, so we cannot be in guest mode. */ if (is_smm(vcpu) && (kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE)) return -EINVAL;
if (!page_address_valid(vcpu, kvm_state->hdr.svm.vmcb_pa)) return -EINVAL; if (kvm_state->size < sizeof(*kvm_state) + KVM_STATE_NESTED_SVM_VMCB_SIZE) return -EINVAL;
ret = -ENOMEM;
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
save = kzalloc(sizeof(*save), GFP_KERNEL); if (!ctl || !save) goto out_free;
ret = -EFAULT; if (copy_from_user(ctl, &user_vmcb->control, sizeof(*ctl))) goto out_free; if (copy_from_user(save, &user_vmcb->save, sizeof(*save))) goto out_free;
ret = -EINVAL;
__nested_copy_vmcb_control_to_cache(vcpu, &ctl_cached, ctl); if (!__nested_vmcb_check_controls(vcpu, &ctl_cached)) goto out_free;
/* * Processor state contains L2 state. Check that it is * valid for guest mode (see nested_vmcb_check_save).
*/
cr0 = kvm_read_cr0(vcpu); if (((cr0 & X86_CR0_CD) == 0) && (cr0 & X86_CR0_NW)) goto out_free;
/* * Validate host state saved from before VMRUN (see * nested_svm_check_permissions).
*/
__nested_copy_vmcb_save_to_cache(&save_cached, save); if (!(save->cr0 & X86_CR0_PG) ||
!(save->cr0 & X86_CR0_PE) ||
(save->rflags & X86_EFLAGS_VM) ||
!__nested_vmcb_check_save(vcpu, &save_cached)) goto out_free;
/* * All checks done, we can enter guest mode. Userspace provides * vmcb12.control, which will be combined with L1 and stored into * vmcb02, and the L1 save state which we store in vmcb01. * L2 registers if needed are moved from the current VMCB to VMCB02.
*/
if (is_guest_mode(vcpu))
svm_leave_nested(vcpu); else
svm->nested.vmcb02.ptr->save = svm->vmcb01.ptr->save;
/* * While the nested guest CR3 is already checked and set by * KVM_SET_SREGS, it was set when nested state was yet loaded, * thus MMU might not be initialized correctly. * Set it again to fix this.
*/
ret = nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
nested_npt_enabled(svm), false); if (WARN_ON_ONCE(ret)) goto out_free;
svm->nested.force_msr_bitmap_recalc = true;
kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
ret = 0;
out_free:
kfree(save);
kfree(ctl);
return ret;
}
staticbool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
{ if (WARN_ON(!is_guest_mode(vcpu))) returntrue;
if (!vcpu->arch.pdptrs_from_userspace &&
!nested_npt_enabled(to_svm(vcpu)) && is_pae_paging(vcpu)) /* * Reload the guest's PDPTRs since after a migration * the guest CR3 might be restored prior to setting the nested * state which can lead to a load of wrong PDPTRs.
*/ if (CC(!load_pdptrs(vcpu, vcpu->arch.cr3))) returnfalse;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.