From: Christoph Egger <Christoph.Egger@amd.com>
To: "xen-devel@lists.xensource.com" <xen-devel@lists.xensource.com>
Subject: [PATCH 09/12] Nested Virtualization: svm specific implementation
Date: Mon, 20 Dec 2010 17:10:16 +0100 [thread overview]
Message-ID: <201012201710.17688.Christoph.Egger@amd.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 264 bytes --]
--
---to satisfy European Law for business letters:
Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach b. Muenchen
Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd
Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632
[-- Attachment #2: xen_nh09_svm.diff --]
[-- Type: text/x-diff, Size: 75914 bytes --]
# HG changeset patch
# User cegger
# Date 1292860414 -3600
Implement SVM specific part for Nested Virtualization
Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
diff -r c8531969c8eb -r 70978f4bf445 xen/arch/x86/hvm/svm/Makefile
--- a/xen/arch/x86/hvm/svm/Makefile
+++ b/xen/arch/x86/hvm/svm/Makefile
@@ -2,6 +2,8 @@ obj-y += asid.o
obj-y += emulate.o
obj-y += entry.o
obj-y += intr.o
+obj-y += nestedsvm.o
obj-y += svm.o
+obj-y += svmdebug.o
obj-y += vmcb.o
obj-y += vpmu.o
diff -r c8531969c8eb -r 70978f4bf445 xen/arch/x86/hvm/svm/emulate.c
--- a/xen/arch/x86/hvm/svm/emulate.c
+++ b/xen/arch/x86/hvm/svm/emulate.c
@@ -102,6 +102,11 @@ MAKE_INSTR(INT3, 1, 0xcc);
MAKE_INSTR(RDTSC, 2, 0x0f, 0x31);
MAKE_INSTR(PAUSE, 1, 0x90);
MAKE_INSTR(XSETBV, 3, 0x0f, 0x01, 0xd1);
+MAKE_INSTR(VMRUN, 3, 0x0f, 0x01, 0xd8);
+MAKE_INSTR(VMLOAD, 3, 0x0f, 0x01, 0xda);
+MAKE_INSTR(VMSAVE, 3, 0x0f, 0x01, 0xdb);
+MAKE_INSTR(STGI, 3, 0x0f, 0x01, 0xdc);
+MAKE_INSTR(CLGI, 3, 0x0f, 0x01, 0xdd);
static const u8 *opc_bytes[INSTR_MAX_COUNT] =
{
@@ -116,6 +121,11 @@ static const u8 *opc_bytes[INSTR_MAX_COU
[INSTR_RDTSC] = OPCODE_RDTSC,
[INSTR_PAUSE] = OPCODE_PAUSE,
[INSTR_XSETBV] = OPCODE_XSETBV,
+ [INSTR_VMRUN] = OPCODE_VMRUN,
+ [INSTR_VMLOAD] = OPCODE_VMLOAD,
+ [INSTR_VMSAVE] = OPCODE_VMSAVE,
+ [INSTR_STGI] = OPCODE_STGI,
+ [INSTR_CLGI] = OPCODE_CLGI,
};
static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len)
diff -r c8531969c8eb -r 70978f4bf445 xen/arch/x86/hvm/svm/entry.S
--- a/xen/arch/x86/hvm/svm/entry.S
+++ b/xen/arch/x86/hvm/svm/entry.S
@@ -54,6 +54,7 @@
ENTRY(svm_asm_do_resume)
call svm_intr_assist
+ call_with_regs(nsvm_vcpu_switch)
get_current(bx)
CLGI
diff -r c8531969c8eb -r 70978f4bf445 xen/arch/x86/hvm/svm/nestedsvm.c
--- /dev/null
+++ b/xen/arch/x86/hvm/svm/nestedsvm.c
@@ -0,0 +1,1239 @@
+/*
+ * nestedsvm.c: Nested Virtualization
+ * Copyright (c) 2010, Advanced Micro Devices, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <asm/hvm/support.h>
+#include <asm/hvm/svm/emulate.h>
+#include <asm/hvm/svm/svm.h>
+#include <asm/hvm/svm/vmcb.h>
+#include <asm/hvm/nestedhvm.h>
+#include <asm/hvm/svm/nestedsvm.h>
+#include <asm/hvm/svm/svmdebug.h>
+#include <asm/paging.h> /* paging_mode_hap */
+
+static int
+nestedsvm_vmcb_isvalid(struct vcpu *v, uint64_t vmcxaddr)
+{
+ if ( !hvm_svm_enabled(v) || hvm_guest_x86_mode(v) < 2 )
+ return 0;
+
+ /* Maximum valid physical address.
+ * See AMD BKDG for HSAVE_PA MSR.
+ */
+ if ( vmcxaddr > 0xfd00000000ULL )
+ return 0;
+
+ return 1;
+}
+
+int nestedsvm_vmcb_map(struct vcpu *v, uint64_t vmcbaddr)
+{
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+
+ if (nv->nv_vmcx != NULL && nv->nv_vmcxaddr != vmcbaddr) {
+ ASSERT(nv->nv_vmcx != NULL);
+ ASSERT(nv->nv_vmcxaddr != VMCX_EADDR);
+ hvm_unmap_guest_frame(nv->nv_vmcx);
+ nv->nv_vmcx = NULL;
+ nv->nv_vmcxaddr = VMCX_EADDR;
+ }
+
+ if (nv->nv_vmcx == NULL) {
+ nv->nv_vmcx = hvm_map_guest_frame_rw(vmcbaddr >> PAGE_SHIFT);
+ if (nv->nv_vmcx == NULL)
+ return 0;
+ nv->nv_vmcxaddr = vmcbaddr;
+ }
+
+ return 1;
+}
+
+/* Interface methods */
+int nsvm_vcpu_initialise(struct vcpu *v)
+{
+ void *msrpm;
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+
+ msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE), 0);
+ svm->ns_cached_msrpm = msrpm;
+ if (msrpm == NULL)
+ goto err;
+ memset(msrpm, 0x0, MSRPM_SIZE);
+
+ msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE), 0);
+ svm->ns_merged_msrpm = msrpm;
+ if (msrpm == NULL)
+ goto err;
+ memset(msrpm, 0x0, MSRPM_SIZE);
+
+ svm->ns_hostsave = alloc_vmcb();
+ if (svm->ns_hostsave == NULL)
+ goto err;
+
+ return 0;
+
+err:
+ nsvm_vcpu_destroy(v);
+ return -ENOMEM;
+}
+
+int nsvm_vcpu_destroy(struct vcpu *v)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+
+ if (svm->ns_cached_msrpm) {
+ free_xenheap_pages(svm->ns_cached_msrpm,
+ get_order_from_bytes(MSRPM_SIZE));
+ svm->ns_cached_msrpm = NULL;
+ }
+ if (svm->ns_merged_msrpm) {
+ free_xenheap_pages(svm->ns_merged_msrpm,
+ get_order_from_bytes(MSRPM_SIZE));
+ svm->ns_merged_msrpm = NULL;
+ }
+ if (svm->ns_hostsave) {
+ free_vmcb(svm->ns_hostsave);
+ svm->ns_hostsave = NULL;
+ }
+ if (svm->ns_iomap) {
+ nestedhvm_vcpu_iomap_put(svm->ns_iomap);
+ svm->ns_iomap = NULL;
+ }
+
+ return 0;
+}
+
+int nsvm_vcpu_reset(struct vcpu *v)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+
+ svm->ns_msr_hsavepa = 0;
+
+ svm->ns_cr_intercepts = 0;
+ svm->ns_dr_intercepts = 0;
+ svm->ns_exception_intercepts = 0;
+ svm->ns_general1_intercepts = 0;
+ svm->ns_general2_intercepts = 0;
+ svm->ns_lbr_control.bytes = 0;
+
+ svm->ns_hap_enabled = 0;
+ svm->ns_vmcb_guestcr3 = 0;
+ svm->ns_vmcb_hostcr3 = 0;
+ svm->ns_guest_asid = 0;
+ svm->ns_hostflags.bytes = 0;
+ svm->ns_vmexit.exitinfo1 = 0;
+ svm->ns_vmexit.exitinfo2 = 0;
+
+ if (svm->ns_iomap) {
+ nestedhvm_vcpu_iomap_put(svm->ns_iomap);
+ svm->ns_iomap = NULL;
+ }
+
+ return 0;
+}
+
+static void nsvm_vmcb_loadsave(struct vmcb_struct *from,
+ struct vmcb_struct *to)
+{
+ to->fs = from->fs;
+ to->gs = from->gs;
+ to->tr = from->tr;
+ to->ldtr = from->ldtr;
+ to->kerngsbase = from->kerngsbase;
+ to->star = from->star;
+ to->lstar = from->lstar;
+ to->cstar = from->cstar;
+ to->sfmask = from->sfmask;
+ to->sysenter_cs = from->sysenter_cs;
+ to->sysenter_esp = from->sysenter_esp;
+ to->sysenter_eip = from->sysenter_eip;
+}
+
+static int nsvm_vcpu_hostsave(struct vcpu *v, unsigned int inst_len)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct vmcb_struct *hsave, *vmcb;
+
+ hsave = svm->ns_hostsave;
+ vmcb = v->arch.hvm_svm.vmcb;
+
+ memcpy(hsave, vmcb, sizeof(struct vmcb_struct));
+ hsave->rip += inst_len;
+
+ /* Remember the host interrupt flag */
+ svm->ns_hostflags.fields.rflagsif = (hsave->rflags & X86_EFLAGS_IF) ? 1 : 0;
+
+ if (nestedhvm_paging_mode_hap(v)) {
+ /* guest: nested paging mode */
+ hsave->_cr3 = vmcb->_cr3;
+ hsave->_h_cr3 = vmcb->_h_cr3;
+ } else if (paging_mode_hap(v->domain))
+ /* host: nested paging, guest: shadow paging */
+ hsave->_cr3 = vmcb->_cr3;
+ else
+ /* host: shadow paging, guest: shadow paging */
+ hsave->_cr3 = v->arch.hvm_vcpu.guest_cr[3];
+
+ hsave->_efer = v->arch.hvm_vcpu.guest_efer;
+ hsave->_cr0 = v->arch.hvm_vcpu.guest_cr[0];
+ hsave->_cr2 = v->arch.hvm_vcpu.guest_cr[2];
+ hsave->_cr4 = v->arch.hvm_vcpu.guest_cr[4];
+ hsave->cleanbits.bytes = 0;
+
+ return 0;
+}
+
+int nsvm_vcpu_hostrestore(struct vcpu *v, struct cpu_user_regs *regs)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct vmcb_struct *hsave, *vmcb;
+ int rc;
+
+ hsave = svm->ns_hostsave;
+ vmcb = v->arch.hvm_svm.vmcb;
+
+ /* Must keep register values handled by VMSAVE/VMLOAD */
+ nsvm_vmcb_loadsave(vmcb, hsave);
+ memcpy(vmcb, hsave, sizeof(struct vmcb_struct));
+
+ /* EFER */
+ v->arch.hvm_vcpu.guest_efer = vmcb->_efer;
+ rc = hvm_set_efer(vmcb->_efer);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_efer failed, rc: %u\n", rc);
+
+ /* CR4 */
+ v->arch.hvm_vcpu.guest_cr[4] = vmcb->_cr4;
+ rc = hvm_set_cr4(vmcb->_cr4);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_cr4 failed, rc: %u\n", rc);
+
+ /* CR0 */
+ v->arch.hvm_vcpu.guest_cr[0] = vmcb->_cr0 | X86_CR0_PE;
+ vmcb->rflags &= ~X86_EFLAGS_VM;
+ rc = hvm_set_cr0(vmcb->_cr0 | X86_CR0_PE);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_cr0 failed, rc: %u\n", rc);
+
+ /* CR2 */
+ v->arch.hvm_vcpu.guest_cr[2] = vmcb->_cr2;
+ hvm_update_guest_cr(v, 2);
+
+ /* CR3 */
+ /* Nested paging mode */
+ if (nestedhvm_paging_mode_hap(v)) {
+ /* host nested paging + guest nested paging. */
+ /* hvm_set_cr3() below sets v->arch.hvm_vcpu.guest_cr[3] for us. */
+ } else if (paging_mode_hap(v->domain)) {
+ /* host nested paging + guest shadow paging. */
+ /* hvm_set_cr3() below sets v->arch.hvm_vcpu.guest_cr[3] for us. */
+ } else {
+ /* host shadow paging + guest shadow paging. */
+
+ /* Reset MMU context -- XXX (hostrestore) not yet working*/
+ if (!pagetable_is_null(v->arch.guest_table))
+ put_page(pagetable_get_page(v->arch.guest_table));
+ v->arch.guest_table = pagetable_null();
+ /* hvm_set_cr3() below sets v->arch.hvm_vcpu.guest_cr[3] for us. */
+ }
+ rc = hvm_set_cr3(vmcb->_cr3);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_cr3 failed, rc: %u\n", rc);
+
+ regs->eax = vmcb->rax;
+ regs->esp = vmcb->rsp;
+ regs->eip = vmcb->rip;
+ regs->eflags = vmcb->rflags;
+ vmcb->_dr7 = 0; /* disable all breakpoints */
+ vmcb->_cpl = 0;
+
+ /* Clear exitintinfo to prevent a fault loop of re-injecting
+ * exceptions forever.
+ */
+ vmcb->exitintinfo.bytes = 0;
+
+ /* Cleanbits */
+ vmcb->cleanbits.bytes = 0;
+
+ hvm_asid_flush_vcpu(v);
+
+ return 0;
+}
+
+static int nsvm_vmrun_permissionmap(struct vcpu *v)
+{
+ struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+ struct vmcb_struct *ns_vmcb = nv->nv_vmcx;
+ struct vmcb_struct *host_vmcb = arch_svm->vmcb;
+ unsigned long *ns_msrpm_ptr;
+ unsigned int i;
+ enum hvm_copy_result ret;
+ unsigned long *ns_viomap;
+ bool_t ioport_80, ioport_ed;
+
+ ns_msrpm_ptr = (unsigned long *)svm->ns_cached_msrpm;
+
+ ret = hvm_copy_from_guest_phys(svm->ns_cached_msrpm,
+ ns_vmcb->_msrpm_base_pa, MSRPM_SIZE);
+ if (ret != HVMCOPY_okay) {
+ gdprintk(XENLOG_ERR, "hvm_copy_from_guest_phys msrpm %u\n", ret);
+ return 1;
+ }
+
+ /* Skip io bitmap merge since hvm_io_bitmap has all bits set but
+ * 0x80 and 0xed.
+ */
+ svm->ns_oiomap_pa = svm->ns_iomap_pa;
+ svm->ns_iomap_pa = ns_vmcb->_iopm_base_pa;
+
+ ns_viomap = hvm_map_guest_frame_ro(svm->ns_iomap_pa >> PAGE_SHIFT);
+ ASSERT(ns_viomap != NULL);
+ ioport_80 = test_bit(0x80, ns_viomap);
+ ioport_ed = test_bit(0xed, ns_viomap);
+ hvm_unmap_guest_frame(ns_viomap);
+
+ if (svm->ns_iomap != NULL) {
+ if (nv->nv_ioport80 != ioport_80 || nv->nv_ioportED != ioport_ed) {
+ nestedhvm_vcpu_iomap_put(svm->ns_iomap);
+ svm->ns_iomap = nestedhvm_vcpu_iomap_get(ioport_80, ioport_ed);
+ }
+ } else
+ svm->ns_iomap = nestedhvm_vcpu_iomap_get(ioport_80, ioport_ed);
+
+ nv->nv_ioport80 = ioport_80;
+ nv->nv_ioportED = ioport_ed;
+
+ /* v->arch.hvm_svm.msrpm has type unsigned long, thus
+ * BYTES_PER_LONG.
+ */
+ for (i = 0; i < MSRPM_SIZE / BYTES_PER_LONG; i++)
+ svm->ns_merged_msrpm[i] = arch_svm->msrpm[i] | ns_msrpm_ptr[i];
+
+ host_vmcb->_iopm_base_pa =
+ (uint64_t)virt_to_maddr(svm->ns_iomap);
+ host_vmcb->_msrpm_base_pa =
+ (uint64_t)virt_to_maddr(svm->ns_merged_msrpm);
+
+ return 0;
+}
+
+static int nsvm_vmcb_prepare4vmrun(struct vcpu *v, struct cpu_user_regs *regs)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct vmcb_struct *ns_vmcb = vcpu_nestedhvm(v).nv_vmcx;
+ struct vmcb_struct *host_vmcb = v->arch.hvm_svm.vmcb;
+ int rc;
+
+ /* Enable nested guest intercepts */
+ svm->ns_cr_intercepts = ns_vmcb->_cr_intercepts;
+ svm->ns_dr_intercepts = ns_vmcb->_dr_intercepts;
+ svm->ns_exception_intercepts = ns_vmcb->_exception_intercepts;
+ svm->ns_general1_intercepts = ns_vmcb->_general1_intercepts;
+ svm->ns_general2_intercepts = ns_vmcb->_general2_intercepts;
+
+ host_vmcb->_cr_intercepts |= ns_vmcb->_cr_intercepts;
+ host_vmcb->_dr_intercepts |= ns_vmcb->_dr_intercepts;
+ host_vmcb->_exception_intercepts |= ns_vmcb->_exception_intercepts;
+ host_vmcb->_general1_intercepts |= ns_vmcb->_general1_intercepts;
+ host_vmcb->_general2_intercepts |= ns_vmcb->_general2_intercepts;
+
+ /* Nested Pause Filter */
+ if (ns_vmcb->_general1_intercepts & GENERAL1_INTERCEPT_PAUSE)
+ host_vmcb->_pause_filter_count =
+ min(ns_vmcb->_pause_filter_count, host_vmcb->_pause_filter_count);
+ else
+ host_vmcb->_pause_filter_count = SVM_PAUSEFILTER_INIT;
+
+ /* Nested IO permission bitmaps */
+ rc = nsvm_vmrun_permissionmap(v);
+ if (rc)
+ return rc;
+
+ /* TSC offset */
+ host_vmcb->_tsc_offset += ns_vmcb->_tsc_offset;
+
+ /* ASID */
+ hvm_asid_flush_vcpu(v);
+ /* host_vmcb->_guest_asid = ns_vmcb->_guest_asid; */
+
+ /* TLB control */
+ host_vmcb->tlb_control |= ns_vmcb->tlb_control;
+
+ /* Virtual Interrupts */
+ host_vmcb->_vintr = ns_vmcb->_vintr;
+ host_vmcb->_vintr.fields.intr_masking = 1;
+
+ /* Shadow Mode */
+ host_vmcb->interrupt_shadow = ns_vmcb->interrupt_shadow;
+
+ /* Exit codes */
+ host_vmcb->exitcode = ns_vmcb->exitcode;
+ host_vmcb->exitinfo1 = ns_vmcb->exitinfo1;
+ host_vmcb->exitinfo2 = ns_vmcb->exitinfo2;
+ host_vmcb->exitintinfo = ns_vmcb->exitintinfo;
+
+ /* Pending Interrupts */
+ host_vmcb->eventinj = ns_vmcb->eventinj;
+
+ /* LBR virtualization */
+ svm->ns_lbr_control = ns_vmcb->lbr_control;
+ host_vmcb->lbr_control.bytes |= ns_vmcb->lbr_control.bytes;
+
+ /* NextRIP */
+ host_vmcb->nextrip = ns_vmcb->nextrip;
+
+ /*
+ * VMCB Save State Area
+ */
+
+ /* Segments */
+ host_vmcb->es = ns_vmcb->es;
+ host_vmcb->cs = ns_vmcb->cs;
+ host_vmcb->ss = ns_vmcb->ss;
+ host_vmcb->ds = ns_vmcb->ds;
+ host_vmcb->gdtr = ns_vmcb->gdtr;
+ host_vmcb->idtr = ns_vmcb->idtr;
+
+ /* CPL */
+ host_vmcb->_cpl = ns_vmcb->_cpl;
+
+ /* EFER */
+ v->arch.hvm_vcpu.guest_efer = ns_vmcb->_efer;
+ rc = hvm_set_efer(ns_vmcb->_efer);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_efer failed, rc: %u\n", rc);
+
+ /* CR4 */
+ v->arch.hvm_vcpu.guest_cr[4] = ns_vmcb->_cr4;
+ rc = hvm_set_cr4(ns_vmcb->_cr4);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_cr4 failed, rc: %u\n", rc);
+
+ /* CR0 */
+ v->arch.hvm_vcpu.guest_cr[0] = ns_vmcb->_cr0;
+ rc = hvm_set_cr0(ns_vmcb->_cr0);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_cr0 failed, rc: %u\n", rc);
+
+ /* CR2 */
+ v->arch.hvm_vcpu.guest_cr[2] = ns_vmcb->_cr2;
+ hvm_update_guest_cr(v, 2);
+
+ /* Nested paging mode */
+ if (nestedhvm_paging_mode_hap(v)) {
+ /* host nested paging + guest nested paging. */
+
+ /* hvm_set_cr3() below sets v->arch.hvm_vcpu.guest_cr[3] for us. */
+ rc = hvm_set_cr3(ns_vmcb->_cr3);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_cr3 failed, rc: %u\n", rc);
+ } else if (paging_mode_hap(v->domain)) {
+ /* host nested paging + guest shadow paging. */
+ host_vmcb->_np_enable = 1;
+ /* Keep h_cr3 as it is. */
+ /* When l1 guest does shadow paging
+ * we assume it intercepts page faults.
+ */
+ /* hvm_set_cr3() below sets v->arch.hvm_vcpu.guest_cr[3] for us. */
+ rc = hvm_set_cr3(ns_vmcb->_cr3);
+ if (rc != X86EMUL_OKAY)
+ gdprintk(XENLOG_ERR, "hvm_set_cr3 failed, rc: %u\n", rc);
+ } else {
+ /* host shadow paging + guest shadow paging. */
+ host_vmcb->_np_enable = 0;
+ host_vmcb->_h_cr3 = 0x0;
+
+ /* TODO: Once shadow-shadow paging is in place come back to here
+ * and set host_vmcb->_cr3 to the shadowed shadow table.
+ */
+ }
+
+ /* DRn */
+ host_vmcb->_dr7 = ns_vmcb->_dr7;
+ host_vmcb->_dr6 = ns_vmcb->_dr6;
+
+ /* RFLAGS */
+ host_vmcb->rflags = ns_vmcb->rflags;
+
+ /* RIP */
+ host_vmcb->rip = ns_vmcb->rip;
+
+ /* RSP */
+ host_vmcb->rsp = ns_vmcb->rsp;
+
+ /* RAX */
+ host_vmcb->rax = ns_vmcb->rax;
+
+ /* Keep the host values of the fs, gs, ldtr, tr, kerngsbase,
+ * star, lstar, cstar, sfmask, sysenter_cs, sysenter_esp,
+ * sysenter_eip. These are handled via VMSAVE/VMLOAD emulation.
+ */
+
+ /* Page tables */
+ host_vmcb->pdpe0 = ns_vmcb->pdpe0;
+ host_vmcb->pdpe1 = ns_vmcb->pdpe1;
+ host_vmcb->pdpe2 = ns_vmcb->pdpe2;
+ host_vmcb->pdpe3 = ns_vmcb->pdpe3;
+
+ /* PAT */
+ host_vmcb->_g_pat = ns_vmcb->_g_pat;
+
+ /* Debug Control MSR */
+ host_vmcb->_debugctlmsr = ns_vmcb->_debugctlmsr;
+
+ /* LBR MSRs */
+ host_vmcb->_lastbranchfromip = ns_vmcb->_lastbranchfromip;
+ host_vmcb->_lastbranchtoip = ns_vmcb->_lastbranchtoip;
+ host_vmcb->_lastintfromip = ns_vmcb->_lastintfromip;
+ host_vmcb->_lastinttoip = ns_vmcb->_lastinttoip;
+
+ /* Cleanbits */
+ host_vmcb->cleanbits.bytes = 0;
+
+ rc = svm_vmcb_isvalid(__func__, ns_vmcb, 1);
+ if (rc) {
+ gdprintk(XENLOG_ERR, "nested vmcb invalid\n");
+ return rc;
+ }
+
+ rc = svm_vmcb_isvalid(__func__, host_vmcb, 1);
+ if (rc) {
+ gdprintk(XENLOG_ERR, "host vmcb invalid\n");
+ return rc;
+ }
+
+ /* Switch guest registers to nested guest */
+ regs->eax = ns_vmcb->rax;
+ regs->eip = ns_vmcb->rip;
+ regs->esp = ns_vmcb->rsp;
+ regs->eflags = ns_vmcb->rflags;
+
+ return 0;
+}
+
+static int
+nsvm_vcpu_vmentry(struct vcpu *v, struct cpu_user_regs *regs,
+ unsigned int inst_len)
+{
+ int ret;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct vmcb_struct *hsave, *ns_vmcb, *hostvmcb;
+
+ hsave = svm->ns_hostsave;
+ ns_vmcb = nv->nv_vmcx;
+ hostvmcb = v->arch.hvm_svm.vmcb;
+ ASSERT(ns_vmcb != NULL);
+
+ /* Save values for later use. Needed for Nested-on-Nested and
+ * Shadow-on-Shadow paging.
+ */
+ svm->ns_vmcb_guestcr3 = ns_vmcb->_cr3;
+ svm->ns_vmcb_hostcr3 = ns_vmcb->_h_cr3;
+
+ nv->nv_flushp2m = (ns_vmcb->tlb_control
+ || (svm->ns_guest_asid != ns_vmcb->_guest_asid));
+ svm->ns_guest_asid = ns_vmcb->_guest_asid;
+
+ /* nested paging for the guest */
+ svm->ns_hap_enabled = (ns_vmcb->_np_enable) ? 1 : 0;
+
+ /* Remember the V_INTR_MASK in hostflags */
+ svm->ns_hostflags.fields.vintrmask =
+ (ns_vmcb->_vintr.fields.intr_masking) ? 1 : 0;
+
+ /* Save l1 guest state (= host state) */
+ ret = nsvm_vcpu_hostsave(v, inst_len);
+ if (ret) {
+ gdprintk(XENLOG_ERR, "hostsave failed\n");
+ return ret;
+ }
+
+ ret = nsvm_vmcb_prepare4vmrun(v, regs);
+ if (ret) {
+ gdprintk(XENLOG_ERR, "hostsave failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int
+nsvm_vcpu_vmrun(struct vcpu *v, struct cpu_user_regs *regs)
+{
+ int ret;
+ unsigned int inst_len;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+
+ inst_len = __get_instruction_length(v, INSTR_VMRUN);
+ if (inst_len == 0) {
+ svm->ns_vmexit.exitcode = VMEXIT_SHUTDOWN;
+ return -1;
+ }
+
+ nv->nv_vmswitch_in_progress = 1;
+ ASSERT(nv->nv_vmcx != NULL);
+
+ /* save host state */
+ ret = nsvm_vcpu_vmentry(v, regs, inst_len);
+ if (ret) {
+ gdprintk(XENLOG_ERR,
+ "nsvm_vcpu_vmentry failed, injecting #UD\n");
+ hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
+ nv->nv_vmswitch_in_progress = 0;
+ return 1;
+ }
+
+ /* Switch vcpu to guest mode
+ */
+ nestedhvm_vcpu_enter_guestmode(v);
+ nv->nv_vmswitch_in_progress = 0;
+ return 0;
+}
+
+int
+nsvm_vcpu_vmexit_inject(struct vcpu *v, struct cpu_user_regs *regs,
+ uint64_t exitcode)
+{
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct vmcb_struct *ns_vmcb;
+
+ ns_vmcb = nv->nv_vmcx;
+
+ if (nv->nv_vmexit_pending) {
+
+ switch (exitcode) {
+ case VMEXIT_INTR:
+ if ( unlikely(ns_vmcb->eventinj.fields.v)
+ && nv->nv_vmentry_pending
+ && hvm_event_needs_reinjection(ns_vmcb->eventinj.fields.type,
+ ns_vmcb->eventinj.fields.vector) )
+ {
+ ns_vmcb->exitintinfo.bytes = ns_vmcb->eventinj.bytes;
+ }
+ break;
+ case VMEXIT_EXCEPTION_PF:
+ ns_vmcb->_cr2 = ns_vmcb->exitinfo2;
+ /* fall through */
+ case VMEXIT_NPF:
+ /* PF error code */
+ ns_vmcb->exitinfo1 = svm->ns_vmexit.exitinfo1;
+ /* fault address */
+ ns_vmcb->exitinfo2 = svm->ns_vmexit.exitinfo2;
+ break;
+ case VMEXIT_EXCEPTION_NP:
+ case VMEXIT_EXCEPTION_SS:
+ case VMEXIT_EXCEPTION_GP:
+ case VMEXIT_EXCEPTION_15:
+ case VMEXIT_EXCEPTION_MF:
+ case VMEXIT_EXCEPTION_AC:
+ ns_vmcb->exitinfo1 = svm->ns_vmexit.exitinfo1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ ns_vmcb->exitcode = exitcode;
+ ns_vmcb->eventinj.bytes = 0;
+ return 0;
+}
+
+int
+nsvm_vcpu_vmexit_trap(struct vcpu *v, unsigned int trapnr,
+ int errcode, unsigned long cr2)
+{
+ ASSERT(vcpu_nestedhvm(v).nv_vmcx != NULL);
+
+ nestedsvm_vmexit_defer(v, VMEXIT_EXCEPTION_DE + trapnr, errcode, cr2);
+ return NESTEDHVM_VMEXIT_DONE;
+}
+
+uint64_t nsvm_vcpu_guestcr3(struct vcpu *v)
+{
+ return vcpu_nestedsvm(v).ns_vmcb_guestcr3;
+}
+
+uint64_t nsvm_vcpu_hostcr3(struct vcpu *v)
+{
+ return vcpu_nestedsvm(v).ns_vmcb_hostcr3;
+}
+
+uint32_t nsvm_vcpu_asid(struct vcpu *v)
+{
+ return vcpu_nestedsvm(v).ns_guest_asid;
+}
+
+static int
+nsvm_vmcb_guest_intercepts_msr(unsigned long *msr_bitmap,
+ uint32_t msr, bool_t write)
+{
+ bool_t enabled;
+ unsigned long *msr_bit;
+
+ msr_bit = svm_msrbit(msr_bitmap, msr);
+
+ if (msr_bit == NULL)
+ /* MSR not in the permission map: Let the guest handle it. */
+ return NESTEDHVM_VMEXIT_INJECT;
+
+ BUG_ON(msr_bit == NULL);
+ msr &= 0x1fff;
+
+ if (write)
+ /* write access */
+ enabled = test_bit(msr * 2 + 1, msr_bit);
+ else
+ /* read access */
+ enabled = test_bit(msr * 2, msr_bit);
+
+ if (!enabled)
+ return NESTEDHVM_VMEXIT_HOST;
+
+ return NESTEDHVM_VMEXIT_INJECT;
+}
+
+static int
+nsvm_vmcb_guest_intercepts_ioio(paddr_t iopm_pa, uint64_t exitinfo1)
+{
+ unsigned long iopm_gfn = iopm_pa >> PAGE_SHIFT;
+ unsigned long *io_bitmap = NULL;
+ ioio_info_t ioinfo;
+ uint16_t port;
+ bool_t enabled;
+
+ ioinfo.bytes = exitinfo1;
+ port = ioinfo.fields.port;
+
+ switch (port) {
+ case 0 ... 32767: /* first 4KB page */
+ io_bitmap = hvm_map_guest_frame_ro(iopm_gfn);
+ break;
+ case 32768 ... 65535: /* second 4KB page */
+ port -= 32768;
+ io_bitmap = hvm_map_guest_frame_ro(iopm_gfn+1);
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ if (io_bitmap == NULL) {
+ gdprintk(XENLOG_ERR,
+ "IOIO intercept: mapping of permission map failed\n");
+ return NESTEDHVM_VMEXIT_ERROR;
+ }
+
+ enabled = test_bit(port, io_bitmap);
+ hvm_unmap_guest_frame(io_bitmap);
+ if (!enabled)
+ return NESTEDHVM_VMEXIT_HOST;
+
+ return NESTEDHVM_VMEXIT_INJECT;
+}
+
+int
+nsvm_vmcb_guest_intercepts_exitcode(struct vcpu *v,
+ struct cpu_user_regs *regs, uint64_t exitcode)
+{
+ uint64_t exit_bits;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct vmcb_struct *ns_vmcb = nv->nv_vmcx;
+ enum nestedhvm_vmexits vmexits;
+
+ switch (exitcode) {
+ case VMEXIT_CR0_READ ... VMEXIT_CR15_READ:
+ case VMEXIT_CR0_WRITE ... VMEXIT_CR15_WRITE:
+ exit_bits = 1ULL << (exitcode - VMEXIT_CR0_READ);
+ if (svm->ns_cr_intercepts & exit_bits)
+ break;
+ return 0;
+
+ case VMEXIT_DR0_READ ... VMEXIT_DR7_READ:
+ case VMEXIT_DR0_WRITE ... VMEXIT_DR7_WRITE:
+ exit_bits = 1ULL << (exitcode - VMEXIT_DR0_READ);
+ if (svm->ns_dr_intercepts & exit_bits)
+ break;
+ return 0;
+
+ case VMEXIT_EXCEPTION_DE ... VMEXIT_EXCEPTION_XF:
+ exit_bits = 1ULL << (exitcode - VMEXIT_EXCEPTION_DE);
+ if (svm->ns_exception_intercepts & exit_bits)
+ break;
+ return 0;
+
+ case VMEXIT_INTR ... VMEXIT_SHUTDOWN:
+ exit_bits = 1ULL << (exitcode - VMEXIT_INTR);
+ if (svm->ns_general1_intercepts & exit_bits)
+ break;
+ return 0;
+
+ case VMEXIT_VMRUN ... VMEXIT_XSETBV:
+ exit_bits = 1ULL << (exitcode - VMEXIT_VMRUN);
+ if (svm->ns_general2_intercepts & exit_bits)
+ break;
+ return 0;
+
+ case VMEXIT_NPF:
+ case VMEXIT_INVALID:
+ /* Always intercepted */
+ break;
+
+ default:
+ gdprintk(XENLOG_ERR, "Illegal exitcode 0x%"PRIx64"\n", exitcode);
+ BUG();
+ break;
+ }
+
+ /* Special cases: Do more detailed checks */
+ switch (exitcode) {
+ case VMEXIT_MSR:
+ ASSERT(regs != NULL);
+ nestedsvm_vmcb_map(v, nv->nv_vmcxaddr);
+ ASSERT(nv->nv_vmcx != NULL);
+ ns_vmcb = nv->nv_vmcx;
+ vmexits = nsvm_vmcb_guest_intercepts_msr(svm->ns_cached_msrpm,
+ regs->ecx, ns_vmcb->exitinfo1 != 0);
+ if (vmexits == NESTEDHVM_VMEXIT_HOST)
+ return 0;
+ break;
+ case VMEXIT_IOIO:
+ nestedsvm_vmcb_map(v, nv->nv_vmcxaddr);
+ ASSERT(nv->nv_vmcx != NULL);
+ ns_vmcb = nv->nv_vmcx;
+ vmexits = nsvm_vmcb_guest_intercepts_ioio(ns_vmcb->_iopm_base_pa,
+ ns_vmcb->exitinfo1);
+ if (vmexits == NESTEDHVM_VMEXIT_HOST)
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+
+int
+nsvm_vmcb_guest_intercepts_trap(struct vcpu *v, unsigned int trapnr)
+{
+ return nsvm_vmcb_guest_intercepts_exitcode(v,
+ guest_cpu_user_regs(), VMEXIT_EXCEPTION_DE + trapnr);
+}
+
+static int
+nsvm_vmcb_prepare4vmexit(struct vcpu *v)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct vmcb_struct *ns_vmcb = vcpu_nestedhvm(v).nv_vmcx;
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+ svm_vmsave(vmcb);
+
+ /* Intercepts - keep them as they are */
+
+ /* Pausefilter - keep it as is */
+
+ /* Nested IO permission bitmap */
+ /* Just keep the iopm_base_pa and msrpm_base_pa values.
+ * The guest must not see the virtualized values.
+ */
+
+ /* TSC offset */
+ ns_vmcb->_tsc_offset = vmcb->_tsc_offset;
+
+ /* ASID */
+ /* ns_vmcb->_guest_asid = vmcb->_guest_asid; */
+
+ /* TLB control */
+ ns_vmcb->tlb_control = 0;
+
+ /* Virtual Interrupts */
+ ns_vmcb->_vintr = vmcb->_vintr;
+ if (!(svm->ns_hostflags.fields.vintrmask))
+ ns_vmcb->_vintr.fields.intr_masking = 0;
+
+ /* Shadow mode */
+ ns_vmcb->interrupt_shadow = vmcb->interrupt_shadow;
+
+ /* Exit codes */
+ ns_vmcb->exitcode = vmcb->exitcode;
+ ns_vmcb->exitinfo1 = vmcb->exitinfo1;
+ ns_vmcb->exitinfo2 = vmcb->exitinfo2;
+ ns_vmcb->exitintinfo = vmcb->exitintinfo;
+
+ /* Interrupts */
+ /* 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 eventinj
+ * here and copy it to exitintinfo if it is valid.
+ * exitintinfo and eventinj can't be both valid because the case below
+ * only happens on a VMRUN instruction intercept which has no valid
+ * exitintinfo set.
+ */
+ if ( unlikely(vmcb->eventinj.fields.v) &&
+ hvm_event_needs_reinjection(vmcb->eventinj.fields.type,
+ vmcb->eventinj.fields.vector) )
+ {
+ ns_vmcb->exitintinfo = vmcb->eventinj;
+ }
+
+ ns_vmcb->eventinj.bytes = 0;
+
+ /* Nested paging mode */
+ if (nestedhvm_paging_mode_hap(v)) {
+ /* host nested paging + guest nested paging. */
+ ns_vmcb->_np_enable = vmcb->_np_enable;
+ ns_vmcb->_cr3 = vmcb->_cr3;
+ /* The vmcb->h_cr3 is the shadowed h_cr3. The original
+ * unshadowed guest h_cr3 is kept in ns_vmcb->h_cr3,
+ * hence we keep the ns_vmcb->h_cr3 value. */
+ } else if (paging_mode_hap(v->domain)) {
+ /* host nested paging + guest shadow paging. */
+ ns_vmcb->_np_enable = 0;
+ /* Throw h_cr3 away. Guest is not allowed to set it or
+ * it can break out, otherwise (security hole!) */
+ ns_vmcb->_h_cr3 = 0x0;
+ /* Stop intercepting #PF (already done above
+ * by restoring cached intercepts). */
+ ns_vmcb->_cr3 = vmcb->_cr3;
+ } else {
+ /* host shadow paging + guest shadow paging. */
+ ns_vmcb->_np_enable = 0;
+ ns_vmcb->_h_cr3 = 0x0;
+ /* The vmcb->_cr3 is the shadowed cr3. The original
+ * unshadowed guest cr3 is kept in ns_vmcb->_cr3,
+ * hence we keep the ns_vmcb->_cr3 value. */
+ }
+
+ /* LBR virtualization - keep lbr control as is */
+
+ /* NextRIP */
+ ns_vmcb->nextrip = vmcb->nextrip;
+
+ /*
+ * VMCB Save State Area
+ */
+
+ /* Segments */
+ ns_vmcb->es = vmcb->es;
+ ns_vmcb->cs = vmcb->cs;
+ ns_vmcb->ss = vmcb->ss;
+ ns_vmcb->ds = vmcb->ds;
+ ns_vmcb->gdtr = vmcb->gdtr;
+ ns_vmcb->idtr = vmcb->idtr;
+
+ /* CPL */
+ ns_vmcb->_cpl = vmcb->_cpl;
+
+ /* EFER */
+ ns_vmcb->_efer = vmcb->_efer;
+
+ /* CRn */
+ ns_vmcb->_cr4 = vmcb->_cr4;
+ ns_vmcb->_cr0 = vmcb->_cr0;
+
+ /* DRn */
+ ns_vmcb->_dr7 = vmcb->_dr7;
+ ns_vmcb->_dr6 = vmcb->_dr6;
+
+ /* RFLAGS */
+ ns_vmcb->rflags = vmcb->rflags;
+
+ /* RIP */
+ ns_vmcb->rip = vmcb->rip;
+
+ /* RSP */
+ ns_vmcb->rsp = vmcb->rsp;
+
+ /* RAX */
+ ns_vmcb->rax = vmcb->rax;
+
+ /* Keep the nested guest values of the fs, gs, ldtr, tr, kerngsbase,
+ * star, lstar, cstar, sfmask, sysenter_cs, sysenter_esp,
+ * sysenter_eip. These are handled via VMSAVE/VMLOAD emulation.
+ */
+
+ /* CR2 */
+ ns_vmcb->_cr2 = vmcb->_cr2;
+
+ /* Page tables */
+ ns_vmcb->pdpe0 = vmcb->pdpe0;
+ ns_vmcb->pdpe1 = vmcb->pdpe1;
+ ns_vmcb->pdpe2 = vmcb->pdpe2;
+ ns_vmcb->pdpe3 = vmcb->pdpe3;
+
+ /* PAT */
+ ns_vmcb->_g_pat = vmcb->_g_pat;
+
+ /* Debug Control MSR */
+ ns_vmcb->_debugctlmsr = vmcb->_debugctlmsr;
+
+ /* LBR MSRs */
+ ns_vmcb->_lastbranchfromip = vmcb->_lastbranchfromip;
+ ns_vmcb->_lastbranchtoip = vmcb->_lastbranchtoip;
+ ns_vmcb->_lastintfromip = vmcb->_lastintfromip;
+ ns_vmcb->_lastinttoip = vmcb->_lastinttoip;
+
+ return 0;
+}
+
+bool_t
+nsvm_vmcb_hap_enabled(struct vcpu *v)
+{
+ return vcpu_nestedsvm(v).ns_hap_enabled;
+}
+
+/* MSR handling */
+int nsvm_rdmsr(struct vcpu *v, unsigned int msr, uint64_t *msr_content)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ int ret = 1;
+
+ *msr_content = 0;
+
+ switch (msr) {
+ case MSR_K8_VM_CR:
+ break;
+ case MSR_K8_VM_HSAVE_PA:
+ *msr_content = svm->ns_msr_hsavepa;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+int nsvm_wrmsr(struct vcpu *v, unsigned int msr, uint64_t msr_content)
+{
+ int ret = 1;
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+
+ switch (msr) {
+ case MSR_K8_VM_CR:
+ /* ignore write. handle all bits as read-only. */
+ break;
+ case MSR_K8_VM_HSAVE_PA:
+ if (!nestedsvm_vmcb_isvalid(v, msr_content)) {
+ gdprintk(XENLOG_ERR,
+ "MSR_K8_VM_HSAVE_PA value invalid 0x%"PRIx64"\n", msr_content);
+ ret = -1; /* inject #GP */
+ break;
+ }
+ svm->ns_msr_hsavepa = msr_content;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+/* VMEXIT emulation */
+void
+nestedsvm_vmexit_defer(struct vcpu *v,
+ uint64_t exitcode, uint64_t exitinfo1, uint64_t exitinfo2)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+
+ svm->ns_vmexit.exitcode = exitcode;
+ svm->ns_vmexit.exitinfo1 = exitinfo1;
+ svm->ns_vmexit.exitinfo2 = exitinfo2;
+ vcpu_nestedhvm(v).nv_vmexit_pending = 1;
+}
+
+enum nestedhvm_vmexits
+nestedsvm_check_intercepts(struct vcpu *v, struct cpu_user_regs *regs,
+ uint64_t exitcode)
+{
+ bool_t is_intercepted;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+
+ ASSERT(nv->nv_vmexit_pending == 0);
+ is_intercepted = nsvm_vmcb_guest_intercepts_exitcode(v, regs, exitcode);
+
+ switch (exitcode) {
+ case VMEXIT_INVALID:
+ if (is_intercepted)
+ return NESTEDHVM_VMEXIT_INJECT;
+ return NESTEDHVM_VMEXIT_HOST;
+
+ case VMEXIT_INTR:
+ case VMEXIT_NMI:
+ return NESTEDHVM_VMEXIT_HOST;
+ case VMEXIT_EXCEPTION_NM:
+ /* Host must handle lazy fpu context switching first.
+ * Then inject the VMEXIT if L1 guest intercepts this.
+ */
+ return NESTEDHVM_VMEXIT_HOST;
+
+ case VMEXIT_NPF:
+ if (nestedhvm_paging_mode_hap(v)) {
+ if (!is_intercepted)
+ return NESTEDHVM_VMEXIT_FATALERROR;
+ /* host nested paging + guest nested paging */
+ return NESTEDHVM_VMEXIT_HOST;
+ }
+ if (paging_mode_hap(v->domain)) {
+ if (is_intercepted)
+ return NESTEDHVM_VMEXIT_FATALERROR;
+ /* host nested paging + guest shadow paging */
+ return NESTEDHVM_VMEXIT_HOST;
+ }
+ /* host shadow paging + guest shadow paging */
+ /* Can this happen? */
+ BUG();
+ return NESTEDHVM_VMEXIT_FATALERROR;
+ case VMEXIT_EXCEPTION_PF:
+ if (nestedhvm_paging_mode_hap(v)) {
+ /* host nested paging + guest nested paging */
+ if (!is_intercepted)
+ /* l1 guest intercepts #PF unnecessarily */
+ return NESTEDHVM_VMEXIT_HOST;
+ /* l2 guest intercepts #PF unnecessarily */
+ return NESTEDHVM_VMEXIT_INJECT;
+ }
+ if (!paging_mode_hap(v->domain)) {
+ /* host shadow paging + guest shadow paging */
+ return NESTEDHVM_VMEXIT_HOST;
+ }
+ /* host nested paging + guest shadow paging */
+ return NESTEDHVM_VMEXIT_INJECT;
+ case VMEXIT_VMMCALL:
+ /* Always let the guest handle VMMCALL/VMCALL */
+ return NESTEDHVM_VMEXIT_INJECT;
+ default:
+ break;
+ }
+
+ if (is_intercepted)
+ return NESTEDHVM_VMEXIT_INJECT;
+ return NESTEDHVM_VMEXIT_HOST;
+}
+
+enum nestedhvm_vmexits
+nestedsvm_vmexit_n2n1(struct vcpu *v, struct cpu_user_regs *regs)
+{
+ int rc;
+ enum nestedhvm_vmexits ret = NESTEDHVM_VMEXIT_DONE;
+
+ ASSERT(vcpu_nestedhvm(v).nv_vmswitch_in_progress);
+ ASSERT(nestedhvm_vcpu_in_guestmode(v));
+
+ rc = nsvm_vmcb_prepare4vmexit(v);
+ if (rc)
+ ret = NESTEDHVM_VMEXIT_ERROR;
+
+ rc = nhvm_vcpu_hostrestore(v, regs);
+ if (rc)
+ ret = NESTEDHVM_VMEXIT_FATALERROR;
+
+ nestedhvm_vcpu_exit_guestmode(v);
+ return ret;
+}
+
+/* The exitcode is in native SVM/VMX format. The forced exitcode
+ * is in generic format.
+ */
+static enum nestedhvm_vmexits
+nestedsvm_vcpu_vmexit(struct vcpu *v, struct cpu_user_regs *regs,
+ uint64_t exitcode)
+{
+ int rc;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+
+ nv->nv_vmswitch_in_progress = 1;
+
+ ASSERT(nv->nv_vmcx != NULL);
+
+ /* On special intercepts the host has to handle
+ * the vcpu is still in guest mode here.
+ */
+ if (nestedhvm_vcpu_in_guestmode(v)) {
+ enum nestedhvm_vmexits ret;
+
+ ret = nestedsvm_vmexit_n2n1(v, regs);
+ switch (ret) {
+ case NESTEDHVM_VMEXIT_FATALERROR:
+ gdprintk(XENLOG_ERR, "VMEXIT: fatal error\n");
+ return ret;
+ case NESTEDHVM_VMEXIT_HOST:
+ BUG();
+ return ret;
+ case NESTEDHVM_VMEXIT_ERROR:
+ exitcode = VMEXIT_INVALID;
+ break;
+ default:
+ ASSERT(!nestedhvm_vcpu_in_guestmode(v));
+ break;
+ }
+
+ /* host state has been restored */
+ }
+
+ ASSERT(!nestedhvm_vcpu_in_guestmode(v));
+
+ /* Prepare for running the l1 guest. Make the actual
+ * modifications to the virtual VMCB/VMCS.
+ */
+ rc = nhvm_vcpu_vmexit(v, regs, exitcode);
+
+ nv->nv_vmswitch_in_progress = 0;
+
+ if (rc)
+ return NESTEDHVM_VMEXIT_FATALERROR;
+
+ return NESTEDHVM_VMEXIT_DONE;
+}
+
+/* VCPU switch */
+asmlinkage void nsvm_vcpu_switch(struct cpu_user_regs *regs)
+{
+ int ret;
+ struct vcpu *v = current;
+ struct nestedvcpu *nv;
+ struct nestedsvm *svm;
+
+ if (!nestedhvm_enabled(v->domain))
+ return;
+
+ nv = &vcpu_nestedhvm(v);
+ svm = &vcpu_nestedsvm(v);
+
+ if (nv->nv_vmexit_pending) {
+ vmexit:
+ nestedsvm_vcpu_vmexit(v, regs, svm->ns_vmexit.exitcode);
+ nv->nv_vmexit_pending = 0;
+ nv->nv_vmentry_pending = 0;
+ return;
+ }
+ if (nv->nv_vmentry_pending) {
+ ASSERT(!nv->nv_vmexit_pending);
+ ret = nsvm_vcpu_vmrun(v, regs);
+ if (ret < 0)
+ goto vmexit;
+ nv->nv_vmentry_pending = 0;
+ return;
+ }
+}
+
+
diff -r c8531969c8eb -r 70978f4bf445 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -49,6 +49,9 @@
#include <asm/hvm/svm/vmcb.h>
#include <asm/hvm/svm/emulate.h>
#include <asm/hvm/svm/intr.h>
+#include <asm/hvm/svm/svmdebug.h>
+#include <asm/hvm/svm/nestedsvm.h>
+#include <asm/hvm/nestedhvm.h>
#include <asm/x86_emulate.h>
#include <public/sched.h>
#include <asm/hvm/vpt.h>
@@ -106,6 +109,44 @@ static void svm_cpu_down(void)
write_efer(read_efer() & ~EFER_SVME);
}
+unsigned long *
+svm_msrbit(unsigned long *msr_bitmap, uint32_t msr)
+{
+ unsigned long *msr_bit = NULL;
+
+ /*
+ * See AMD64 Programmers Manual, Vol 2, Section 15.10 (MSR-Bitmap Address).
+ */
+ if ( msr <= 0x1fff )
+ msr_bit = msr_bitmap + 0x0000 / BYTES_PER_LONG;
+ else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )
+ msr_bit = msr_bitmap + 0x0800 / BYTES_PER_LONG;
+ else if ( (msr >= 0xc0010000) && (msr <= 0xc0011fff) )
+ msr_bit = msr_bitmap + 0x1000 / BYTES_PER_LONG;
+
+ return msr_bit;
+}
+
+void svm_intercept_msr(struct vcpu *v, uint32_t msr, int enable)
+{
+ unsigned long *msr_bit;
+
+ msr_bit = svm_msrbit(v->arch.hvm_svm.msrpm, msr);
+ BUG_ON(msr_bit == NULL);
+ msr &= 0x1fff;
+
+ if ( enable )
+ {
+ __set_bit(msr * 2, msr_bit);
+ __set_bit(msr * 2 + 1, msr_bit);
+ }
+ else
+ {
+ __clear_bit(msr * 2, msr_bit);
+ __clear_bit(msr * 2 + 1, msr_bit);
+ }
+}
+
static void svm_save_dr(struct vcpu *v)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
@@ -295,7 +336,7 @@ static int svm_load_vmcb_ctxt(struct vcp
{
svm_load_cpu_state(v, ctxt);
if (svm_vmcb_restore(v, ctxt)) {
- printk("svm_vmcb restore failed!\n");
+ gdprintk(XENLOG_ERR, "svm_vmcb restore failed!\n");
domain_crash(v->domain);
return -EINVAL;
}
@@ -690,9 +731,13 @@ static void svm_do_resume(struct vcpu *v
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
bool_t debug_state = v->domain->debugger_attached;
- vintr_t intr;
+ bool_t vcpu_guestmode = 0;
- if ( unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
+ if ( nestedhvm_enabled(v->domain) && nestedhvm_vcpu_in_guestmode(v) )
+ vcpu_guestmode = 1;
+
+ if ( !vcpu_guestmode &&
+ unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
{
uint32_t intercepts = vmcb_get_exception_intercepts(vmcb);
uint32_t mask = (1U << TRAP_debug) | (1U << TRAP_int3);
@@ -710,13 +755,19 @@ static void svm_do_resume(struct vcpu *v
hvm_asid_flush_vcpu(v);
}
- /* Reflect the vlapic's TPR in the hardware vtpr */
- intr = vmcb_get_vintr(vmcb);
- intr.fields.tpr =
- (vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0xFF) >> 4;
- vmcb_set_vintr(vmcb, intr);
+ if ( !vcpu_guestmode )
+ {
+ vintr_t intr;
+
+ /* Reflect the vlapic's TPR in the hardware vtpr */
+ intr = vmcb_get_vintr(vmcb);
+ intr.fields.tpr =
+ (vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0xFF) >> 4;
+ vmcb_set_vintr(vmcb, intr);
+ }
hvm_do_resume(v);
+
reset_stack_and_jump(svm_asm_do_resume);
}
@@ -968,8 +1019,8 @@ static void svm_do_nested_pgfault(paddr_
struct {
uint64_t gpa;
uint64_t mfn;
- u32 qualification;
- u32 p2mt;
+ uint32_t qualification;
+ uint32_t p2mt;
} _d;
_d.gpa = gpa;
@@ -991,12 +1042,21 @@ static void svm_do_nested_pgfault(paddr_
static void svm_fpu_dirty_intercept(void)
{
- struct vcpu *curr = current;
- struct vmcb_struct *vmcb = curr->arch.hvm_svm.vmcb;
+ struct vcpu *v = current;
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- svm_fpu_enter(curr);
+ svm_fpu_enter(v);
- if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
+ if ( nestedhvm_enabled(v->domain) && nestedhvm_vcpu_in_guestmode(v) ) {
+ /* Check if guest must make FPU ready for the nested guest */
+ if ( v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS )
+ hvm_inject_exception(TRAP_no_device, HVM_DELIVER_NO_ERROR_CODE, 0);
+ else
+ vmcb_set_cr0(vmcb, vmcb_get_cr0(vmcb) & ~X86_CR0_TS);
+ return;
+ }
+
+ if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
vmcb_set_cr0(vmcb, vmcb_get_cr0(vmcb) & ~X86_CR0_TS);
}
@@ -1010,11 +1070,14 @@ static void svm_cpuid_intercept(
hvm_cpuid(input, eax, ebx, ecx, edx);
- if ( input == 0x80000001 )
- {
+ switch (input) {
+ case 0x80000001:
/* Fix up VLAPIC details. */
if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
__clear_bit(X86_FEATURE_APIC & 31, edx);
+ break;
+ default:
+ break;
}
HVMTRACE_5D (CPUID, input, *eax, *ebx, *ecx, *edx);
@@ -1050,6 +1113,7 @@ static void svm_dr_access(struct vcpu *v
static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
{
+ int ret;
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
@@ -1083,9 +1147,6 @@ static int svm_msr_read_intercept(unsign
*msr_content = 0;
break;
- case MSR_K8_VM_HSAVE_PA:
- goto gpf;
-
case MSR_IA32_DEBUGCTLMSR:
*msr_content = vmcb_get_debugctlmsr(vmcb);
break;
@@ -1118,6 +1179,11 @@ static int svm_msr_read_intercept(unsign
break;
default:
+ ret = nsvm_rdmsr(v, msr, msr_content);
+ if ( ret < 0 )
+ goto gpf;
+ else if ( ret )
+ break;
if ( rdmsr_viridian_regs(msr, msr_content) ||
rdmsr_hypervisor_regs(msr, msr_content) )
@@ -1140,14 +1206,12 @@ static int svm_msr_read_intercept(unsign
static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
{
+ int ret;
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
switch ( msr )
{
- case MSR_K8_VM_HSAVE_PA:
- goto gpf;
-
case MSR_IA32_SYSENTER_CS:
v->arch.hvm_svm.guest_sysenter_cs = msr_content;
break;
@@ -1207,6 +1271,12 @@ static int svm_msr_write_intercept(unsig
break;
default:
+ ret = nsvm_wrmsr(v, msr, msr_content);
+ if ( ret < 0 )
+ goto gpf;
+ else if ( ret )
+ break;
+
if ( wrmsr_viridian_regs(msr, msr_content) )
break;
@@ -1286,6 +1356,96 @@ static void svm_vmexit_do_pause(struct c
do_sched_op_compat(SCHEDOP_yield, 0);
}
+static void
+svm_vmexit_do_vmrun(struct cpu_user_regs *regs,
+ struct vcpu *v, uint64_t vmcbaddr)
+{
+ if (!nestedhvm_enabled(v->domain)) {
+ gdprintk(XENLOG_ERR, "VMRUN: nestedhvm disabled, injecting #UD\n");
+ hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
+ return;
+ }
+
+ if (!nestedsvm_vmcb_map(v, vmcbaddr)) {
+ gdprintk(XENLOG_ERR, "VMRUN: mapping vmcb failed, injecting #UD\n");
+ hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
+ return;
+ }
+
+ vcpu_nestedhvm(v).nv_vmentry_pending = 1;
+ return;
+}
+
+static void
+svm_vmexit_do_vmload(struct vmcb_struct *vmcb,
+ struct cpu_user_regs *regs,
+ struct vcpu *v, uint64_t vmcbaddr)
+{
+ int ret;
+ unsigned int inst_len;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+
+ if ( (inst_len = __get_instruction_length(v, INSTR_VMLOAD)) == 0 )
+ return;
+
+ if (!nestedhvm_enabled(v->domain)) {
+ gdprintk(XENLOG_ERR, "VMLOAD: nestedhvm disabled, injecting #UD\n");
+ ret = TRAP_invalid_op;
+ goto inject;
+ }
+
+ if (!nestedsvm_vmcb_map(v, vmcbaddr)) {
+ gdprintk(XENLOG_ERR, "VMLOAD: mapping vmcb failed, injecting #UD\n");
+ ret = TRAP_invalid_op;
+ goto inject;
+ }
+
+ svm_vmload(nv->nv_vmcx);
+ /* State in L1 VMCB is stale now */
+ v->arch.hvm_svm.vmcb_in_sync = 0;
+
+ __update_guest_eip(regs, inst_len);
+ return;
+
+ inject:
+ hvm_inject_exception(ret, HVM_DELIVER_NO_ERROR_CODE, 0);
+ return;
+}
+
+static void
+svm_vmexit_do_vmsave(struct vmcb_struct *vmcb,
+ struct cpu_user_regs *regs,
+ struct vcpu *v, uint64_t vmcbaddr)
+{
+ int ret;
+ unsigned int inst_len;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+
+ if ( (inst_len = __get_instruction_length(v, INSTR_VMSAVE)) == 0 )
+ return;
+
+ if (!nestedhvm_enabled(v->domain)) {
+ gdprintk(XENLOG_ERR, "VMSAVE: nestedhvm disabled, injecting #UD\n");
+ ret = TRAP_invalid_op;
+ goto inject;
+ }
+
+ if (!nestedsvm_vmcb_map(v, vmcbaddr)) {
+ gdprintk(XENLOG_ERR, "VMSAVE: mapping vmcb failed, injecting #UD\n");
+ ret = TRAP_invalid_op;
+ goto inject;
+ }
+
+ svm_vmsave(nv->nv_vmcx);
+
+ __update_guest_eip(regs, inst_len);
+ return;
+
+ inject:
+ hvm_inject_exception(ret, HVM_DELIVER_NO_ERROR_CODE, 0);
+ return;
+}
+
static void svm_vmexit_ud_intercept(struct cpu_user_regs *regs)
{
struct hvm_emulate_ctxt ctxt;
@@ -1416,22 +1576,38 @@ static struct hvm_function_table __read_
.msr_read_intercept = svm_msr_read_intercept,
.msr_write_intercept = svm_msr_write_intercept,
.invlpg_intercept = svm_invlpg_intercept,
- .set_rdtsc_exiting = svm_set_rdtsc_exiting
+ .set_rdtsc_exiting = svm_set_rdtsc_exiting,
+
+ .nhvm_vcpu_initialise = nsvm_vcpu_initialise,
+ .nhvm_vcpu_destroy = nsvm_vcpu_destroy,
+ .nhvm_vcpu_reset = nsvm_vcpu_reset,
+ .nhvm_vcpu_hostrestore = nsvm_vcpu_hostrestore,
+ .nhvm_vcpu_vmexit = nsvm_vcpu_vmexit_inject,
+ .nhvm_vcpu_vmexit_trap = nsvm_vcpu_vmexit_trap,
+ .nhvm_vcpu_guestcr3 = nsvm_vcpu_guestcr3,
+ .nhvm_vcpu_hostcr3 = nsvm_vcpu_hostcr3,
+ .nhvm_vcpu_asid = nsvm_vcpu_asid,
+ .nhvm_vmcx_guest_intercepts_trap = nsvm_vmcb_guest_intercepts_trap,
+ .nhvm_vmcx_hap_enabled = nsvm_vmcb_hap_enabled,
};
asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
{
- unsigned int exit_reason;
+ uint64_t exit_reason;
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
eventinj_t eventinj;
int inst_len, rc;
vintr_t intr;
+ bool_t vcpu_guestmode = 0;
if ( paging_mode_hap(v->domain) )
v->arch.hvm_vcpu.guest_cr[3] = v->arch.hvm_vcpu.hw_cr[3] =
vmcb_get_cr3(vmcb);
+ if ( nestedhvm_enabled(v->domain) && nestedhvm_vcpu_in_guestmode(v) )
+ vcpu_guestmode = 1;
+
/*
* Before doing anything else, we need to sync up the VLAPIC's TPR with
* SVM's vTPR. It's OK if the guest doesn't touch CR8 (e.g. 32-bit Windows)
@@ -1439,13 +1615,73 @@ asmlinkage void svm_vmexit_handler(struc
* NB. We need to preserve the low bits of the TPR to make checked builds
* of Windows work, even though they don't actually do anything.
*/
- intr = vmcb_get_vintr(vmcb);
- vlapic_set_reg(vcpu_vlapic(v), APIC_TASKPRI,
+ if ( !vcpu_guestmode ) {
+ intr = vmcb_get_vintr(vmcb);
+ vlapic_set_reg(vcpu_vlapic(v), APIC_TASKPRI,
((intr.fields.tpr & 0x0F) << 4) |
(vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0x0F));
+ }
exit_reason = vmcb->exitcode;
+ if ( vcpu_guestmode ) {
+ enum nestedhvm_vmexits nsret;
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+ struct vmcb_struct *ns_vmcb = nv->nv_vmcx;
+ uint64_t exitinfo1, exitinfo2;
+
+ /* Write real exitinfo1 back into virtual vmcb.
+ * nestedsvm_check_intercepts() expects to have the correct
+ * exitinfo1 value there.
+ */
+ exitinfo1 = ns_vmcb->exitinfo1;
+ ns_vmcb->exitinfo1 = vmcb->exitinfo1;
+ nsret = nestedsvm_check_intercepts(v, regs, exit_reason);
+ switch (nsret) {
+ case NESTEDHVM_VMEXIT_CONTINUE:
+ BUG();
+ break;
+ case NESTEDHVM_VMEXIT_HOST:
+ break;
+ case NESTEDHVM_VMEXIT_INJECT:
+ /* Switch vcpu from l2 to l1 guest. We must perform
+ * the switch here to have svm_do_resume() working
+ * as intended.
+ */
+ exitinfo1 = vmcb->exitinfo1;
+ exitinfo2 = vmcb->exitinfo2;
+ nv->nv_vmswitch_in_progress = 1;
+ nsret = nestedsvm_vmexit_n2n1(v, regs);
+ nv->nv_vmswitch_in_progress = 0;
+ switch (nsret) {
+ case NESTEDHVM_VMEXIT_DONE:
+ /* defer VMEXIT injection */
+ nestedsvm_vmexit_defer(v, exit_reason, exitinfo1, exitinfo2);
+ goto out;
+ case NESTEDHVM_VMEXIT_FATALERROR:
+ gdprintk(XENLOG_ERR, "unexpected nestedsvm_vmexit() error\n");
+ goto exit_and_crash;
+
+ default:
+ BUG();
+ case NESTEDHVM_VMEXIT_ERROR:
+ break;
+ }
+ case NESTEDHVM_VMEXIT_ERROR:
+ gdprintk(XENLOG_ERR,
+ "nestedsvm_check_intercepts() returned NESTEDHVM_VMEXIT_ERROR\n");
+ goto out;
+ case NESTEDHVM_VMEXIT_FATALERROR:
+ gdprintk(XENLOG_ERR,
+ "unexpected nestedsvm_check_intercepts() error\n");
+ goto exit_and_crash;
+ default:
+ gdprintk(XENLOG_INFO, "nestedsvm_check_intercepts() returned %i\n",
+ nsret);
+ goto exit_and_crash;
+ }
+ }
+
if ( hvm_long_mode_enabled(v) )
HVMTRACE_ND(VMEXIT64, 1/*cycles*/, 3, exit_reason,
(uint32_t)regs->eip, (uint32_t)((uint64_t)regs->eip >> 32),
@@ -1457,7 +1693,7 @@ asmlinkage void svm_vmexit_handler(struc
if ( unlikely(exit_reason == VMEXIT_INVALID) )
{
- svm_dump_vmcb(__func__, vmcb);
+ svm_vmcb_dump(__func__, vmcb);
goto exit_and_crash;
}
@@ -1618,6 +1854,7 @@ asmlinkage void svm_vmexit_handler(struc
case VMEXIT_VMMCALL:
if ( (inst_len = __get_instruction_length(v, INSTR_VMCALL)) == 0 )
break;
+ BUG_ON(vcpu_guestmode);
HVMTRACE_1D(VMMCALL, regs->eax);
rc = hvm_do_hypercall(regs);
if ( rc != HVM_HCALL_preempted )
@@ -1650,9 +1887,18 @@ asmlinkage void svm_vmexit_handler(struc
case VMEXIT_MONITOR:
case VMEXIT_MWAIT:
+ hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
+ break;
+
case VMEXIT_VMRUN:
+ svm_vmexit_do_vmrun(regs, v, regs->eax);
+ break;
case VMEXIT_VMLOAD:
+ svm_vmexit_do_vmload(vmcb, regs, v, regs->eax);
+ break;
case VMEXIT_VMSAVE:
+ svm_vmexit_do_vmsave(vmcb, regs, v, regs->eax);
+ break;
case VMEXIT_STGI:
case VMEXIT_CLGI:
case VMEXIT_SKINIT:
@@ -1696,7 +1942,7 @@ asmlinkage void svm_vmexit_handler(struc
default:
exit_and_crash:
- gdprintk(XENLOG_ERR, "unexpected VMEXIT: exit reason = 0x%x, "
+ gdprintk(XENLOG_ERR, "unexpected VMEXIT: exit reason = 0x%"PRIx64", "
"exitinfo1 = %"PRIx64", exitinfo2 = %"PRIx64"\n",
exit_reason,
(u64)vmcb->exitinfo1, (u64)vmcb->exitinfo2);
@@ -1704,6 +1950,11 @@ asmlinkage void svm_vmexit_handler(struc
break;
}
+ out:
+ if ( vcpu_guestmode )
+ /* Don't clobber TPR of the nested guest. */
+ return;
+
/* The exit may have updated the TPR: reflect this in the hardware vtpr */
intr = vmcb_get_vintr(vmcb);
intr.fields.tpr =
diff -r c8531969c8eb -r 70978f4bf445 xen/arch/x86/hvm/svm/svmdebug.c
--- /dev/null
+++ b/xen/arch/x86/hvm/svm/svmdebug.c
@@ -0,0 +1,191 @@
+/*
+ * svmdebug.c: debug functions
+ * Copyright (c) 2010, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/msr-index.h>
+#include <asm/hvm/svm/svmdebug.h>
+
+static void svm_dump_sel(const char *name, svm_segment_register_t *s)
+{
+ printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
+ name, s->sel, s->attr.bytes, s->limit,
+ (unsigned long long)s->base);
+}
+
+/* This function can directly access fields which are covered by clean bits. */
+void svm_vmcb_dump(const char *from, struct vmcb_struct *vmcb)
+{
+ printk("Dumping guest's current state at %s...\n", from);
+ printk("Size of VMCB = %d, paddr = 0x%016lx, vaddr = %p\n",
+ (int) sizeof(struct vmcb_struct), virt_to_maddr(vmcb), vmcb);
+
+ printk("cr_intercepts = 0x%08x dr_intercepts = 0x%08x "
+ "exception_intercepts = 0x%08x\n",
+ vmcb->_cr_intercepts, vmcb->_dr_intercepts,
+ vmcb->_exception_intercepts);
+ printk("general1_intercepts = 0x%08x general2_intercepts = 0x%08x\n",
+ vmcb->_general1_intercepts, vmcb->_general2_intercepts);
+ printk("iopm_base_pa = 0x%016llx msrpm_base_pa = 0x%016llx tsc_offset = "
+ "0x%016llx\n",
+ (unsigned long long)vmcb->_iopm_base_pa,
+ (unsigned long long)vmcb->_msrpm_base_pa,
+ (unsigned long long)vmcb->_tsc_offset);
+ printk("tlb_control = 0x%08x vintr = 0x%016llx interrupt_shadow = "
+ "0x%016llx\n", vmcb->tlb_control,
+ (unsigned long long)vmcb->_vintr.bytes,
+ (unsigned long long)vmcb->interrupt_shadow);
+ printk("exitcode = 0x%016llx exitintinfo = 0x%016llx\n",
+ (unsigned long long)vmcb->exitcode,
+ (unsigned long long)vmcb->exitintinfo.bytes);
+ printk("exitinfo1 = 0x%016llx exitinfo2 = 0x%016llx \n",
+ (unsigned long long)vmcb->exitinfo1,
+ (unsigned long long)vmcb->exitinfo2);
+ printk("np_enable = 0x%016llx guest_asid = 0x%03x\n",
+ (unsigned long long)vmcb->_np_enable, vmcb->_guest_asid);
+ printk("cpl = %d efer = 0x%016llx star = 0x%016llx lstar = 0x%016llx\n",
+ vmcb->_cpl, (unsigned long long)vmcb->_efer,
+ (unsigned long long)vmcb->star, (unsigned long long)vmcb->lstar);
+ printk("CR0 = 0x%016llx CR2 = 0x%016llx\n",
+ (unsigned long long)vmcb->_cr0, (unsigned long long)vmcb->_cr2);
+ printk("CR3 = 0x%016llx CR4 = 0x%016llx\n",
+ (unsigned long long)vmcb->_cr3, (unsigned long long)vmcb->_cr4);
+ printk("RSP = 0x%016llx RIP = 0x%016llx\n",
+ (unsigned long long)vmcb->rsp, (unsigned long long)vmcb->rip);
+ printk("RAX = 0x%016llx RFLAGS=0x%016llx\n",
+ (unsigned long long)vmcb->rax, (unsigned long long)vmcb->rflags);
+ printk("DR6 = 0x%016llx, DR7 = 0x%016llx\n",
+ (unsigned long long)vmcb->_dr6, (unsigned long long)vmcb->_dr7);
+ printk("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
+ (unsigned long long)vmcb->cstar,
+ (unsigned long long)vmcb->sfmask);
+ printk("KernGSBase = 0x%016llx PAT = 0x%016llx \n",
+ (unsigned long long)vmcb->kerngsbase,
+ (unsigned long long)vmcb->_g_pat);
+ printk("H_CR3 = 0x%016llx CleanBits = 0x%08x\n",
+ (unsigned long long)vmcb->_h_cr3, vmcb->cleanbits.bytes);
+
+ /* print out all the selectors */
+ svm_dump_sel("CS", &vmcb->cs);
+ svm_dump_sel("DS", &vmcb->ds);
+ svm_dump_sel("SS", &vmcb->ss);
+ svm_dump_sel("ES", &vmcb->es);
+ svm_dump_sel("FS", &vmcb->fs);
+ svm_dump_sel("GS", &vmcb->gs);
+ svm_dump_sel("GDTR", &vmcb->gdtr);
+ svm_dump_sel("LDTR", &vmcb->ldtr);
+ svm_dump_sel("IDTR", &vmcb->idtr);
+ svm_dump_sel("TR", &vmcb->tr);
+}
+
+bool_t
+svm_vmcb_isvalid(const char *from, struct vmcb_struct *vmcb,
+ bool_t verbose)
+{
+ bool_t ret = 0; /* ok */
+
+#define PRINTF(...) \
+ if (verbose) { ret = 1; printk("%s: ", from); printk(__VA_ARGS__); \
+ } else return 1;
+
+ if ((vmcb->_efer & EFER_SVME) == 0) {
+ PRINTF("EFER: SVME bit not set (0x%"PRIx64")\n", vmcb->_efer);
+ }
+
+ if ((vmcb->_cr0 & X86_CR0_CD) == 0 && (vmcb->_cr0 & X86_CR0_NW) != 0) {
+ PRINTF("CR0: CD bit is zero and NW bit set (0x%"PRIx64")\n",
+ vmcb->_cr0);
+ }
+
+ if ((vmcb->_cr0 >> 32U) != 0) {
+ PRINTF("CR0: bits [63:32] are not zero (0x%"PRIx64")\n",
+ vmcb->_cr0);
+ }
+
+ if ((vmcb->_cr3 & 0x7) != 0) {
+ PRINTF("CR3: MBZ bits are set (0x%"PRIx64")\n", vmcb->_cr3);
+ }
+ if ((vmcb->_efer & EFER_LMA) && (vmcb->_cr3 & 0xfe) != 0) {
+ PRINTF("CR3: MBZ bits are set (0x%"PRIx64")\n", vmcb->_cr3);
+ }
+
+ if ((vmcb->_cr4 >> 11U) != 0) {
+ PRINTF("CR4: bits [63:11] are not zero (0x%"PRIx64")\n",
+ vmcb->_cr4);
+ }
+
+ if ((vmcb->_dr6 >> 32U) != 0) {
+ PRINTF("DR6: bits [63:32] are not zero (0x%"PRIx64")\n",
+ vmcb->_dr6);
+ }
+
+ if ((vmcb->_dr7 >> 32U) != 0) {
+ PRINTF("DR7: bits [63:32] are not zero (0x%"PRIx64")\n",
+ vmcb->_dr7);
+ }
+
+ if ((vmcb->_efer >> 15U) != 0) {
+ PRINTF("EFER: bits [63:15] are not zero (0x%"PRIx64")\n",
+ vmcb->_efer);
+ }
+
+ if ((vmcb->_efer & EFER_LME) != 0 && ((vmcb->_cr0 & X86_CR0_PG) != 0)) {
+ if ((vmcb->_cr4 & X86_CR4_PAE) == 0) {
+ PRINTF("EFER_LME and CR0.PG are both set and CR4.PAE is zero.\n");
+ }
+ if ((vmcb->_cr0 & X86_CR0_PE) == 0) {
+ PRINTF("EFER_LME and CR0.PG are both set and CR0.PE is zero.\n");
+ }
+ }
+
+ if ((vmcb->_efer & EFER_LME) != 0
+ && (vmcb->_cr0 & X86_CR0_PG) != 0
+ && (vmcb->_cr4 & X86_CR4_PAE) != 0
+ && (vmcb->cs.attr.fields.l != 0)
+ && (vmcb->cs.attr.fields.db != 0))
+ {
+ PRINTF("EFER_LME, CR0.PG, CR4.PAE, CS.L and CS.D are all non-zero.\n");
+ }
+
+ if ((vmcb->_general2_intercepts & GENERAL2_INTERCEPT_VMRUN) == 0) {
+ PRINTF("GENERAL2_INTERCEPT: VMRUN intercept bit is clear (0x%"PRIx32")\n",
+ vmcb->_general2_intercepts);
+ }
+
+ if (vmcb->eventinj.fields.resvd1 != 0) {
+ PRINTF("eventinj: MBZ bits are set (0x%"PRIx64")\n",
+ vmcb->eventinj.bytes);
+ }
+
+ if (vmcb->_np_enable && vmcb->_h_cr3 == 0) {
+ PRINTF("nested paging enabled but host cr3 is 0\n");
+ }
+
+#undef PRINTF
+ return ret;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r c8531969c8eb -r 70978f4bf445 xen/arch/x86/hvm/svm/vmcb.c
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -33,6 +33,7 @@
#include <asm/hvm/svm/svm.h>
#include <asm/hvm/svm/intr.h>
#include <asm/hvm/svm/asid.h>
+#include <asm/hvm/svm/svmdebug.h>
#include <xen/event.h>
#include <xen/kernel.h>
#include <xen/domain_page.h>
@@ -40,9 +41,6 @@
extern int svm_dbg_on;
-#define IOPM_SIZE (12 * 1024)
-#define MSRPM_SIZE (8 * 1024)
-
struct vmcb_struct *alloc_vmcb(void)
{
struct vmcb_struct *vmcb;
@@ -78,37 +76,6 @@ struct host_save_area *alloc_host_save_a
return hsa;
}
-void svm_intercept_msr(struct vcpu *v, uint32_t msr, int enable)
-{
- unsigned long *msr_bitmap = v->arch.hvm_svm.msrpm;
- unsigned long *msr_bit = NULL;
-
- /*
- * See AMD64 Programmers Manual, Vol 2, Section 15.10 (MSR-Bitmap Address).
- */
- if ( msr <= 0x1fff )
- msr_bit = msr_bitmap + 0x0000 / BYTES_PER_LONG;
- else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )
- msr_bit = msr_bitmap + 0x0800 / BYTES_PER_LONG;
- else if ( (msr >= 0xc0010000) && (msr <= 0xc0011fff) )
- msr_bit = msr_bitmap + 0x1000 / BYTES_PER_LONG;
-
- BUG_ON(msr_bit == NULL);
-
- msr &= 0x1fff;
-
- if ( enable )
- {
- __set_bit(msr * 2, msr_bit);
- __set_bit(msr * 2 + 1, msr_bit);
- }
- else
- {
- __clear_bit(msr * 2, msr_bit);
- __clear_bit(msr * 2 + 1, msr_bit);
- }
-}
-
/* This function can directly access fields which are covered by clean bits. */
static int construct_vmcb(struct vcpu *v)
{
@@ -257,7 +224,7 @@ static int construct_vmcb(struct vcpu *v
if ( cpu_has_pause_filter )
{
- vmcb->_pause_filter_count = 3000;
+ vmcb->_pause_filter_count = SVM_PAUSEFILTER_INIT;
vmcb->_general1_intercepts |= GENERAL1_INTERCEPT_PAUSE;
}
@@ -307,78 +274,6 @@ void svm_destroy_vmcb(struct vcpu *v)
arch_svm->vmcb = NULL;
}
-static void svm_dump_sel(char *name, svm_segment_register_t *s)
-{
- printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
- name, s->sel, s->attr.bytes, s->limit,
- (unsigned long long)s->base);
-}
-
-/* This function can directly access fields which are covered by clean bits. */
-void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb)
-{
- printk("Dumping guest's current state at %s...\n", from);
- printk("Size of VMCB = %d, paddr = 0x%016lx, vaddr = %p\n",
- (int) sizeof(struct vmcb_struct), virt_to_maddr(vmcb), vmcb);
-
- printk("cr_intercepts = 0x%08x dr_intercepts = 0x%08x "
- "exception_intercepts = 0x%08x\n",
- vmcb->_cr_intercepts, vmcb->_dr_intercepts,
- vmcb->_exception_intercepts);
- printk("general1_intercepts = 0x%08x general2_intercepts = 0x%08x\n",
- vmcb->_general1_intercepts, vmcb->_general2_intercepts);
- printk("iopm_base_pa = 0x%016llx msrpm_base_pa = 0x%016llx tsc_offset = "
- "0x%016llx\n",
- (unsigned long long)vmcb->_iopm_base_pa,
- (unsigned long long)vmcb->_msrpm_base_pa,
- (unsigned long long)vmcb->_tsc_offset);
- printk("tlb_control = 0x%08x vintr = 0x%016llx interrupt_shadow = "
- "0x%016llx\n", vmcb->tlb_control,
- (unsigned long long)vmcb->_vintr.bytes,
- (unsigned long long)vmcb->interrupt_shadow);
- printk("exitcode = 0x%016llx exitintinfo = 0x%016llx\n",
- (unsigned long long)vmcb->exitcode,
- (unsigned long long)vmcb->exitintinfo.bytes);
- printk("exitinfo1 = 0x%016llx exitinfo2 = 0x%016llx \n",
- (unsigned long long)vmcb->exitinfo1,
- (unsigned long long)vmcb->exitinfo2);
- printk("np_enable = 0x%016llx guest_asid = 0x%03x\n",
- (unsigned long long)vmcb->_np_enable, vmcb->_guest_asid);
- printk("cpl = %d efer = 0x%016llx star = 0x%016llx lstar = 0x%016llx\n",
- vmcb->_cpl, (unsigned long long)vmcb->_efer,
- (unsigned long long)vmcb->star, (unsigned long long)vmcb->lstar);
- printk("CR0 = 0x%016llx CR2 = 0x%016llx\n",
- (unsigned long long)vmcb->_cr0, (unsigned long long)vmcb->_cr2);
- printk("CR3 = 0x%016llx CR4 = 0x%016llx\n",
- (unsigned long long)vmcb->_cr3, (unsigned long long)vmcb->_cr4);
- printk("RSP = 0x%016llx RIP = 0x%016llx\n",
- (unsigned long long)vmcb->rsp, (unsigned long long)vmcb->rip);
- printk("RAX = 0x%016llx RFLAGS=0x%016llx\n",
- (unsigned long long)vmcb->rax, (unsigned long long)vmcb->rflags);
- printk("DR6 = 0x%016llx, DR7 = 0x%016llx\n",
- (unsigned long long)vmcb->_dr6, (unsigned long long)vmcb->_dr7);
- printk("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
- (unsigned long long)vmcb->cstar,
- (unsigned long long)vmcb->sfmask);
- printk("KernGSBase = 0x%016llx PAT = 0x%016llx \n",
- (unsigned long long)vmcb->kerngsbase,
- (unsigned long long)vmcb->_g_pat);
- printk("H_CR3 = 0x%016llx CleanBits = 0x%08x\n",
- (unsigned long long)vmcb->_h_cr3, vmcb->cleanbits.bytes);
-
- /* print out all the selectors */
- svm_dump_sel("CS", &vmcb->cs);
- svm_dump_sel("DS", &vmcb->ds);
- svm_dump_sel("SS", &vmcb->ss);
- svm_dump_sel("ES", &vmcb->es);
- svm_dump_sel("FS", &vmcb->fs);
- svm_dump_sel("GS", &vmcb->gs);
- svm_dump_sel("GDTR", &vmcb->gdtr);
- svm_dump_sel("LDTR", &vmcb->ldtr);
- svm_dump_sel("IDTR", &vmcb->idtr);
- svm_dump_sel("TR", &vmcb->tr);
-}
-
static void vmcb_dump(unsigned char ch)
{
struct domain *d;
@@ -396,7 +291,7 @@ static void vmcb_dump(unsigned char ch)
for_each_vcpu ( d, v )
{
printk("\tVCPU %d\n", v->vcpu_id);
- svm_dump_vmcb("key_handler", v->arch.hvm_svm.vmcb);
+ svm_vmcb_dump("key_handler", v->arch.hvm_svm.vmcb);
}
}
diff -r c8531969c8eb -r 70978f4bf445 xen/include/asm-x86/hvm/svm/emulate.h
--- a/xen/include/asm-x86/hvm/svm/emulate.h
+++ b/xen/include/asm-x86/hvm/svm/emulate.h
@@ -33,6 +33,11 @@ enum instruction_index {
INSTR_RDTSC,
INSTR_PAUSE,
INSTR_XSETBV,
+ INSTR_VMRUN,
+ INSTR_VMLOAD,
+ INSTR_VMSAVE,
+ INSTR_STGI,
+ INSTR_CLGI,
INSTR_MAX_COUNT /* Must be last - Number of instructions supported */
};
diff -r c8531969c8eb -r 70978f4bf445 xen/include/asm-x86/hvm/svm/nestedsvm.h
--- /dev/null
+++ b/xen/include/asm-x86/hvm/svm/nestedsvm.h
@@ -0,0 +1,126 @@
+/*
+ * nestedsvm.h: Nested Virtualization
+ * Copyright (c) 2010, Advanced Micro Devices, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+#ifndef __ASM_X86_HVM_SVM_NESTEDSVM_H__
+#define __ASM_X86_HVM_SVM_NESTEDSVM_H__
+
+#include <asm/config.h>
+#include <asm/hvm/hvm.h>
+#include <asm/hvm/svm/vmcb.h>
+
+struct nestedsvm {
+ uint64_t ns_msr_hsavepa; /* MSR HSAVE_PA value */
+
+ /* Cached real intercepts of the nested guest */
+ uint32_t ns_cr_intercepts;
+ uint32_t ns_dr_intercepts;
+ uint32_t ns_exception_intercepts;
+ uint32_t ns_general1_intercepts;
+ uint32_t ns_general2_intercepts;
+
+ /* Cached real lbr of the nested guest */
+ lbrctrl_t ns_lbr_control;
+
+ /* Cached real MSR permission bitmaps of the nested guest */
+ unsigned long *ns_cached_msrpm;
+ /* Merged MSR permission bitmap */
+ unsigned long *ns_merged_msrpm;
+
+ /* guest physical address of virtual io permission map */
+ paddr_t ns_iomap_pa, ns_oiomap_pa;
+ /* Shadow io permission map */
+ unsigned long *ns_iomap;
+
+ void *ns_hostsave;
+
+ /* Cache guest cr3/host cr3 the guest sets up for the nested guest.
+ * Used by Shadow-on-Shadow and Nested-on-Nested.
+ * ns_vmcb_guestcr3: in l2 guest physical address space and points to
+ * the l2 guest page table
+ * ns_vmcb_hostcr3: in l1 guest physical address space and points to
+ * the l1 guest nested page table
+ */
+ uint64_t ns_vmcb_guestcr3, ns_vmcb_hostcr3;
+ uint32_t ns_guest_asid;
+
+ bool_t ns_hap_enabled;
+
+ /* Only meaningful when vmexit_pending flag is set */
+ struct {
+ uint64_t exitcode; /* native exitcode to inject into l1 guest */
+ uint64_t exitinfo1; /* additional information to the exitcode */
+ uint64_t exitinfo2; /* additional information to the exitcode */
+ } ns_vmexit;
+ union {
+ uint32_t bytes;
+ struct {
+ uint32_t rflagsif: 1;
+ uint32_t vintrmask: 1;
+ uint32_t reserved: 30;
+ } fields;
+ } ns_hostflags;
+};
+
+#define vcpu_nestedsvm(v) (vcpu_nestedhvm(v).u.nsvm)
+
+/* True when l1 guest enabled SVM in EFER */
+#define hvm_svm_enabled(v) \
+ (!!((v)->arch.hvm_vcpu.guest_efer & EFER_SVME))
+
+int nestedsvm_vmcb_map(struct vcpu *v, uint64_t vmcbaddr);
+void nestedsvm_vmexit_defer(struct vcpu *v,
+ uint64_t exitcode, uint64_t exitinfo1, uint64_t exitinfo2);
+enum nestedhvm_vmexits
+nestedsvm_vmexit_n2n1(struct vcpu *v, struct cpu_user_regs *regs);
+enum nestedhvm_vmexits
+nestedsvm_check_intercepts(struct vcpu *v, struct cpu_user_regs *regs,
+ uint64_t exitcode);
+
+/* Interface methods */
+int nsvm_vcpu_destroy(struct vcpu *v);
+int nsvm_vcpu_initialise(struct vcpu *v);
+int nsvm_vcpu_reset(struct vcpu *v);
+int nsvm_vcpu_hostrestore(struct vcpu *v, struct cpu_user_regs *regs);
+int nsvm_vcpu_vmrun(struct vcpu *v, struct cpu_user_regs *regs);
+int nsvm_vcpu_vmexit_inject(struct vcpu *v, struct cpu_user_regs *regs,
+ uint64_t exitcode);
+int nsvm_vcpu_vmexit_trap(struct vcpu *v, unsigned int trapnr,
+ int errcode, unsigned long cr2);
+uint64_t nsvm_vcpu_guestcr3(struct vcpu *v);
+uint64_t nsvm_vcpu_hostcr3(struct vcpu *v);
+uint32_t nsvm_vcpu_asid(struct vcpu *v);
+int nsvm_vmcb_guest_intercepts_exitcode(struct vcpu *v,
+ struct cpu_user_regs *regs, uint64_t exitcode);
+int nsvm_vmcb_guest_intercepts_trap(struct vcpu *v, unsigned int trapnr);
+bool_t nsvm_vmcb_hap_enabled(struct vcpu *v);
+
+/* MSRs */
+int nsvm_rdmsr(struct vcpu *v, unsigned int msr, uint64_t *msr_content);
+int nsvm_wrmsr(struct vcpu *v, unsigned int msr, uint64_t msr_content);
+
+#endif /* ASM_X86_HVM_SVM_NESTEDSVM_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r c8531969c8eb -r 70978f4bf445 xen/include/asm-x86/hvm/svm/svm.h
--- a/xen/include/asm-x86/hvm/svm/svm.h
+++ b/xen/include/asm-x86/hvm/svm/svm.h
@@ -29,8 +29,6 @@
#include <asm/i387.h>
#include <asm/hvm/vpmu.h>
-void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb);
-
#define SVM_REG_EAX (0)
#define SVM_REG_ECX (1)
#define SVM_REG_EDX (2)
@@ -62,6 +60,8 @@ static inline void svm_vmsave(void *vmcb
: : "a" (__pa(vmcb)) : "memory" );
}
+unsigned long *svm_msrbit(unsigned long *msr_bitmap, uint32_t msr);
+
extern u32 svm_feature_flags;
#define SVM_FEATURE_NPT 0
@@ -78,4 +78,6 @@ extern u32 svm_feature_flags;
#define cpu_has_svm_cleanbits test_bit(SVM_FEATURE_CLEAN, &svm_feature_flags)
#define cpu_has_pause_filter test_bit(SVM_FEATURE_PAUSEF, &svm_feature_flags)
+#define SVM_PAUSEFILTER_INIT 3000
+
#endif /* __ASM_X86_HVM_SVM_H__ */
diff -r c8531969c8eb -r 70978f4bf445 xen/include/asm-x86/hvm/svm/svmdebug.h
--- /dev/null
+++ b/xen/include/asm-x86/hvm/svm/svmdebug.h
@@ -0,0 +1,30 @@
+/*
+ * svmdebug.h: SVM related debug defintions
+ * Copyright (c) 2010, AMD Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#ifndef __ASM_X86_HVM_SVM_SVMDEBUG_H__
+#define __ASM_X86_HVM_SVM_SVMDEBUG_H__
+
+#include <asm/types.h>
+#include <asm/hvm/svm/vmcb.h>
+
+void svm_vmcb_dump(const char *from, struct vmcb_struct *vmcb);
+bool_t svm_vmcb_isvalid(const char *from, struct vmcb_struct *vmcb,
+ bool_t verbose);
+
+#endif /* __ASM_X86_HVM_SVM_SVMDEBUG_H__ */
diff -r c8531969c8eb -r 70978f4bf445 xen/include/asm-x86/hvm/svm/vmcb.h
--- a/xen/include/asm-x86/hvm/svm/vmcb.h
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h
@@ -398,6 +398,9 @@ typedef union
} fields;
} __attribute__ ((packed)) vmcbcleanbits_t;
+#define IOPM_SIZE (12 * 1024)
+#define MSRPM_SIZE (8 * 1024)
+
struct vmcb_struct {
u32 _cr_intercepts; /* offset 0x00 - cleanbit 0 */
u32 _dr_intercepts; /* offset 0x04 - cleanbit 0 */
diff -r c8531969c8eb -r 70978f4bf445 xen/include/asm-x86/hvm/vcpu.h
--- a/xen/include/asm-x86/hvm/vcpu.h
+++ b/xen/include/asm-x86/hvm/vcpu.h
@@ -25,6 +25,7 @@
#include <asm/hvm/vlapic.h>
#include <asm/hvm/vmx/vmcs.h>
#include <asm/hvm/svm/vmcb.h>
+#include <asm/hvm/svm/nestedsvm.h>
#include <asm/mtrr.h>
enum hvm_io_state {
@@ -45,6 +46,7 @@ struct nestedvcpu {
/* SVM/VMX arch specific */
union {
+ struct nestedsvm nsvm;
} u;
bool_t nv_flushp2m; /* True, when p2m table must be flushed */
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
next reply other threads:[~2010-12-20 16:10 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-20 16:10 Christoph Egger [this message]
-- strict thread matches above, loose matches on Subject: below --
2011-03-09 14:25 [PATCH 09/12] Nested Virtualization: svm specific implementation Christoph Egger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201012201710.17688.Christoph.Egger@amd.com \
--to=christoph.egger@amd.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.