[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <87d0917ezq.fsf@vitty.brq.redhat.com>
Date: Tue, 24 Mar 2020 20:02:49 +0100
From: Vitaly Kuznetsov <vkuznets@...hat.com>
To: Joerg Roedel <joro@...tes.org>, Paolo Bonzini <pbonzini@...hat.com>
Cc: Sean Christopherson <sean.j.christopherson@...el.com>,
Wanpeng Li <wanpengli@...cent.com>,
Jim Mattson <jmattson@...gle.com>,
Joerg Roedel <joro@...tes.org>,
Suravee Suthikulpanit <suravee.suthikulpanit@....com>,
Tom Lendacky <thomas.lendacky@....com>,
Ashish Kalra <Ashish.Kalra@....com>,
Brijesh Singh <brijesh.singh@....com>, kvm@...r.kernel.org,
linux-kernel@...r.kernel.org, Joerg Roedel <jroedel@...e.de>
Subject: Re: [PATCH 2/4] KVM: SVM: Move Nested SVM Implementation to nested.c
Joerg Roedel <joro@...tes.org> writes:
> From: Joerg Roedel <jroedel@...e.de>
>
> Split out the code for the nested SVM implementation and move it to a
> separate file.
>
> Signed-off-by: Joerg Roedel <jroedel@...e.de>
> ---
> arch/x86/kvm/Makefile | 2 +-
> arch/x86/kvm/svm/nested.c | 823 ++++++++++++++++++++++++++
> arch/x86/kvm/svm/svm.c | 1155 +------------------------------------
> arch/x86/kvm/svm/svm.h | 381 ++++++++++++
> 4 files changed, 1216 insertions(+), 1145 deletions(-)
> create mode 100644 arch/x86/kvm/svm/nested.c
> create mode 100644 arch/x86/kvm/svm/svm.h
>
> diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
> index c6f14e3cc5ab..63ae654f7f97 100644
> --- a/arch/x86/kvm/Makefile
> +++ b/arch/x86/kvm/Makefile
> @@ -14,7 +14,7 @@ kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \
> hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o
>
> kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o vmx/evmcs.o vmx/nested.o
> -kvm-amd-y += svm/svm.o svm/pmu.o
> +kvm-amd-y += svm/svm.o svm/pmu.o svm/nested.o
>
> obj-$(CONFIG_KVM) += kvm.o
> obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> new file mode 100644
> index 000000000000..961f413626d0
> --- /dev/null
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -0,0 +1,823 @@
> +// 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@...ranet.com>
> + * Avi Kivity <avi@...ranet.com>
> + */
> +
> +#define pr_fmt(fmt) "SVM: " fmt
> +
> +#include <linux/kvm_types.h>
> +#include <linux/kvm_host.h>
> +#include <linux/kernel.h>
> +
> +#include <asm/msr-index.h>
> +
> +#include "kvm_emulate.h"
> +#include "trace.h"
> +#include "mmu.h"
> +#include "x86.h"
> +#include "svm.h"
> +
> +static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
> + struct x86_exception *fault)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> +
> + if (svm->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.
> + */
> + svm->vmcb->control.exit_code = SVM_EXIT_NPF;
> + svm->vmcb->control.exit_code_hi = 0;
> + svm->vmcb->control.exit_info_1 = (1ULL << 32);
> + svm->vmcb->control.exit_info_2 = fault->address;
> + }
> +
> + svm->vmcb->control.exit_info_1 &= ~0xffffffffULL;
> + svm->vmcb->control.exit_info_1 |= fault->error_code;
> +
> + /*
> + * The present bit is always zero for page structure faults on real
> + * hardware.
> + */
> + if (svm->vmcb->control.exit_info_1 & (2ULL << 32))
> + svm->vmcb->control.exit_info_1 &= ~1;
> +
> + nested_svm_vmexit(svm);
> +}
> +
> +static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> + u64 cr3 = svm->nested.nested_cr3;
> + u64 pdpte;
> + int ret;
> +
> + ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(__sme_clr(cr3)), &pdpte,
> + offset_in_page(cr3) + index * 8, 8);
> + if (ret)
> + return 0;
> + return pdpte;
> +}
> +
> +static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> +
> + return svm->nested.nested_cr3;
> +}
> +
> +static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
> +{
> + WARN_ON(mmu_is_nested(vcpu));
> +
> + vcpu->arch.mmu = &vcpu->arch.guest_mmu;
> + kvm_init_shadow_mmu(vcpu);
> + 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.mmu->shadow_root_level = kvm_x86_ops->get_tdp_level(vcpu);
> + reset_shadow_zero_bits_mask(vcpu, vcpu->arch.mmu);
> + vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu;
> +}
> +
> +static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
> +{
> + vcpu->arch.mmu = &vcpu->arch.root_mmu;
> + vcpu->arch.walk_mmu = &vcpu->arch.root_mmu;
> +}
> +
> +void recalc_intercepts(struct vcpu_svm *svm)
> +{
> + struct vmcb_control_area *c, *h;
> + struct nested_state *g;
> +
> + mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
> +
> + if (!is_guest_mode(&svm->vcpu))
> + return;
> +
> + c = &svm->vmcb->control;
> + h = &svm->nested.hsave->control;
> + g = &svm->nested;
> +
> + c->intercept_cr = h->intercept_cr;
> + c->intercept_dr = h->intercept_dr;
> + c->intercept_exceptions = h->intercept_exceptions;
> + c->intercept = h->intercept;
> +
> + if (svm->vcpu.arch.hflags & HF_VINTR_MASK) {
> + /* We only want the cr8 intercept bits of L1 */
> + c->intercept_cr &= ~(1U << INTERCEPT_CR8_READ);
> + c->intercept_cr &= ~(1U << INTERCEPT_CR8_WRITE);
> +
> + /*
> + * Once running L2 with HF_VINTR_MASK, EFLAGS.IF does not
> + * affect any interrupt we may want to inject; therefore,
> + * interrupt window vmexits are irrelevant to L0.
> + */
> + c->intercept &= ~(1ULL << INTERCEPT_VINTR);
> + }
> +
> + /* We don't want to see VMMCALLs from a nested guest */
> + c->intercept &= ~(1ULL << INTERCEPT_VMMCALL);
> +
> + c->intercept_cr |= g->intercept_cr;
> + c->intercept_dr |= g->intercept_dr;
> + c->intercept_exceptions |= g->intercept_exceptions;
> + c->intercept |= g->intercept;
> +}
> +
> +static void copy_vmcb_control_area(struct vmcb *dst_vmcb, struct vmcb *from_vmcb)
> +{
> + struct vmcb_control_area *dst = &dst_vmcb->control;
> + struct vmcb_control_area *from = &from_vmcb->control;
> +
> + dst->intercept_cr = from->intercept_cr;
> + dst->intercept_dr = from->intercept_dr;
> + dst->intercept_exceptions = from->intercept_exceptions;
> + dst->intercept = from->intercept;
> + dst->iopm_base_pa = from->iopm_base_pa;
> + dst->msrpm_base_pa = from->msrpm_base_pa;
> + dst->tsc_offset = from->tsc_offset;
> + dst->asid = from->asid;
> + dst->tlb_ctl = from->tlb_ctl;
> + dst->int_ctl = from->int_ctl;
> + dst->int_vector = from->int_vector;
> + dst->int_state = from->int_state;
> + dst->exit_code = from->exit_code;
> + dst->exit_code_hi = from->exit_code_hi;
> + dst->exit_info_1 = from->exit_info_1;
> + dst->exit_info_2 = from->exit_info_2;
> + dst->exit_int_info = from->exit_int_info;
> + dst->exit_int_info_err = from->exit_int_info_err;
> + dst->nested_ctl = from->nested_ctl;
> + dst->event_inj = from->event_inj;
> + dst->event_inj_err = from->event_inj_err;
> + dst->nested_cr3 = from->nested_cr3;
> + dst->virt_ext = from->virt_ext;
> + dst->pause_filter_count = from->pause_filter_count;
> + dst->pause_filter_thresh = from->pause_filter_thresh;
> +}
> +
> +static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
> +{
> + /*
> + * This function merges the msr permission bitmaps of kvm and the
> + * nested vmcb. It is optimized in that it only merges the parts where
> + * the kvm msr permission bitmap may contain zero bits
> + */
> + int i;
> +
> + if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
> + return true;
> +
> + for (i = 0; i < MSRPM_OFFSETS; i++) {
> + u32 value, p;
> + u64 offset;
> +
> + if (msrpm_offsets[i] == 0xffffffff)
> + break;
> +
> + p = msrpm_offsets[i];
> + offset = svm->nested.vmcb_msrpm + (p * 4);
> +
> + if (kvm_vcpu_read_guest(&svm->vcpu, offset, &value, 4))
> + return false;
> +
> + svm->nested.msrpm[p] = svm->msrpm[p] | value;
> + }
> +
> + svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
> +
> + return true;
> +}
> +
> +static bool nested_vmcb_checks(struct vmcb *vmcb)
> +{
> + if ((vmcb->save.efer & EFER_SVME) == 0)
> + return false;
> +
> + if ((vmcb->control.intercept & (1ULL << INTERCEPT_VMRUN)) == 0)
> + return false;
> +
> + if (vmcb->control.asid == 0)
> + return false;
> +
> + if ((vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) &&
> + !npt_enabled)
> + return false;
> +
> + return true;
> +}
> +
> +void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
> + struct vmcb *nested_vmcb, struct kvm_host_map *map)
> +{
> + bool evaluate_pending_interrupts =
> + is_intercept(svm, INTERCEPT_VINTR) ||
> + is_intercept(svm, INTERCEPT_IRET);
> +
> + if (kvm_get_rflags(&svm->vcpu) & X86_EFLAGS_IF)
> + svm->vcpu.arch.hflags |= HF_HIF_MASK;
> + else
> + svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
> +
> + if (nested_vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) {
> + svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3;
> + nested_svm_init_mmu_context(&svm->vcpu);
> + }
> +
> + /* Load the nested guest state */
> + svm->vmcb->save.es = nested_vmcb->save.es;
> + svm->vmcb->save.cs = nested_vmcb->save.cs;
> + svm->vmcb->save.ss = nested_vmcb->save.ss;
> + svm->vmcb->save.ds = nested_vmcb->save.ds;
> + svm->vmcb->save.gdtr = nested_vmcb->save.gdtr;
> + svm->vmcb->save.idtr = nested_vmcb->save.idtr;
> + kvm_set_rflags(&svm->vcpu, nested_vmcb->save.rflags);
> + svm_set_efer(&svm->vcpu, nested_vmcb->save.efer);
> + svm_set_cr0(&svm->vcpu, nested_vmcb->save.cr0);
> + svm_set_cr4(&svm->vcpu, nested_vmcb->save.cr4);
> + if (npt_enabled) {
> + svm->vmcb->save.cr3 = nested_vmcb->save.cr3;
> + svm->vcpu.arch.cr3 = nested_vmcb->save.cr3;
> + } else
> + (void)kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
> +
> + /* Guest paging mode is active - reset mmu */
> + kvm_mmu_reset_context(&svm->vcpu);
> +
> + svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = nested_vmcb->save.cr2;
> + kvm_rax_write(&svm->vcpu, nested_vmcb->save.rax);
> + kvm_rsp_write(&svm->vcpu, nested_vmcb->save.rsp);
> + kvm_rip_write(&svm->vcpu, nested_vmcb->save.rip);
> +
> + /* In case we don't even reach vcpu_run, the fields are not updated */
> + svm->vmcb->save.rax = nested_vmcb->save.rax;
> + svm->vmcb->save.rsp = nested_vmcb->save.rsp;
> + svm->vmcb->save.rip = nested_vmcb->save.rip;
> + svm->vmcb->save.dr7 = nested_vmcb->save.dr7;
> + svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
> + svm->vmcb->save.cpl = nested_vmcb->save.cpl;
> +
> + svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa & ~0x0fffULL;
> + svm->nested.vmcb_iopm = nested_vmcb->control.iopm_base_pa & ~0x0fffULL;
> +
> + /* cache intercepts */
> + svm->nested.intercept_cr = nested_vmcb->control.intercept_cr;
> + svm->nested.intercept_dr = nested_vmcb->control.intercept_dr;
> + svm->nested.intercept_exceptions = nested_vmcb->control.intercept_exceptions;
> + svm->nested.intercept = nested_vmcb->control.intercept;
> +
> + svm_flush_tlb(&svm->vcpu, true);
> + svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
> + if (nested_vmcb->control.int_ctl & V_INTR_MASKING_MASK)
> + svm->vcpu.arch.hflags |= HF_VINTR_MASK;
> + else
> + svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
> +
> + svm->vcpu.arch.tsc_offset += nested_vmcb->control.tsc_offset;
> + svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset;
> +
> + svm->vmcb->control.virt_ext = nested_vmcb->control.virt_ext;
> + svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
> + svm->vmcb->control.int_state = nested_vmcb->control.int_state;
> + svm->vmcb->control.event_inj = nested_vmcb->control.event_inj;
> + svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err;
> +
> + svm->vmcb->control.pause_filter_count =
> + nested_vmcb->control.pause_filter_count;
> + svm->vmcb->control.pause_filter_thresh =
> + nested_vmcb->control.pause_filter_thresh;
> +
> + kvm_vcpu_unmap(&svm->vcpu, map, true);
> +
> + /* Enter Guest-Mode */
> + enter_guest_mode(&svm->vcpu);
> +
> + /*
> + * Merge guest and host intercepts - must be called with vcpu in
> + * guest-mode to take affect here
> + */
> + recalc_intercepts(svm);
> +
> + svm->nested.vmcb = vmcb_gpa;
> +
> + /*
> + * If L1 had a pending IRQ/NMI before executing VMRUN,
> + * which wasn't delivered because it was disallowed (e.g.
> + * interrupts disabled), L0 needs to evaluate if this pending
> + * event should cause an exit from L2 to L1 or be delivered
> + * directly to L2.
> + *
> + * Usually this would be handled by the processor noticing an
> + * IRQ/NMI window request. However, VMRUN can unblock interrupts
> + * by implicitly setting GIF, so force L0 to perform pending event
> + * evaluation by requesting a KVM_REQ_EVENT.
> + */
> + enable_gif(svm);
> + if (unlikely(evaluate_pending_interrupts))
> + kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
> +
> + mark_all_dirty(svm->vmcb);
> +}
> +
> +int nested_svm_vmrun(struct vcpu_svm *svm)
> +{
> + int ret;
> + struct vmcb *nested_vmcb;
> + struct vmcb *hsave = svm->nested.hsave;
> + struct vmcb *vmcb = svm->vmcb;
> + struct kvm_host_map map;
> + u64 vmcb_gpa;
> +
> + vmcb_gpa = svm->vmcb->save.rax;
> +
> + ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb_gpa), &map);
> + if (ret == -EINVAL) {
> + kvm_inject_gp(&svm->vcpu, 0);
> + return 1;
> + } else if (ret) {
> + return kvm_skip_emulated_instruction(&svm->vcpu);
> + }
> +
> + ret = kvm_skip_emulated_instruction(&svm->vcpu);
> +
> + nested_vmcb = map.hva;
> +
> + if (!nested_vmcb_checks(nested_vmcb)) {
> + nested_vmcb->control.exit_code = SVM_EXIT_ERR;
> + nested_vmcb->control.exit_code_hi = 0;
> + nested_vmcb->control.exit_info_1 = 0;
> + nested_vmcb->control.exit_info_2 = 0;
> +
> + kvm_vcpu_unmap(&svm->vcpu, &map, true);
> +
> + return ret;
> + }
> +
> + trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa,
> + nested_vmcb->save.rip,
> + nested_vmcb->control.int_ctl,
> + nested_vmcb->control.event_inj,
> + nested_vmcb->control.nested_ctl);
> +
> + trace_kvm_nested_intercepts(nested_vmcb->control.intercept_cr & 0xffff,
> + nested_vmcb->control.intercept_cr >> 16,
> + nested_vmcb->control.intercept_exceptions,
> + nested_vmcb->control.intercept);
> +
> + /* Clear internal status */
> + kvm_clear_exception_queue(&svm->vcpu);
> + kvm_clear_interrupt_queue(&svm->vcpu);
> +
> + /*
> + * Save the old vmcb, so we don't need to pick what we save, but can
> + * restore everything when a VMEXIT occurs
> + */
> + hsave->save.es = vmcb->save.es;
> + hsave->save.cs = vmcb->save.cs;
> + hsave->save.ss = vmcb->save.ss;
> + hsave->save.ds = vmcb->save.ds;
> + hsave->save.gdtr = vmcb->save.gdtr;
> + hsave->save.idtr = vmcb->save.idtr;
> + hsave->save.efer = svm->vcpu.arch.efer;
> + hsave->save.cr0 = kvm_read_cr0(&svm->vcpu);
> + hsave->save.cr4 = svm->vcpu.arch.cr4;
> + hsave->save.rflags = kvm_get_rflags(&svm->vcpu);
> + hsave->save.rip = kvm_rip_read(&svm->vcpu);
> + hsave->save.rsp = vmcb->save.rsp;
> + hsave->save.rax = vmcb->save.rax;
> + if (npt_enabled)
> + hsave->save.cr3 = vmcb->save.cr3;
> + else
> + hsave->save.cr3 = kvm_read_cr3(&svm->vcpu);
> +
> + copy_vmcb_control_area(hsave, vmcb);
> +
> + enter_svm_guest_mode(svm, vmcb_gpa, nested_vmcb, &map);
> +
> + if (!nested_svm_vmrun_msrpm(svm)) {
> + svm->vmcb->control.exit_code = SVM_EXIT_ERR;
> + svm->vmcb->control.exit_code_hi = 0;
> + svm->vmcb->control.exit_info_1 = 0;
> + svm->vmcb->control.exit_info_2 = 0;
> +
> + nested_svm_vmexit(svm);
> + }
> +
> + return ret;
> +}
> +
> +void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
> +{
> + to_vmcb->save.fs = from_vmcb->save.fs;
> + to_vmcb->save.gs = from_vmcb->save.gs;
> + to_vmcb->save.tr = from_vmcb->save.tr;
> + to_vmcb->save.ldtr = from_vmcb->save.ldtr;
> + to_vmcb->save.kernel_gs_base = from_vmcb->save.kernel_gs_base;
> + to_vmcb->save.star = from_vmcb->save.star;
> + to_vmcb->save.lstar = from_vmcb->save.lstar;
> + to_vmcb->save.cstar = from_vmcb->save.cstar;
> + to_vmcb->save.sfmask = from_vmcb->save.sfmask;
> + to_vmcb->save.sysenter_cs = from_vmcb->save.sysenter_cs;
> + to_vmcb->save.sysenter_esp = from_vmcb->save.sysenter_esp;
> + to_vmcb->save.sysenter_eip = from_vmcb->save.sysenter_eip;
> +}
> +
> +int nested_svm_vmexit(struct vcpu_svm *svm)
> +{
> + int rc;
> + struct vmcb *nested_vmcb;
> + struct vmcb *hsave = svm->nested.hsave;
> + struct vmcb *vmcb = svm->vmcb;
> + struct kvm_host_map map;
> +
> + trace_kvm_nested_vmexit_inject(vmcb->control.exit_code,
> + vmcb->control.exit_info_1,
> + vmcb->control.exit_info_2,
> + vmcb->control.exit_int_info,
> + vmcb->control.exit_int_info_err,
> + KVM_ISA_SVM);
> +
> + rc = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->nested.vmcb), &map);
> + if (rc) {
> + if (rc == -EINVAL)
> + kvm_inject_gp(&svm->vcpu, 0);
> + return 1;
> + }
> +
> + nested_vmcb = map.hva;
> +
> + /* Exit Guest-Mode */
> + leave_guest_mode(&svm->vcpu);
> + svm->nested.vmcb = 0;
> +
> + /* Give the current vmcb to the guest */
> + disable_gif(svm);
> +
> + nested_vmcb->save.es = vmcb->save.es;
> + nested_vmcb->save.cs = vmcb->save.cs;
> + nested_vmcb->save.ss = vmcb->save.ss;
> + nested_vmcb->save.ds = vmcb->save.ds;
> + nested_vmcb->save.gdtr = vmcb->save.gdtr;
> + nested_vmcb->save.idtr = vmcb->save.idtr;
> + nested_vmcb->save.efer = svm->vcpu.arch.efer;
> + nested_vmcb->save.cr0 = kvm_read_cr0(&svm->vcpu);
> + nested_vmcb->save.cr3 = kvm_read_cr3(&svm->vcpu);
> + nested_vmcb->save.cr2 = vmcb->save.cr2;
> + nested_vmcb->save.cr4 = svm->vcpu.arch.cr4;
> + nested_vmcb->save.rflags = kvm_get_rflags(&svm->vcpu);
> + nested_vmcb->save.rip = vmcb->save.rip;
> + nested_vmcb->save.rsp = vmcb->save.rsp;
> + nested_vmcb->save.rax = vmcb->save.rax;
> + nested_vmcb->save.dr7 = vmcb->save.dr7;
> + nested_vmcb->save.dr6 = vmcb->save.dr6;
> + nested_vmcb->save.cpl = vmcb->save.cpl;
> +
> + nested_vmcb->control.int_ctl = vmcb->control.int_ctl;
> + nested_vmcb->control.int_vector = vmcb->control.int_vector;
> + nested_vmcb->control.int_state = vmcb->control.int_state;
> + nested_vmcb->control.exit_code = vmcb->control.exit_code;
> + nested_vmcb->control.exit_code_hi = vmcb->control.exit_code_hi;
> + nested_vmcb->control.exit_info_1 = vmcb->control.exit_info_1;
> + nested_vmcb->control.exit_info_2 = vmcb->control.exit_info_2;
> + nested_vmcb->control.exit_int_info = vmcb->control.exit_int_info;
> + nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err;
> +
> + if (svm->nrips_enabled)
> + nested_vmcb->control.next_rip = vmcb->control.next_rip;
> +
> + /*
> + * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
> + * to make sure that we do not lose injected events. So check event_inj
> + * here and copy it to exit_int_info if it is valid.
> + * Exit_int_info and event_inj can't be both valid because the case
> + * below only happens on a VMRUN instruction intercept which has
> + * no valid exit_int_info set.
> + */
> + if (vmcb->control.event_inj & SVM_EVTINJ_VALID) {
> + struct vmcb_control_area *nc = &nested_vmcb->control;
> +
> + nc->exit_int_info = vmcb->control.event_inj;
> + nc->exit_int_info_err = vmcb->control.event_inj_err;
> + }
> +
> + nested_vmcb->control.tlb_ctl = 0;
> + nested_vmcb->control.event_inj = 0;
> + nested_vmcb->control.event_inj_err = 0;
> +
> + nested_vmcb->control.pause_filter_count =
> + svm->vmcb->control.pause_filter_count;
> + nested_vmcb->control.pause_filter_thresh =
> + svm->vmcb->control.pause_filter_thresh;
> +
> + /* We always set V_INTR_MASKING and remember the old value in hflags */
> + if (!(svm->vcpu.arch.hflags & HF_VINTR_MASK))
> + nested_vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
> +
> + /* Restore the original control entries */
> + copy_vmcb_control_area(vmcb, hsave);
> +
> + svm->vcpu.arch.tsc_offset = svm->vmcb->control.tsc_offset;
> + kvm_clear_exception_queue(&svm->vcpu);
> + kvm_clear_interrupt_queue(&svm->vcpu);
> +
> + svm->nested.nested_cr3 = 0;
> +
> + /* Restore selected save entries */
> + svm->vmcb->save.es = hsave->save.es;
> + svm->vmcb->save.cs = hsave->save.cs;
> + svm->vmcb->save.ss = hsave->save.ss;
> + svm->vmcb->save.ds = hsave->save.ds;
> + svm->vmcb->save.gdtr = hsave->save.gdtr;
> + svm->vmcb->save.idtr = hsave->save.idtr;
> + kvm_set_rflags(&svm->vcpu, hsave->save.rflags);
> + svm_set_efer(&svm->vcpu, hsave->save.efer);
> + svm_set_cr0(&svm->vcpu, hsave->save.cr0 | X86_CR0_PE);
> + svm_set_cr4(&svm->vcpu, hsave->save.cr4);
> + if (npt_enabled) {
> + svm->vmcb->save.cr3 = hsave->save.cr3;
> + svm->vcpu.arch.cr3 = hsave->save.cr3;
> + } else {
> + (void)kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
> + }
> + kvm_rax_write(&svm->vcpu, hsave->save.rax);
> + kvm_rsp_write(&svm->vcpu, hsave->save.rsp);
> + kvm_rip_write(&svm->vcpu, hsave->save.rip);
> + svm->vmcb->save.dr7 = 0;
> + svm->vmcb->save.cpl = 0;
> + svm->vmcb->control.exit_int_info = 0;
> +
> + mark_all_dirty(svm->vmcb);
> +
> + kvm_vcpu_unmap(&svm->vcpu, &map, true);
> +
> + nested_svm_uninit_mmu_context(&svm->vcpu);
> + kvm_mmu_reset_context(&svm->vcpu);
> + kvm_mmu_load(&svm->vcpu);
> +
> + /*
> + * 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(&svm->vcpu);
> + kvm_clear_interrupt_queue(&svm->vcpu);
> +
> + return 0;
> +}
> +
> +static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
> +{
> + u32 offset, msr, value;
> + int write, mask;
> +
> + if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
> + return NESTED_EXIT_HOST;
> +
> + msr = svm->vcpu.arch.regs[VCPU_REGS_RCX];
> + offset = svm_msrpm_offset(msr);
> + write = svm->vmcb->control.exit_info_1 & 1;
> + mask = 1 << ((2 * (msr & 0xf)) + write);
> +
> + if (offset == MSR_INVALID)
> + return NESTED_EXIT_DONE;
> +
> + /* Offset is in 32 bit units but need in 8 bit units */
> + offset *= 4;
> +
> + if (kvm_vcpu_read_guest(&svm->vcpu, svm->nested.vmcb_msrpm + offset, &value, 4))
> + return NESTED_EXIT_DONE;
> +
> + return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
> +}
> +
> +/* DB exceptions for our internal use must not cause vmexit */
> +static int nested_svm_intercept_db(struct vcpu_svm *svm)
> +{
> + unsigned long dr6;
> +
> + /* if we're not singlestepping, it's not ours */
> + if (!svm->nmi_singlestep)
> + return NESTED_EXIT_DONE;
> +
> + /* if it's not a singlestep exception, it's not ours */
> + if (kvm_get_dr(&svm->vcpu, 6, &dr6))
> + return NESTED_EXIT_DONE;
> + if (!(dr6 & DR6_BS))
> + return NESTED_EXIT_DONE;
> +
> + /* if the guest is singlestepping, it should get the vmexit */
> + if (svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF) {
> + disable_nmi_singlestep(svm);
> + return NESTED_EXIT_DONE;
> + }
> +
> + /* it's ours, the nested hypervisor must not see this one */
> + return NESTED_EXIT_HOST;
> +}
> +
> +static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
> +{
> + unsigned port, size, iopm_len;
> + u16 val, mask;
> + u8 start_bit;
> + u64 gpa;
> +
> + if (!(svm->nested.intercept & (1ULL << INTERCEPT_IOIO_PROT)))
> + return NESTED_EXIT_HOST;
> +
> + port = svm->vmcb->control.exit_info_1 >> 16;
> + size = (svm->vmcb->control.exit_info_1 & SVM_IOIO_SIZE_MASK) >>
> + SVM_IOIO_SIZE_SHIFT;
> + gpa = svm->nested.vmcb_iopm + (port / 8);
> + start_bit = port % 8;
> + iopm_len = (start_bit + size > 8) ? 2 : 1;
> + mask = (0xf >> (4 - size)) << start_bit;
> + val = 0;
> +
> + if (kvm_vcpu_read_guest(&svm->vcpu, gpa, &val, iopm_len))
> + return NESTED_EXIT_DONE;
> +
> + return (val & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
> +}
> +
> +static int nested_svm_intercept(struct vcpu_svm *svm)
> +{
> + u32 exit_code = svm->vmcb->control.exit_code;
> + int vmexit = NESTED_EXIT_HOST;
> +
> + switch (exit_code) {
> + case SVM_EXIT_MSR:
> + vmexit = nested_svm_exit_handled_msr(svm);
> + break;
> + case SVM_EXIT_IOIO:
> + vmexit = nested_svm_intercept_ioio(svm);
> + break;
> + case SVM_EXIT_READ_CR0 ... SVM_EXIT_WRITE_CR8: {
> + u32 bit = 1U << (exit_code - SVM_EXIT_READ_CR0);
> + if (svm->nested.intercept_cr & bit)
> + vmexit = NESTED_EXIT_DONE;
> + break;
> + }
> + case SVM_EXIT_READ_DR0 ... SVM_EXIT_WRITE_DR7: {
> + u32 bit = 1U << (exit_code - SVM_EXIT_READ_DR0);
> + if (svm->nested.intercept_dr & bit)
> + vmexit = NESTED_EXIT_DONE;
> + break;
> + }
> + case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: {
> + u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE);
> + if (svm->nested.intercept_exceptions & excp_bits) {
> + if (exit_code == SVM_EXIT_EXCP_BASE + DB_VECTOR)
> + vmexit = nested_svm_intercept_db(svm);
> + else
> + vmexit = NESTED_EXIT_DONE;
> + }
> + /* async page fault always cause vmexit */
> + else if ((exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) &&
> + svm->vcpu.arch.exception.nested_apf != 0)
> + vmexit = NESTED_EXIT_DONE;
> + break;
> + }
> + case SVM_EXIT_ERR: {
> + vmexit = NESTED_EXIT_DONE;
> + break;
> + }
> + default: {
> + u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR);
> + if (svm->nested.intercept & exit_bits)
> + vmexit = NESTED_EXIT_DONE;
> + }
> + }
> +
> + return vmexit;
> +}
> +
> +int nested_svm_exit_handled(struct vcpu_svm *svm)
> +{
> + int vmexit;
> +
> + vmexit = nested_svm_intercept(svm);
> +
> + if (vmexit == NESTED_EXIT_DONE)
> + nested_svm_vmexit(svm);
> +
> + return vmexit;
> +}
> +
> +int nested_svm_check_permissions(struct vcpu_svm *svm)
> +{
> + if (!(svm->vcpu.arch.efer & EFER_SVME) ||
> + !is_paging(&svm->vcpu)) {
> + kvm_queue_exception(&svm->vcpu, UD_VECTOR);
> + return 1;
> + }
> +
> + if (svm->vmcb->save.cpl) {
> + kvm_inject_gp(&svm->vcpu, 0);
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
> + bool has_error_code, u32 error_code)
> +{
> + int vmexit;
> +
> + if (!is_guest_mode(&svm->vcpu))
> + return 0;
> +
> + vmexit = nested_svm_intercept(svm);
> + if (vmexit != NESTED_EXIT_DONE)
> + return 0;
> +
> + svm->vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + nr;
> + svm->vmcb->control.exit_code_hi = 0;
> + svm->vmcb->control.exit_info_1 = error_code;
> +
> + /*
> + * EXITINFO2 is undefined for all exception intercepts other
> + * than #PF.
> + */
> + if (svm->vcpu.arch.exception.nested_apf)
> + svm->vmcb->control.exit_info_2 = svm->vcpu.arch.apf.nested_apf_token;
> + else if (svm->vcpu.arch.exception.has_payload)
> + svm->vmcb->control.exit_info_2 = svm->vcpu.arch.exception.payload;
> + else
> + svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
> +
> + svm->nested.exit_required = true;
> + return vmexit;
> +}
> +
> +static void nested_svm_intr(struct vcpu_svm *svm)
> +{
> + svm->vmcb->control.exit_code = SVM_EXIT_INTR;
> + svm->vmcb->control.exit_info_1 = 0;
> + svm->vmcb->control.exit_info_2 = 0;
> +
> + /* nested_svm_vmexit this gets called afterwards from handle_exit */
> + svm->nested.exit_required = true;
> + trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
> +}
> +
> +static bool nested_exit_on_intr(struct vcpu_svm *svm)
> +{
> + return (svm->nested.intercept & 1ULL);
> +}
> +
> +int svm_check_nested_events(struct kvm_vcpu *vcpu)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> + bool block_nested_events =
> + kvm_event_needs_reinjection(vcpu) || svm->nested.exit_required;
> +
> + if (kvm_cpu_has_interrupt(vcpu) && nested_exit_on_intr(svm)) {
> + if (block_nested_events)
> + return -EBUSY;
> + nested_svm_intr(svm);
> + return 0;
> + }
> +
> + return 0;
> +}
> +
> +int nested_svm_exit_special(struct vcpu_svm *svm)
> +{
> + u32 exit_code = svm->vmcb->control.exit_code;
> +
> + switch (exit_code) {
> + case SVM_EXIT_INTR:
> + case SVM_EXIT_NMI:
> + case SVM_EXIT_EXCP_BASE + MC_VECTOR:
> + return NESTED_EXIT_HOST;
> + case SVM_EXIT_NPF:
> + /* For now we are always handling NPFs when using them */
> + if (npt_enabled)
> + return NESTED_EXIT_HOST;
> + break;
> + case SVM_EXIT_EXCP_BASE + PF_VECTOR:
> + /* When we're shadowing, trap PFs, but not async PF */
> + if (!npt_enabled && svm->vcpu.arch.apf.host_apf_reason == 0)
> + return NESTED_EXIT_HOST;
> + break;
> + default:
> + break;
> + }
> +
> + return NESTED_EXIT_CONTINUE;
> +}
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 2125c6ae5951..b74ebc19e1f6 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -52,6 +52,8 @@
> #include <asm/virtext.h>
> #include "trace.h"
>
> +#include "svm.h"
> +
> #define __ex(x) __kvm_handle_fault_on_reboot(x)
>
> MODULE_AUTHOR("Qumranet");
> @@ -79,10 +81,6 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
>
> #define SVM_AVIC_DOORBELL 0xc001011b
>
> -#define NESTED_EXIT_HOST 0 /* Exit handled on host level */
> -#define NESTED_EXIT_DONE 1 /* Exit caused nested vmexit */
> -#define NESTED_EXIT_CONTINUE 2 /* Further checks needed */
> -
> #define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
>
> #define TSC_RATIO_RSVD 0xffffff0000000000ULL
> @@ -116,68 +114,7 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
>
> static bool erratum_383_found __read_mostly;
>
> -static const u32 host_save_user_msrs[] = {
> -#ifdef CONFIG_X86_64
> - MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
> - MSR_FS_BASE,
> -#endif
> - MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
> - MSR_TSC_AUX,
> -};
> -
> -#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
> -
> -struct kvm_sev_info {
> - bool active; /* SEV enabled guest */
> - unsigned int asid; /* ASID used for this guest */
> - unsigned int handle; /* SEV firmware handle */
> - int fd; /* SEV device fd */
> - unsigned long pages_locked; /* Number of pages locked */
> - struct list_head regions_list; /* List of registered regions */
> -};
> -
> -struct kvm_svm {
> - struct kvm kvm;
> -
> - /* Struct members for AVIC */
> - u32 avic_vm_id;
> - struct page *avic_logical_id_table_page;
> - struct page *avic_physical_id_table_page;
> - struct hlist_node hnode;
> -
> - struct kvm_sev_info sev_info;
> -};
> -
> -struct kvm_vcpu;
> -
> -struct nested_state {
> - struct vmcb *hsave;
> - u64 hsave_msr;
> - u64 vm_cr_msr;
> - u64 vmcb;
> -
> - /* These are the merged vectors */
> - u32 *msrpm;
> -
> - /* gpa pointers to the real vectors */
> - u64 vmcb_msrpm;
> - u64 vmcb_iopm;
> -
> - /* 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;
> -};
> -
> -#define MSRPM_OFFSETS 16
> -static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
> +u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
>
> /*
> * Set osvw_len to higher value when updated Revision Guides
> @@ -185,70 +122,6 @@ static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
> */
> static uint64_t osvw_len = 4, osvw_status;
>
> -struct vcpu_svm {
> - struct kvm_vcpu vcpu;
> - struct vmcb *vmcb;
> - unsigned long vmcb_pa;
> - struct svm_cpu_data *svm_data;
> - uint64_t asid_generation;
> - uint64_t sysenter_esp;
> - uint64_t sysenter_eip;
> - uint64_t tsc_aux;
> -
> - u64 msr_decfg;
> -
> - u64 next_rip;
> -
> - u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
> - struct {
> - u16 fs;
> - u16 gs;
> - u16 ldt;
> - u64 gs_base;
> - } host;
> -
> - u64 spec_ctrl;
> - /*
> - * Contains guest-controlled bits of VIRT_SPEC_CTRL, which will be
> - * translated into the appropriate L2_CFG bits on the host to
> - * perform speculative control.
> - */
> - u64 virt_spec_ctrl;
> -
> - u32 *msrpm;
> -
> - ulong nmi_iret_rip;
> -
> - struct nested_state nested;
> -
> - bool nmi_singlestep;
> - u64 nmi_singlestep_guest_rflags;
> -
> - unsigned int3_injected;
> - unsigned long int3_rip;
> -
> - /* cached guest cpuid flags for faster access */
> - bool nrips_enabled : 1;
> -
> - u32 ldr_reg;
> - u32 dfr_reg;
> - struct page *avic_backing_page;
> - u64 *avic_physical_id_cache;
> - bool avic_is_running;
> -
> - /*
> - * Per-vcpu list of struct amd_svm_iommu_ir:
> - * This is used mainly to store interrupt remapping information used
> - * when update the vcpu affinity. This avoids the need to scan for
> - * IRTE and try to match ga_tag in the IOMMU driver.
> - */
> - struct list_head ir_list;
> - spinlock_t ir_list_lock;
> -
> - /* which host CPU was used for running this vcpu */
> - unsigned int last_cpu;
> -};
> -
> /*
> * This is a wrapper of struct amd_iommu_ir_data.
> */
> @@ -269,8 +142,6 @@ struct amd_svm_iommu_ir {
> static DEFINE_PER_CPU(u64, current_tsc_ratio);
> #define TSC_RATIO_DEFAULT 0x0100000000ULL
>
> -#define MSR_INVALID 0xffffffffU
> -
> static const struct svm_direct_access_msrs {
> u32 index; /* Index of the MSR */
> bool always; /* True if intercept is always on */
> @@ -296,9 +167,9 @@ static const struct svm_direct_access_msrs {
>
> /* enable NPT for AMD64 and X86 with PAE */
> #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
> -static bool npt_enabled = true;
> +bool npt_enabled = true;
> #else
> -static bool npt_enabled;
> +bool npt_enabled;
> #endif
>
> /*
> @@ -384,41 +255,10 @@ module_param(dump_invalid_vmcb, bool, 0644);
>
> static u8 rsm_ins_bytes[] = "\x0f\xaa";
>
> -static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
> -static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa);
> static void svm_complete_interrupts(struct vcpu_svm *svm);
> static void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate);
> static inline void avic_post_state_restore(struct kvm_vcpu *vcpu);
>
> -static int nested_svm_exit_handled(struct vcpu_svm *svm);
> -static int nested_svm_intercept(struct vcpu_svm *svm);
> -static int nested_svm_vmexit(struct vcpu_svm *svm);
> -static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
> - bool has_error_code, u32 error_code);
> -
> -enum {
> - VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
> - pause filter count */
> - VMCB_PERM_MAP, /* IOPM Base and MSRPM Base */
> - VMCB_ASID, /* ASID */
> - VMCB_INTR, /* int_ctl, int_vector */
> - VMCB_NPT, /* npt_en, nCR3, gPAT */
> - VMCB_CR, /* CR0, CR3, CR4, EFER */
> - VMCB_DR, /* DR6, DR7 */
> - VMCB_DT, /* GDT, IDT */
> - VMCB_SEG, /* CS, DS, SS, ES, CPL */
> - VMCB_CR2, /* CR2 only */
> - VMCB_LBR, /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */
> - VMCB_AVIC, /* AVIC APIC_BAR, AVIC APIC_BACKING_PAGE,
> - * AVIC PHYSICAL_TABLE pointer,
> - * AVIC LOGICAL_TABLE pointer
> - */
> - VMCB_DIRTY_MAX,
> -};
> -
> -/* TPR and CR2 are always written before VMRUN */
> -#define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2))
> -
> #define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL
>
> static int sev_flush_asids(void);
> @@ -467,27 +307,6 @@ static inline int sev_get_asid(struct kvm *kvm)
> return sev->asid;
> }
>
> -static inline void mark_all_dirty(struct vmcb *vmcb)
> -{
> - vmcb->control.clean = 0;
> -}
> -
> -static inline void mark_all_clean(struct vmcb *vmcb)
> -{
> - vmcb->control.clean = ((1 << VMCB_DIRTY_MAX) - 1)
> - & ~VMCB_ALWAYS_DIRTY_MASK;
> -}
> -
> -static inline void mark_dirty(struct vmcb *vmcb, int bit)
> -{
> - vmcb->control.clean &= ~(1 << bit);
> -}
> -
> -static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
> -{
> - return container_of(vcpu, struct vcpu_svm, vcpu);
> -}
> -
> static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data)
> {
> svm->vmcb->control.avic_vapic_bar = data & VMCB_AVIC_APIC_BAR_MASK;
> @@ -505,183 +324,6 @@ static inline bool avic_vcpu_is_running(struct kvm_vcpu *vcpu)
> return (READ_ONCE(*entry) & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
> }
>
> -static void recalc_intercepts(struct vcpu_svm *svm)
> -{
> - struct vmcb_control_area *c, *h;
> - struct nested_state *g;
> -
> - mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
> -
> - if (!is_guest_mode(&svm->vcpu))
> - return;
> -
> - c = &svm->vmcb->control;
> - h = &svm->nested.hsave->control;
> - g = &svm->nested;
> -
> - c->intercept_cr = h->intercept_cr;
> - c->intercept_dr = h->intercept_dr;
> - c->intercept_exceptions = h->intercept_exceptions;
> - c->intercept = h->intercept;
> -
> - if (svm->vcpu.arch.hflags & HF_VINTR_MASK) {
> - /* We only want the cr8 intercept bits of L1 */
> - c->intercept_cr &= ~(1U << INTERCEPT_CR8_READ);
> - c->intercept_cr &= ~(1U << INTERCEPT_CR8_WRITE);
> -
> - /*
> - * Once running L2 with HF_VINTR_MASK, EFLAGS.IF does not
> - * affect any interrupt we may want to inject; therefore,
> - * interrupt window vmexits are irrelevant to L0.
> - */
> - c->intercept &= ~(1ULL << INTERCEPT_VINTR);
> - }
> -
> - /* We don't want to see VMMCALLs from a nested guest */
> - c->intercept &= ~(1ULL << INTERCEPT_VMMCALL);
> -
> - c->intercept_cr |= g->intercept_cr;
> - c->intercept_dr |= g->intercept_dr;
> - c->intercept_exceptions |= g->intercept_exceptions;
> - c->intercept |= g->intercept;
> -}
> -
> -static inline struct vmcb *get_host_vmcb(struct vcpu_svm *svm)
> -{
> - if (is_guest_mode(&svm->vcpu))
> - return svm->nested.hsave;
> - else
> - return svm->vmcb;
> -}
> -
> -static inline void set_cr_intercept(struct vcpu_svm *svm, int bit)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept_cr |= (1U << bit);
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline void clr_cr_intercept(struct vcpu_svm *svm, int bit)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept_cr &= ~(1U << bit);
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline bool is_cr_intercept(struct vcpu_svm *svm, int bit)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - return vmcb->control.intercept_cr & (1U << bit);
> -}
> -
> -static inline void set_dr_intercepts(struct vcpu_svm *svm)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept_dr = (1 << INTERCEPT_DR0_READ)
> - | (1 << INTERCEPT_DR1_READ)
> - | (1 << INTERCEPT_DR2_READ)
> - | (1 << INTERCEPT_DR3_READ)
> - | (1 << INTERCEPT_DR4_READ)
> - | (1 << INTERCEPT_DR5_READ)
> - | (1 << INTERCEPT_DR6_READ)
> - | (1 << INTERCEPT_DR7_READ)
> - | (1 << INTERCEPT_DR0_WRITE)
> - | (1 << INTERCEPT_DR1_WRITE)
> - | (1 << INTERCEPT_DR2_WRITE)
> - | (1 << INTERCEPT_DR3_WRITE)
> - | (1 << INTERCEPT_DR4_WRITE)
> - | (1 << INTERCEPT_DR5_WRITE)
> - | (1 << INTERCEPT_DR6_WRITE)
> - | (1 << INTERCEPT_DR7_WRITE);
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline void clr_dr_intercepts(struct vcpu_svm *svm)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept_dr = 0;
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline void set_exception_intercept(struct vcpu_svm *svm, int bit)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept_exceptions |= (1U << bit);
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline void clr_exception_intercept(struct vcpu_svm *svm, int bit)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept_exceptions &= ~(1U << bit);
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline void set_intercept(struct vcpu_svm *svm, int bit)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept |= (1ULL << bit);
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline void clr_intercept(struct vcpu_svm *svm, int bit)
> -{
> - struct vmcb *vmcb = get_host_vmcb(svm);
> -
> - vmcb->control.intercept &= ~(1ULL << bit);
> -
> - recalc_intercepts(svm);
> -}
> -
> -static inline bool is_intercept(struct vcpu_svm *svm, int bit)
> -{
> - return (svm->vmcb->control.intercept & (1ULL << bit)) != 0;
> -}
> -
> -static inline bool vgif_enabled(struct vcpu_svm *svm)
> -{
> - return !!(svm->vmcb->control.int_ctl & V_GIF_ENABLE_MASK);
> -}
> -
> -static inline void enable_gif(struct vcpu_svm *svm)
> -{
> - if (vgif_enabled(svm))
> - svm->vmcb->control.int_ctl |= V_GIF_MASK;
> - else
> - svm->vcpu.arch.hflags |= HF_GIF_MASK;
> -}
> -
> -static inline void disable_gif(struct vcpu_svm *svm)
> -{
> - if (vgif_enabled(svm))
> - svm->vmcb->control.int_ctl &= ~V_GIF_MASK;
> - else
> - svm->vcpu.arch.hflags &= ~HF_GIF_MASK;
> -}
> -
> -static inline bool gif_set(struct vcpu_svm *svm)
> -{
> - if (vgif_enabled(svm))
> - return !!(svm->vmcb->control.int_ctl & V_GIF_MASK);
> - else
> - return !!(svm->vcpu.arch.hflags & HF_GIF_MASK);
> -}
> -
> static unsigned long iopm_base;
>
> struct kvm_ldttss_desc {
> @@ -717,7 +359,7 @@ static const u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
> #define MSRS_RANGE_SIZE 2048
> #define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2)
>
> -static u32 svm_msrpm_offset(u32 msr)
> +u32 svm_msrpm_offset(u32 msr)
> {
> u32 offset;
> int i;
> @@ -764,7 +406,7 @@ static int get_npt_level(struct kvm_vcpu *vcpu)
> #endif
> }
>
> -static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
> +void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
> {
> vcpu->arch.efer = efer;
>
> @@ -1195,7 +837,7 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
> set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 0, 0);
> }
>
> -static void disable_nmi_singlestep(struct vcpu_svm *svm)
> +void disable_nmi_singlestep(struct vcpu_svm *svm)
> {
> svm->nmi_singlestep = false;
>
> @@ -2649,7 +2291,7 @@ static void update_cr0_intercept(struct vcpu_svm *svm)
> }
> }
>
> -static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
> +void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
> {
> struct vcpu_svm *svm = to_svm(vcpu);
>
> @@ -2683,7 +2325,7 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
> update_cr0_intercept(svm);
> }
>
> -static int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
> +int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
> {
> unsigned long host_cr4_mce = cr4_read_shadow() & X86_CR4_MCE;
> unsigned long old_cr4 = to_svm(vcpu)->vmcb->save.cr4;
> @@ -3019,776 +2661,6 @@ static int vmmcall_interception(struct vcpu_svm *svm)
> return kvm_emulate_hypercall(&svm->vcpu);
> }
>
> -static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
> -{
> - struct vcpu_svm *svm = to_svm(vcpu);
> -
> - return svm->nested.nested_cr3;
> -}
> -
> -static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
> -{
> - struct vcpu_svm *svm = to_svm(vcpu);
> - u64 cr3 = svm->nested.nested_cr3;
> - u64 pdpte;
> - int ret;
> -
> - ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(__sme_clr(cr3)), &pdpte,
> - offset_in_page(cr3) + index * 8, 8);
> - if (ret)
> - return 0;
> - return pdpte;
> -}
> -
> -static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
> - struct x86_exception *fault)
> -{
> - struct vcpu_svm *svm = to_svm(vcpu);
> -
> - if (svm->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.
> - */
> - svm->vmcb->control.exit_code = SVM_EXIT_NPF;
> - svm->vmcb->control.exit_code_hi = 0;
> - svm->vmcb->control.exit_info_1 = (1ULL << 32);
> - svm->vmcb->control.exit_info_2 = fault->address;
> - }
> -
> - svm->vmcb->control.exit_info_1 &= ~0xffffffffULL;
> - svm->vmcb->control.exit_info_1 |= fault->error_code;
> -
> - /*
> - * The present bit is always zero for page structure faults on real
> - * hardware.
> - */
> - if (svm->vmcb->control.exit_info_1 & (2ULL << 32))
> - svm->vmcb->control.exit_info_1 &= ~1;
> -
> - nested_svm_vmexit(svm);
> -}
> -
> -static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
> -{
> - WARN_ON(mmu_is_nested(vcpu));
> -
> - vcpu->arch.mmu = &vcpu->arch.guest_mmu;
> - kvm_init_shadow_mmu(vcpu);
> - 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.mmu->shadow_root_level = get_npt_level(vcpu);
> - reset_shadow_zero_bits_mask(vcpu, vcpu->arch.mmu);
> - vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu;
> -}
> -
> -static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
> -{
> - vcpu->arch.mmu = &vcpu->arch.root_mmu;
> - vcpu->arch.walk_mmu = &vcpu->arch.root_mmu;
> -}
> -
> -static int nested_svm_check_permissions(struct vcpu_svm *svm)
> -{
> - if (!(svm->vcpu.arch.efer & EFER_SVME) ||
> - !is_paging(&svm->vcpu)) {
> - kvm_queue_exception(&svm->vcpu, UD_VECTOR);
> - return 1;
> - }
> -
> - if (svm->vmcb->save.cpl) {
> - kvm_inject_gp(&svm->vcpu, 0);
> - return 1;
> - }
> -
> - return 0;
> -}
> -
> -static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
> - bool has_error_code, u32 error_code)
> -{
> - int vmexit;
> -
> - if (!is_guest_mode(&svm->vcpu))
> - return 0;
> -
> - vmexit = nested_svm_intercept(svm);
> - if (vmexit != NESTED_EXIT_DONE)
> - return 0;
> -
> - svm->vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + nr;
> - svm->vmcb->control.exit_code_hi = 0;
> - svm->vmcb->control.exit_info_1 = error_code;
> -
> - /*
> - * EXITINFO2 is undefined for all exception intercepts other
> - * than #PF.
> - */
> - if (svm->vcpu.arch.exception.nested_apf)
> - svm->vmcb->control.exit_info_2 = svm->vcpu.arch.apf.nested_apf_token;
> - else if (svm->vcpu.arch.exception.has_payload)
> - svm->vmcb->control.exit_info_2 = svm->vcpu.arch.exception.payload;
> - else
> - svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
> -
> - svm->nested.exit_required = true;
> - return vmexit;
> -}
> -
> -static void nested_svm_intr(struct vcpu_svm *svm)
> -{
> - svm->vmcb->control.exit_code = SVM_EXIT_INTR;
> - svm->vmcb->control.exit_info_1 = 0;
> - svm->vmcb->control.exit_info_2 = 0;
> -
> - /* nested_svm_vmexit this gets called afterwards from handle_exit */
> - svm->nested.exit_required = true;
> - trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
> -}
> -
> -static bool nested_exit_on_intr(struct vcpu_svm *svm)
> -{
> - return (svm->nested.intercept & 1ULL);
> -}
> -
> -static int svm_check_nested_events(struct kvm_vcpu *vcpu)
> -{
> - struct vcpu_svm *svm = to_svm(vcpu);
> - bool block_nested_events =
> - kvm_event_needs_reinjection(vcpu) || svm->nested.exit_required;
> -
> - if (kvm_cpu_has_interrupt(vcpu) && nested_exit_on_intr(svm)) {
> - if (block_nested_events)
> - return -EBUSY;
> - nested_svm_intr(svm);
> - return 0;
> - }
> -
> - return 0;
> -}
> -
> -/* 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 int nested_svm_intercept_ioio(struct vcpu_svm *svm)
> -{
> - unsigned port, size, iopm_len;
> - u16 val, mask;
> - u8 start_bit;
> - u64 gpa;
> -
> - if (!(svm->nested.intercept & (1ULL << INTERCEPT_IOIO_PROT)))
> - return NESTED_EXIT_HOST;
> -
> - port = svm->vmcb->control.exit_info_1 >> 16;
> - size = (svm->vmcb->control.exit_info_1 & SVM_IOIO_SIZE_MASK) >>
> - SVM_IOIO_SIZE_SHIFT;
> - gpa = svm->nested.vmcb_iopm + (port / 8);
> - start_bit = port % 8;
> - iopm_len = (start_bit + size > 8) ? 2 : 1;
> - mask = (0xf >> (4 - size)) << start_bit;
> - val = 0;
> -
> - if (kvm_vcpu_read_guest(&svm->vcpu, gpa, &val, iopm_len))
> - return NESTED_EXIT_DONE;
> -
> - return (val & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
> -}
> -
> -static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
> -{
> - u32 offset, msr, value;
> - int write, mask;
> -
> - if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
> - return NESTED_EXIT_HOST;
> -
> - msr = svm->vcpu.arch.regs[VCPU_REGS_RCX];
> - offset = svm_msrpm_offset(msr);
> - write = svm->vmcb->control.exit_info_1 & 1;
> - mask = 1 << ((2 * (msr & 0xf)) + write);
> -
> - if (offset == MSR_INVALID)
> - return NESTED_EXIT_DONE;
> -
> - /* Offset is in 32 bit units but need in 8 bit units */
> - offset *= 4;
> -
> - if (kvm_vcpu_read_guest(&svm->vcpu, svm->nested.vmcb_msrpm + offset, &value, 4))
> - return NESTED_EXIT_DONE;
> -
> - return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
> -}
> -
> -/* DB exceptions for our internal use must not cause vmexit */
> -static int nested_svm_intercept_db(struct vcpu_svm *svm)
> -{
> - unsigned long dr6;
> -
> - /* if we're not singlestepping, it's not ours */
> - if (!svm->nmi_singlestep)
> - return NESTED_EXIT_DONE;
> -
> - /* if it's not a singlestep exception, it's not ours */
> - if (kvm_get_dr(&svm->vcpu, 6, &dr6))
> - return NESTED_EXIT_DONE;
> - if (!(dr6 & DR6_BS))
> - return NESTED_EXIT_DONE;
> -
> - /* if the guest is singlestepping, it should get the vmexit */
> - if (svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF) {
> - disable_nmi_singlestep(svm);
> - return NESTED_EXIT_DONE;
> - }
> -
> - /* it's ours, the nested hypervisor must not see this one */
> - return NESTED_EXIT_HOST;
> -}
> -
> -static int nested_svm_exit_special(struct vcpu_svm *svm)
> -{
> - u32 exit_code = svm->vmcb->control.exit_code;
> -
> - switch (exit_code) {
> - case SVM_EXIT_INTR:
> - case SVM_EXIT_NMI:
> - case SVM_EXIT_EXCP_BASE + MC_VECTOR:
> - return NESTED_EXIT_HOST;
> - case SVM_EXIT_NPF:
> - /* For now we are always handling NPFs when using them */
> - if (npt_enabled)
> - return NESTED_EXIT_HOST;
> - break;
> - case SVM_EXIT_EXCP_BASE + PF_VECTOR:
> - /* When we're shadowing, trap PFs, but not async PF */
> - if (!npt_enabled && svm->vcpu.arch.apf.host_apf_reason == 0)
> - return NESTED_EXIT_HOST;
> - break;
> - default:
> - break;
> - }
> -
> - return NESTED_EXIT_CONTINUE;
> -}
> -
> -static int nested_svm_intercept(struct vcpu_svm *svm)
> -{
> - u32 exit_code = svm->vmcb->control.exit_code;
> - int vmexit = NESTED_EXIT_HOST;
> -
> - switch (exit_code) {
> - case SVM_EXIT_MSR:
> - vmexit = nested_svm_exit_handled_msr(svm);
> - break;
> - case SVM_EXIT_IOIO:
> - vmexit = nested_svm_intercept_ioio(svm);
> - break;
> - case SVM_EXIT_READ_CR0 ... SVM_EXIT_WRITE_CR8: {
> - u32 bit = 1U << (exit_code - SVM_EXIT_READ_CR0);
> - if (svm->nested.intercept_cr & bit)
> - vmexit = NESTED_EXIT_DONE;
> - break;
> - }
> - case SVM_EXIT_READ_DR0 ... SVM_EXIT_WRITE_DR7: {
> - u32 bit = 1U << (exit_code - SVM_EXIT_READ_DR0);
> - if (svm->nested.intercept_dr & bit)
> - vmexit = NESTED_EXIT_DONE;
> - break;
> - }
> - case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: {
> - u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE);
> - if (svm->nested.intercept_exceptions & excp_bits) {
> - if (exit_code == SVM_EXIT_EXCP_BASE + DB_VECTOR)
> - vmexit = nested_svm_intercept_db(svm);
> - else
> - vmexit = NESTED_EXIT_DONE;
> - }
> - /* async page fault always cause vmexit */
> - else if ((exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) &&
> - svm->vcpu.arch.exception.nested_apf != 0)
> - vmexit = NESTED_EXIT_DONE;
> - break;
> - }
> - case SVM_EXIT_ERR: {
> - vmexit = NESTED_EXIT_DONE;
> - break;
> - }
> - default: {
> - u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR);
> - if (svm->nested.intercept & exit_bits)
> - vmexit = NESTED_EXIT_DONE;
> - }
> - }
> -
> - return vmexit;
> -}
> -
> -static int nested_svm_exit_handled(struct vcpu_svm *svm)
> -{
> - int vmexit;
> -
> - vmexit = nested_svm_intercept(svm);
> -
> - if (vmexit == NESTED_EXIT_DONE)
> - nested_svm_vmexit(svm);
> -
> - return vmexit;
> -}
> -
> -static inline void copy_vmcb_control_area(struct vmcb *dst_vmcb, struct vmcb *from_vmcb)
> -{
> - struct vmcb_control_area *dst = &dst_vmcb->control;
> - struct vmcb_control_area *from = &from_vmcb->control;
> -
> - dst->intercept_cr = from->intercept_cr;
> - dst->intercept_dr = from->intercept_dr;
> - dst->intercept_exceptions = from->intercept_exceptions;
> - dst->intercept = from->intercept;
> - dst->iopm_base_pa = from->iopm_base_pa;
> - dst->msrpm_base_pa = from->msrpm_base_pa;
> - dst->tsc_offset = from->tsc_offset;
> - dst->asid = from->asid;
> - dst->tlb_ctl = from->tlb_ctl;
> - dst->int_ctl = from->int_ctl;
> - dst->int_vector = from->int_vector;
> - dst->int_state = from->int_state;
> - dst->exit_code = from->exit_code;
> - dst->exit_code_hi = from->exit_code_hi;
> - dst->exit_info_1 = from->exit_info_1;
> - dst->exit_info_2 = from->exit_info_2;
> - dst->exit_int_info = from->exit_int_info;
> - dst->exit_int_info_err = from->exit_int_info_err;
> - dst->nested_ctl = from->nested_ctl;
> - dst->event_inj = from->event_inj;
> - dst->event_inj_err = from->event_inj_err;
> - dst->nested_cr3 = from->nested_cr3;
> - dst->virt_ext = from->virt_ext;
> - dst->pause_filter_count = from->pause_filter_count;
> - dst->pause_filter_thresh = from->pause_filter_thresh;
> -}
> -
> -static int nested_svm_vmexit(struct vcpu_svm *svm)
> -{
> - int rc;
> - struct vmcb *nested_vmcb;
> - struct vmcb *hsave = svm->nested.hsave;
> - struct vmcb *vmcb = svm->vmcb;
> - struct kvm_host_map map;
> -
> - trace_kvm_nested_vmexit_inject(vmcb->control.exit_code,
> - vmcb->control.exit_info_1,
> - vmcb->control.exit_info_2,
> - vmcb->control.exit_int_info,
> - vmcb->control.exit_int_info_err,
> - KVM_ISA_SVM);
> -
> - rc = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->nested.vmcb), &map);
> - if (rc) {
> - if (rc == -EINVAL)
> - kvm_inject_gp(&svm->vcpu, 0);
> - return 1;
> - }
> -
> - nested_vmcb = map.hva;
> -
> - /* Exit Guest-Mode */
> - leave_guest_mode(&svm->vcpu);
> - svm->nested.vmcb = 0;
> -
> - /* Give the current vmcb to the guest */
> - disable_gif(svm);
> -
> - nested_vmcb->save.es = vmcb->save.es;
> - nested_vmcb->save.cs = vmcb->save.cs;
> - nested_vmcb->save.ss = vmcb->save.ss;
> - nested_vmcb->save.ds = vmcb->save.ds;
> - nested_vmcb->save.gdtr = vmcb->save.gdtr;
> - nested_vmcb->save.idtr = vmcb->save.idtr;
> - nested_vmcb->save.efer = svm->vcpu.arch.efer;
> - nested_vmcb->save.cr0 = kvm_read_cr0(&svm->vcpu);
> - nested_vmcb->save.cr3 = kvm_read_cr3(&svm->vcpu);
> - nested_vmcb->save.cr2 = vmcb->save.cr2;
> - nested_vmcb->save.cr4 = svm->vcpu.arch.cr4;
> - nested_vmcb->save.rflags = kvm_get_rflags(&svm->vcpu);
> - nested_vmcb->save.rip = vmcb->save.rip;
> - nested_vmcb->save.rsp = vmcb->save.rsp;
> - nested_vmcb->save.rax = vmcb->save.rax;
> - nested_vmcb->save.dr7 = vmcb->save.dr7;
> - nested_vmcb->save.dr6 = vmcb->save.dr6;
> - nested_vmcb->save.cpl = vmcb->save.cpl;
> -
> - nested_vmcb->control.int_ctl = vmcb->control.int_ctl;
> - nested_vmcb->control.int_vector = vmcb->control.int_vector;
> - nested_vmcb->control.int_state = vmcb->control.int_state;
> - nested_vmcb->control.exit_code = vmcb->control.exit_code;
> - nested_vmcb->control.exit_code_hi = vmcb->control.exit_code_hi;
> - nested_vmcb->control.exit_info_1 = vmcb->control.exit_info_1;
> - nested_vmcb->control.exit_info_2 = vmcb->control.exit_info_2;
> - nested_vmcb->control.exit_int_info = vmcb->control.exit_int_info;
> - nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err;
> -
> - if (svm->nrips_enabled)
> - nested_vmcb->control.next_rip = vmcb->control.next_rip;
> -
> - /*
> - * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
> - * to make sure that we do not lose injected events. So check event_inj
> - * here and copy it to exit_int_info if it is valid.
> - * Exit_int_info and event_inj can't be both valid because the case
> - * below only happens on a VMRUN instruction intercept which has
> - * no valid exit_int_info set.
> - */
> - if (vmcb->control.event_inj & SVM_EVTINJ_VALID) {
> - struct vmcb_control_area *nc = &nested_vmcb->control;
> -
> - nc->exit_int_info = vmcb->control.event_inj;
> - nc->exit_int_info_err = vmcb->control.event_inj_err;
> - }
> -
> - nested_vmcb->control.tlb_ctl = 0;
> - nested_vmcb->control.event_inj = 0;
> - nested_vmcb->control.event_inj_err = 0;
> -
> - nested_vmcb->control.pause_filter_count =
> - svm->vmcb->control.pause_filter_count;
> - nested_vmcb->control.pause_filter_thresh =
> - svm->vmcb->control.pause_filter_thresh;
> -
> - /* We always set V_INTR_MASKING and remember the old value in hflags */
> - if (!(svm->vcpu.arch.hflags & HF_VINTR_MASK))
> - nested_vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
> -
> - /* Restore the original control entries */
> - copy_vmcb_control_area(vmcb, hsave);
> -
> - svm->vcpu.arch.tsc_offset = svm->vmcb->control.tsc_offset;
> - kvm_clear_exception_queue(&svm->vcpu);
> - kvm_clear_interrupt_queue(&svm->vcpu);
> -
> - svm->nested.nested_cr3 = 0;
> -
> - /* Restore selected save entries */
> - svm->vmcb->save.es = hsave->save.es;
> - svm->vmcb->save.cs = hsave->save.cs;
> - svm->vmcb->save.ss = hsave->save.ss;
> - svm->vmcb->save.ds = hsave->save.ds;
> - svm->vmcb->save.gdtr = hsave->save.gdtr;
> - svm->vmcb->save.idtr = hsave->save.idtr;
> - kvm_set_rflags(&svm->vcpu, hsave->save.rflags);
> - svm_set_efer(&svm->vcpu, hsave->save.efer);
> - svm_set_cr0(&svm->vcpu, hsave->save.cr0 | X86_CR0_PE);
> - svm_set_cr4(&svm->vcpu, hsave->save.cr4);
> - if (npt_enabled) {
> - svm->vmcb->save.cr3 = hsave->save.cr3;
> - svm->vcpu.arch.cr3 = hsave->save.cr3;
> - } else {
> - (void)kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
> - }
> - kvm_rax_write(&svm->vcpu, hsave->save.rax);
> - kvm_rsp_write(&svm->vcpu, hsave->save.rsp);
> - kvm_rip_write(&svm->vcpu, hsave->save.rip);
> - svm->vmcb->save.dr7 = 0;
> - svm->vmcb->save.cpl = 0;
> - svm->vmcb->control.exit_int_info = 0;
> -
> - mark_all_dirty(svm->vmcb);
> -
> - kvm_vcpu_unmap(&svm->vcpu, &map, true);
> -
> - nested_svm_uninit_mmu_context(&svm->vcpu);
> - kvm_mmu_reset_context(&svm->vcpu);
> - kvm_mmu_load(&svm->vcpu);
> -
> - /*
> - * 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(&svm->vcpu);
> - kvm_clear_interrupt_queue(&svm->vcpu);
> -
> - return 0;
> -}
> -
> -static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
> -{
> - /*
> - * This function merges the msr permission bitmaps of kvm and the
> - * nested vmcb. It is optimized in that it only merges the parts where
> - * the kvm msr permission bitmap may contain zero bits
> - */
> - int i;
> -
> - if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
> - return true;
> -
> - for (i = 0; i < MSRPM_OFFSETS; i++) {
> - u32 value, p;
> - u64 offset;
> -
> - if (msrpm_offsets[i] == 0xffffffff)
> - break;
> -
> - p = msrpm_offsets[i];
> - offset = svm->nested.vmcb_msrpm + (p * 4);
> -
> - if (kvm_vcpu_read_guest(&svm->vcpu, offset, &value, 4))
> - return false;
> -
> - svm->nested.msrpm[p] = svm->msrpm[p] | value;
> - }
> -
> - svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
> -
> - return true;
> -}
> -
> -static bool nested_vmcb_checks(struct vmcb *vmcb)
> -{
> - if ((vmcb->save.efer & EFER_SVME) == 0)
> - return false;
> -
> - if ((vmcb->control.intercept & (1ULL << INTERCEPT_VMRUN)) == 0)
> - return false;
> -
> - if (vmcb->control.asid == 0)
> - return false;
> -
> - if ((vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) &&
> - !npt_enabled)
> - return false;
> -
> - return true;
> -}
> -
> -static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
> - struct vmcb *nested_vmcb, struct kvm_host_map *map)
> -{
> - bool evaluate_pending_interrupts =
> - is_intercept(svm, INTERCEPT_VINTR) ||
> - is_intercept(svm, INTERCEPT_IRET);
> -
> - if (kvm_get_rflags(&svm->vcpu) & X86_EFLAGS_IF)
> - svm->vcpu.arch.hflags |= HF_HIF_MASK;
> - else
> - svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
> -
> - if (nested_vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) {
> - svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3;
> - nested_svm_init_mmu_context(&svm->vcpu);
> - }
> -
> - /* Load the nested guest state */
> - svm->vmcb->save.es = nested_vmcb->save.es;
> - svm->vmcb->save.cs = nested_vmcb->save.cs;
> - svm->vmcb->save.ss = nested_vmcb->save.ss;
> - svm->vmcb->save.ds = nested_vmcb->save.ds;
> - svm->vmcb->save.gdtr = nested_vmcb->save.gdtr;
> - svm->vmcb->save.idtr = nested_vmcb->save.idtr;
> - kvm_set_rflags(&svm->vcpu, nested_vmcb->save.rflags);
> - svm_set_efer(&svm->vcpu, nested_vmcb->save.efer);
> - svm_set_cr0(&svm->vcpu, nested_vmcb->save.cr0);
> - svm_set_cr4(&svm->vcpu, nested_vmcb->save.cr4);
> - if (npt_enabled) {
> - svm->vmcb->save.cr3 = nested_vmcb->save.cr3;
> - svm->vcpu.arch.cr3 = nested_vmcb->save.cr3;
> - } else
> - (void)kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
> -
> - /* Guest paging mode is active - reset mmu */
> - kvm_mmu_reset_context(&svm->vcpu);
> -
> - svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = nested_vmcb->save.cr2;
> - kvm_rax_write(&svm->vcpu, nested_vmcb->save.rax);
> - kvm_rsp_write(&svm->vcpu, nested_vmcb->save.rsp);
> - kvm_rip_write(&svm->vcpu, nested_vmcb->save.rip);
> -
> - /* In case we don't even reach vcpu_run, the fields are not updated */
> - svm->vmcb->save.rax = nested_vmcb->save.rax;
> - svm->vmcb->save.rsp = nested_vmcb->save.rsp;
> - svm->vmcb->save.rip = nested_vmcb->save.rip;
> - svm->vmcb->save.dr7 = nested_vmcb->save.dr7;
> - svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
> - svm->vmcb->save.cpl = nested_vmcb->save.cpl;
> -
> - svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa & ~0x0fffULL;
> - svm->nested.vmcb_iopm = nested_vmcb->control.iopm_base_pa & ~0x0fffULL;
> -
> - /* cache intercepts */
> - svm->nested.intercept_cr = nested_vmcb->control.intercept_cr;
> - svm->nested.intercept_dr = nested_vmcb->control.intercept_dr;
> - svm->nested.intercept_exceptions = nested_vmcb->control.intercept_exceptions;
> - svm->nested.intercept = nested_vmcb->control.intercept;
> -
> - svm_flush_tlb(&svm->vcpu, true);
> - svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
> - if (nested_vmcb->control.int_ctl & V_INTR_MASKING_MASK)
> - svm->vcpu.arch.hflags |= HF_VINTR_MASK;
> - else
> - svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
> -
> - svm->vcpu.arch.tsc_offset += nested_vmcb->control.tsc_offset;
> - svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset;
> -
> - svm->vmcb->control.virt_ext = nested_vmcb->control.virt_ext;
> - svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
> - svm->vmcb->control.int_state = nested_vmcb->control.int_state;
> - svm->vmcb->control.event_inj = nested_vmcb->control.event_inj;
> - svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err;
> -
> - svm->vmcb->control.pause_filter_count =
> - nested_vmcb->control.pause_filter_count;
> - svm->vmcb->control.pause_filter_thresh =
> - nested_vmcb->control.pause_filter_thresh;
> -
> - kvm_vcpu_unmap(&svm->vcpu, map, true);
> -
> - /* Enter Guest-Mode */
> - enter_guest_mode(&svm->vcpu);
> -
> - /*
> - * Merge guest and host intercepts - must be called with vcpu in
> - * guest-mode to take affect here
> - */
> - recalc_intercepts(svm);
> -
> - svm->nested.vmcb = vmcb_gpa;
> -
> - /*
> - * If L1 had a pending IRQ/NMI before executing VMRUN,
> - * which wasn't delivered because it was disallowed (e.g.
> - * interrupts disabled), L0 needs to evaluate if this pending
> - * event should cause an exit from L2 to L1 or be delivered
> - * directly to L2.
> - *
> - * Usually this would be handled by the processor noticing an
> - * IRQ/NMI window request. However, VMRUN can unblock interrupts
> - * by implicitly setting GIF, so force L0 to perform pending event
> - * evaluation by requesting a KVM_REQ_EVENT.
> - */
> - enable_gif(svm);
> - if (unlikely(evaluate_pending_interrupts))
> - kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
> -
> - mark_all_dirty(svm->vmcb);
> -}
> -
> -static int nested_svm_vmrun(struct vcpu_svm *svm)
> -{
> - int ret;
> - struct vmcb *nested_vmcb;
> - struct vmcb *hsave = svm->nested.hsave;
> - struct vmcb *vmcb = svm->vmcb;
> - struct kvm_host_map map;
> - u64 vmcb_gpa;
> -
> - vmcb_gpa = svm->vmcb->save.rax;
> -
> - ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb_gpa), &map);
> - if (ret == -EINVAL) {
> - kvm_inject_gp(&svm->vcpu, 0);
> - return 1;
> - } else if (ret) {
> - return kvm_skip_emulated_instruction(&svm->vcpu);
> - }
> -
> - ret = kvm_skip_emulated_instruction(&svm->vcpu);
> -
> - nested_vmcb = map.hva;
> -
> - if (!nested_vmcb_checks(nested_vmcb)) {
> - nested_vmcb->control.exit_code = SVM_EXIT_ERR;
> - nested_vmcb->control.exit_code_hi = 0;
> - nested_vmcb->control.exit_info_1 = 0;
> - nested_vmcb->control.exit_info_2 = 0;
> -
> - kvm_vcpu_unmap(&svm->vcpu, &map, true);
> -
> - return ret;
> - }
> -
> - trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa,
> - nested_vmcb->save.rip,
> - nested_vmcb->control.int_ctl,
> - nested_vmcb->control.event_inj,
> - nested_vmcb->control.nested_ctl);
> -
> - trace_kvm_nested_intercepts(nested_vmcb->control.intercept_cr & 0xffff,
> - nested_vmcb->control.intercept_cr >> 16,
> - nested_vmcb->control.intercept_exceptions,
> - nested_vmcb->control.intercept);
> -
> - /* Clear internal status */
> - kvm_clear_exception_queue(&svm->vcpu);
> - kvm_clear_interrupt_queue(&svm->vcpu);
> -
> - /*
> - * Save the old vmcb, so we don't need to pick what we save, but can
> - * restore everything when a VMEXIT occurs
> - */
> - hsave->save.es = vmcb->save.es;
> - hsave->save.cs = vmcb->save.cs;
> - hsave->save.ss = vmcb->save.ss;
> - hsave->save.ds = vmcb->save.ds;
> - hsave->save.gdtr = vmcb->save.gdtr;
> - hsave->save.idtr = vmcb->save.idtr;
> - hsave->save.efer = svm->vcpu.arch.efer;
> - hsave->save.cr0 = kvm_read_cr0(&svm->vcpu);
> - hsave->save.cr4 = svm->vcpu.arch.cr4;
> - hsave->save.rflags = kvm_get_rflags(&svm->vcpu);
> - hsave->save.rip = kvm_rip_read(&svm->vcpu);
> - hsave->save.rsp = vmcb->save.rsp;
> - hsave->save.rax = vmcb->save.rax;
> - if (npt_enabled)
> - hsave->save.cr3 = vmcb->save.cr3;
> - else
> - hsave->save.cr3 = kvm_read_cr3(&svm->vcpu);
> -
> - copy_vmcb_control_area(hsave, vmcb);
> -
> - enter_svm_guest_mode(svm, vmcb_gpa, nested_vmcb, &map);
> -
> - if (!nested_svm_vmrun_msrpm(svm)) {
> - svm->vmcb->control.exit_code = SVM_EXIT_ERR;
> - svm->vmcb->control.exit_code_hi = 0;
> - svm->vmcb->control.exit_info_1 = 0;
> - svm->vmcb->control.exit_info_2 = 0;
> -
> - nested_svm_vmexit(svm);
> - }
> -
> - return ret;
> -}
> -
> -static void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
> -{
> - to_vmcb->save.fs = from_vmcb->save.fs;
> - to_vmcb->save.gs = from_vmcb->save.gs;
> - to_vmcb->save.tr = from_vmcb->save.tr;
> - to_vmcb->save.ldtr = from_vmcb->save.ldtr;
> - to_vmcb->save.kernel_gs_base = from_vmcb->save.kernel_gs_base;
> - to_vmcb->save.star = from_vmcb->save.star;
> - to_vmcb->save.lstar = from_vmcb->save.lstar;
> - to_vmcb->save.cstar = from_vmcb->save.cstar;
> - to_vmcb->save.sfmask = from_vmcb->save.sfmask;
> - to_vmcb->save.sysenter_cs = from_vmcb->save.sysenter_cs;
> - to_vmcb->save.sysenter_esp = from_vmcb->save.sysenter_esp;
> - to_vmcb->save.sysenter_eip = from_vmcb->save.sysenter_eip;
> -}
> -
> static int vmload_interception(struct vcpu_svm *svm)
> {
> struct vmcb *nested_vmcb;
> @@ -5183,11 +4055,6 @@ static void svm_set_irq(struct kvm_vcpu *vcpu)
> SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
> }
>
> -static inline bool svm_nested_virtualize_tpr(struct kvm_vcpu *vcpu)
> -{
> - return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK);
> -}
> -
> static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
> {
> struct vcpu_svm *svm = to_svm(vcpu);
> @@ -5629,7 +4496,7 @@ static int svm_set_identity_map_addr(struct kvm *kvm, u64 ident_addr)
> return 0;
> }
>
> -static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa)
> +void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa)
> {
> struct vcpu_svm *svm = to_svm(vcpu);
>
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> new file mode 100644
> index 000000000000..f4c446d7a31e
> --- /dev/null
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -0,0 +1,381 @@
> +// 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@...ranet.com>
> + * Avi Kivity <avi@...ranet.com>
> + */
> +
> +#ifndef __SVM_SVM_H
> +#define __SVM_SVM_H
> +
> +#include <linux/kvm_types.h>
> +#include <linux/kvm_host.h>
> +
> +#include <asm/svm.h>
> +
> +static const u32 host_save_user_msrs[] = {
> +#ifdef CONFIG_X86_64
> + MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
> + MSR_FS_BASE,
> +#endif
> + MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
> + MSR_TSC_AUX,
> +};
> +
> +#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
> +
> +#define MSRPM_OFFSETS 16
> +extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
> +extern bool npt_enabled;
> +
> +enum {
> + VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
> + pause filter count */
> + VMCB_PERM_MAP, /* IOPM Base and MSRPM Base */
> + VMCB_ASID, /* ASID */
> + VMCB_INTR, /* int_ctl, int_vector */
> + VMCB_NPT, /* npt_en, nCR3, gPAT */
> + VMCB_CR, /* CR0, CR3, CR4, EFER */
> + VMCB_DR, /* DR6, DR7 */
> + VMCB_DT, /* GDT, IDT */
> + VMCB_SEG, /* CS, DS, SS, ES, CPL */
> + VMCB_CR2, /* CR2 only */
> + VMCB_LBR, /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */
> + VMCB_AVIC, /* AVIC APIC_BAR, AVIC APIC_BACKING_PAGE,
> + * AVIC PHYSICAL_TABLE pointer,
> + * AVIC LOGICAL_TABLE pointer
> + */
> + VMCB_DIRTY_MAX,
> +};
> +
> +/* TPR and CR2 are always written before VMRUN */
> +#define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2))
> +
> +struct kvm_sev_info {
> + bool active; /* SEV enabled guest */
> + unsigned int asid; /* ASID used for this guest */
> + unsigned int handle; /* SEV firmware handle */
> + int fd; /* SEV device fd */
> + unsigned long pages_locked; /* Number of pages locked */
> + struct list_head regions_list; /* List of registered regions */
> +};
> +
> +struct kvm_svm {
> + struct kvm kvm;
> +
> + /* Struct members for AVIC */
> + u32 avic_vm_id;
> + struct page *avic_logical_id_table_page;
> + struct page *avic_physical_id_table_page;
> + struct hlist_node hnode;
> +
> + struct kvm_sev_info sev_info;
> +};
> +
> +struct kvm_vcpu;
> +
> +struct nested_state {
Not sure if it's worth doing in this patch (or even patch series) but
I'd suggest we name this e.g. "struct svm_nested_state" as this is not
local to svm.c anymore.
> + struct vmcb *hsave;
> + u64 hsave_msr;
> + u64 vm_cr_msr;
> + u64 vmcb;
> +
> + /* These are the merged vectors */
> + u32 *msrpm;
> +
> + /* gpa pointers to the real vectors */
> + u64 vmcb_msrpm;
> + u64 vmcb_iopm;
> +
> + /* 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;
> +};
> +
> +struct vcpu_svm {
> + struct kvm_vcpu vcpu;
> + struct vmcb *vmcb;
> + unsigned long vmcb_pa;
> + struct svm_cpu_data *svm_data;
> + uint64_t asid_generation;
> + uint64_t sysenter_esp;
> + uint64_t sysenter_eip;
> + uint64_t tsc_aux;
> +
> + u64 msr_decfg;
> +
> + u64 next_rip;
> +
> + u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
> + struct {
> + u16 fs;
> + u16 gs;
> + u16 ldt;
> + u64 gs_base;
> + } host;
> +
> + u64 spec_ctrl;
> + /*
> + * Contains guest-controlled bits of VIRT_SPEC_CTRL, which will be
> + * translated into the appropriate L2_CFG bits on the host to
> + * perform speculative control.
> + */
> + u64 virt_spec_ctrl;
> +
> + u32 *msrpm;
> +
> + ulong nmi_iret_rip;
> +
> + struct nested_state nested;
> +
> + bool nmi_singlestep;
> + u64 nmi_singlestep_guest_rflags;
> +
> + unsigned int3_injected;
> + unsigned long int3_rip;
> +
> + /* cached guest cpuid flags for faster access */
> + bool nrips_enabled : 1;
> +
> + u32 ldr_reg;
> + u32 dfr_reg;
> + struct page *avic_backing_page;
> + u64 *avic_physical_id_cache;
> + bool avic_is_running;
> +
> + /*
> + * Per-vcpu list of struct amd_svm_iommu_ir:
> + * This is used mainly to store interrupt remapping information used
> + * when update the vcpu affinity. This avoids the need to scan for
> + * IRTE and try to match ga_tag in the IOMMU driver.
> + */
> + struct list_head ir_list;
> + spinlock_t ir_list_lock;
> +
> + /* which host CPU was used for running this vcpu */
> + unsigned int last_cpu;
> +};
> +
> +void recalc_intercepts(struct vcpu_svm *svm);
> +
> +static inline void mark_all_dirty(struct vmcb *vmcb)
> +{
> + vmcb->control.clean = 0;
> +}
> +
> +static inline void mark_all_clean(struct vmcb *vmcb)
> +{
> + vmcb->control.clean = ((1 << VMCB_DIRTY_MAX) - 1)
> + & ~VMCB_ALWAYS_DIRTY_MASK;
> +}
> +
> +static inline void mark_dirty(struct vmcb *vmcb, int bit)
> +{
> + vmcb->control.clean &= ~(1 << bit);
> +}
... same goes to the three functions above (suggestion: add 'vmcb_'
prefix to all of them).
> +
> +static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
> +{
> + return container_of(vcpu, struct vcpu_svm, vcpu);
> +}
> +
> +static inline struct vmcb *get_host_vmcb(struct vcpu_svm *svm)
> +{
> + if (is_guest_mode(&svm->vcpu))
> + return svm->nested.hsave;
> + else
> + return svm->vmcb;
> +}
> +
> +static inline void set_cr_intercept(struct vcpu_svm *svm, int bit)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept_cr |= (1U << bit);
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline void clr_cr_intercept(struct vcpu_svm *svm, int bit)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept_cr &= ~(1U << bit);
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline bool is_cr_intercept(struct vcpu_svm *svm, int bit)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + return vmcb->control.intercept_cr & (1U << bit);
> +}
> +
> +static inline void set_dr_intercepts(struct vcpu_svm *svm)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept_dr = (1 << INTERCEPT_DR0_READ)
> + | (1 << INTERCEPT_DR1_READ)
> + | (1 << INTERCEPT_DR2_READ)
> + | (1 << INTERCEPT_DR3_READ)
> + | (1 << INTERCEPT_DR4_READ)
> + | (1 << INTERCEPT_DR5_READ)
> + | (1 << INTERCEPT_DR6_READ)
> + | (1 << INTERCEPT_DR7_READ)
> + | (1 << INTERCEPT_DR0_WRITE)
> + | (1 << INTERCEPT_DR1_WRITE)
> + | (1 << INTERCEPT_DR2_WRITE)
> + | (1 << INTERCEPT_DR3_WRITE)
> + | (1 << INTERCEPT_DR4_WRITE)
> + | (1 << INTERCEPT_DR5_WRITE)
> + | (1 << INTERCEPT_DR6_WRITE)
> + | (1 << INTERCEPT_DR7_WRITE);
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline void clr_dr_intercepts(struct vcpu_svm *svm)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept_dr = 0;
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline void set_exception_intercept(struct vcpu_svm *svm, int bit)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept_exceptions |= (1U << bit);
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline void clr_exception_intercept(struct vcpu_svm *svm, int bit)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept_exceptions &= ~(1U << bit);
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline void set_intercept(struct vcpu_svm *svm, int bit)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept |= (1ULL << bit);
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline void clr_intercept(struct vcpu_svm *svm, int bit)
> +{
> + struct vmcb *vmcb = get_host_vmcb(svm);
> +
> + vmcb->control.intercept &= ~(1ULL << bit);
> +
> + recalc_intercepts(svm);
> +}
> +
> +static inline bool is_intercept(struct vcpu_svm *svm, int bit)
> +{
> + return (svm->vmcb->control.intercept & (1ULL << bit)) != 0;
> +}
... and these three (suggestion: add 'svm_' prefix)
> +
> +static inline bool vgif_enabled(struct vcpu_svm *svm)
> +{
> + return !!(svm->vmcb->control.int_ctl & V_GIF_ENABLE_MASK);
> +}
> +
> +static inline void enable_gif(struct vcpu_svm *svm)
> +{
> + if (vgif_enabled(svm))
> + svm->vmcb->control.int_ctl |= V_GIF_MASK;
> + else
> + svm->vcpu.arch.hflags |= HF_GIF_MASK;
> +}
> +
> +static inline void disable_gif(struct vcpu_svm *svm)
> +{
> + if (vgif_enabled(svm))
> + svm->vmcb->control.int_ctl &= ~V_GIF_MASK;
> + else
> + svm->vcpu.arch.hflags &= ~HF_GIF_MASK;
> +}
> +
> +static inline bool gif_set(struct vcpu_svm *svm)
> +{
> + if (vgif_enabled(svm))
> + return !!(svm->vmcb->control.int_ctl & V_GIF_MASK);
> + else
> + return !!(svm->vcpu.arch.hflags & HF_GIF_MASK);
> +}
> +
> +/* svm.c */
> +#define MSR_INVALID 0xffffffffU
> +
> +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 disable_nmi_singlestep(struct vcpu_svm *svm);
> +
> +/* nested.c */
> +
> +#define NESTED_EXIT_HOST 0 /* Exit handled on host level */
> +#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)
svm_nested_virtualize_tpr() -> nested_svm_virtualize_tpr() to match the rest.
> +{
> + return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK);
> +}
> +
> +void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
> + struct vmcb *nested_vmcb, struct kvm_host_map *map);
> +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);
> +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);
> +
> +#endif
--
Vitaly
Powered by blists - more mailing lists