All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 05/14] Nested Virtualization: core
@ 2010-08-05 15:01 Christoph Egger
  2010-08-09 12:38 ` Tim Deegan
  0 siblings, 1 reply; 3+ messages in thread
From: Christoph Egger @ 2010-08-05 15:01 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 322 bytes --]


Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>

-- 
---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_nh05_core.diff --]
[-- Type: text/x-diff, Size: 23860 bytes --]

# HG changeset patch
# User cegger
# Date 1280925500 -7200
Nested Virtualization core implementation

diff -r c19b4e3959c5 -r 917f9eb07fc3 xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile
+++ b/xen/arch/x86/hvm/Makefile
@@ -10,6 +10,7 @@ obj-y += intercept.o
 obj-y += io.o
 obj-y += irq.o
 obj-y += mtrr.o
+obj-y += nestedhvm.o
 obj-y += pmtimer.o
 obj-y += quirks.o
 obj-y += rtc.o
diff -r c19b4e3959c5 -r 917f9eb07fc3 xen/arch/x86/hvm/nestedhvm.c
--- /dev/null
+++ b/xen/arch/x86/hvm/nestedhvm.c
@@ -0,0 +1,673 @@
+/*
+ * Nested HVM
+ * Copyright (c) 2010, Advanced Micro Devices, Inc.
+ * Author: Christoph Egger <Christoph.Egger@amd.com>
+ *
+ * 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/msr.h>
+#include <asm/hvm/support.h>	/* for HVM_DELIVER_NO_ERROR_CODE */
+#include <asm/hvm/hvm.h>
+#include <asm/hvm/nestedhvm.h>
+#include <asm/event.h>  /* for local_event_delivery_(en|dis)able */
+#include <asm/paging.h> /* for paging_mode_hap() */
+
+/* Nested HVM on/off per domain */
+bool_t
+nestedhvm_enabled(struct domain *d)
+{
+	bool_t enabled;
+
+	enabled = !!(d->arch.hvm_domain.params[HVM_PARAM_NESTEDHVM]);
+	/* sanity check */
+	BUG_ON(enabled && !is_hvm_domain(d));
+
+	if (!is_hvm_domain(d))
+		return 0;
+
+	return enabled;
+}
+
+/* Nested VM */
+bool_t
+nestedhvm_vmaddr_isvalid(struct nestedhvm *hvm, uint64_t addr)
+{
+	/* Maximum valid physical address.
+	 * See AMD BKDG for HSAVE_PA MSR.
+	 */
+	if (addr > hvm->nh_vmmaxaddr)
+		return 0;
+	if ((addr & ~PAGE_MASK) != 0)
+		return 0;
+	return 1;
+}
+
+/* Get VM from the guest for the nested guest. */
+enum hvm_copy_result
+nestedhvm_vm_fromguest(struct nestedhvm *hvm, uint64_t vmaddr)
+{
+	return hvm_copy_from_guest_phys(hvm->nh_vm, vmaddr,
+		hvm->nh_vmsize);
+}
+
+/* Put VM into the guest for the nested guest. */
+enum hvm_copy_result
+nestedhvm_vm_toguest(struct nestedhvm *hvm, uint64_t vmaddr)
+{
+	return hvm_copy_to_guest_phys(vmaddr, hvm->nh_vm,
+		hvm->nh_vmsize);
+}
+
+/* Nested VCPU */
+int
+nestedhvm_vcpu_state_validate(struct vcpu *v, uint64_t vmaddr)
+{
+	struct segment_register reg;
+
+	if ( !nestedhvm_enabled(v->domain) )
+		return TRAP_invalid_op;
+
+	if ( !hvm_svm_enabled(v) || hvm_guest_x86_mode(v) < 2 )
+		return TRAP_invalid_op;
+
+	/* if CPL != 0 inject #GP */
+	hvm_get_segment_register(v, x86_seg_ss, &reg);
+	if (reg.attr.fields.dpl != 0)
+		return TRAP_gp_fault;
+
+	if (!nestedhvm_vmaddr_isvalid(&VCPU_NESTEDHVM(v), vmaddr))
+		return TRAP_gp_fault;
+
+	return 0;
+}
+
+bool_t
+nestedhvm_vcpu_in_guestmode(struct vcpu *v)
+{
+	return VCPU_NESTEDHVM(v).nh_guestmode;
+}
+
+void
+nestedhvm_vcpu_reset(struct vcpu *v)
+{
+	struct nestedhvm *nh = &VCPU_NESTEDHVM(v);
+
+	nh->nh_hap_enabled = 0;
+	nh->nh_vmcb_cr3 = 0;
+	nh->nh_vmcb_hcr3 = 0;
+	nh->nh_guest_asid = 0;
+	nh->nh_flushp2m = 0;
+	nh->nh_p2m = NULL;
+
+	hvm_nestedhvm_vcpu_reset(v);
+
+	/* Always on */
+	nestedsvm_vcpu_stgi(v);
+	/* vcpu is in host mode */
+	nestedhvm_vcpu_exit_guestmode(v);
+}
+
+int
+nestedhvm_vcpu_initialise(struct vcpu *v)
+{
+	int rc;
+	struct nestedhvm *hvm = &VCPU_NESTEDHVM(v);
+
+	if (!nestedhvm_enabled(v->domain))
+		return 0;
+
+	memset(hvm, 0x0, sizeof(struct nestedhvm));
+
+	/* initialise hostsave, for example */
+	rc = hvm_nestedhvm_vcpu_initialise(v); 
+	if (rc) {
+		hvm_nestedhvm_vcpu_destroy(v);
+		return rc;
+	}
+
+	nestedhvm_vcpu_reset(v);
+	return 0;
+}
+
+int
+nestedhvm_vcpu_destroy(struct vcpu *v)
+{
+	int ret = 0;
+
+	if (!nestedhvm_enabled(v->domain))
+		return 0;
+
+	if (nestedhvm_vcpu_in_guestmode(v)) {
+		nestedhvm_vcpu_exit_guestmode(v);
+		ret = -EBUSY;
+	}
+
+	/* Enable interrupts or the guest won't see any interrupts
+	 * after nested guest exited.
+	 */
+	nestedsvm_vcpu_stgi(v);
+
+	hvm_nestedhvm_vcpu_destroy(v);
+	return ret;
+}
+
+int
+nestedhvm_vcpu_vmentry(struct vcpu *v, struct cpu_user_regs *regs,
+	uint64_t vmaddr, unsigned int inst_len)
+{
+	int ret;
+	enum nestedhvm_vmexits vmret;
+	enum hvm_copy_result rc;
+	struct nestedhvm *hvm = &VCPU_NESTEDHVM(v);
+	uint64_t exitreason;
+
+	hvm->nh_hostflags.fields.vmentry = 1;
+
+	ret = nestedhvm_vcpu_state_validate(v, vmaddr);
+	if (ret) {
+		gdprintk(XENLOG_ERR,
+			"nestedhvm_vcpu_state_validate failed, injecting 0x%x\n",
+			ret);
+		hvm_inject_exception(ret, HVM_DELIVER_NO_ERROR_CODE, 0);
+		return ret;
+	}
+
+	/* Save vmaddr. Needed for VMEXIT */
+	hvm->nh_vmaddr = vmaddr;
+
+	/* get nested vm */
+	rc = nestedhvm_vm_fromguest(hvm, vmaddr);
+	if (rc) {
+		vmret = NESTEDHVM_VMEXIT_FATALERROR;
+		gdprintk(XENLOG_ERR,
+			"nestedhvm_vm_fromguest failed, injecting #GP\n");
+		hvm_inject_exception(TRAP_gp_fault,
+			HVM_DELIVER_NO_ERROR_CODE, 0);
+		hvm->nh_hostflags.fields.vmentry = 0;
+		return TRAP_gp_fault;
+	}
+
+	ret = hvm_nestedhvm_vcpu_vmentry(v);
+	if (ret) {
+		gdprintk(XENLOG_ERR,
+			"hvm_nestedhvm_vcpu_hostsave failed, injecting #UD\n");
+		hvm_inject_exception(TRAP_invalid_op,
+			HVM_DELIVER_NO_ERROR_CODE, 0);
+		hvm->nh_hostflags.fields.vmentry = 0;
+		return ret;
+	}
+
+	/* save host state */
+	ret = hvm_nestedhvm_vcpu_hostsave(v, inst_len);
+	if (ret) {
+		gdprintk(XENLOG_ERR,
+			"hvm_nestedhvm_vcpu_hostsave failed, injecting #UD\n");
+		hvm_inject_exception(TRAP_invalid_op,
+			HVM_DELIVER_NO_ERROR_CODE, 0);
+		hvm->nh_hostflags.fields.vmentry = 0;
+		return ret;
+	}
+
+	/* Switch vcpu to guest mode.
+	 */
+	nestedhvm_vcpu_enter_guestmode(v);
+
+	/* prepare VM to run nested guest, validate VMCB/VMCS */
+	ret = hvm_nestedhvm_vm_prepare4vmentry(v, regs);
+	if (ret) {
+		exitreason = NESTEDHVM_INTERCEPT_INVALID;
+		goto err;
+	}
+
+	ret = nestedhvm_vm_toguest(hvm, vmaddr);
+	if (ret) {
+		exitreason = NESTEDHVM_INTERCEPT_SHUTDOWN;
+		goto err;
+	}
+
+	nestedsvm_vcpu_stgi(v);
+
+	hvm->nh_hostflags.fields.vmentry = 0;
+	return 0;
+
+err:
+	rc = hvm_nestedhvm_vcpu_hostrestore(v, regs);
+	if (rc)
+		exitreason = NESTEDHVM_INTERCEPT_SHUTDOWN;
+
+	hvm->nh_hostflags.fields.forcevmexit = 1;
+	hvm->nh_forcevmexit.exitcode = exitreason;
+	vmret = nestedhvm_vcpu_vmexit(v, regs, exitreason);
+	hvm->nh_hostflags.fields.forcevmexit = 0;
+	hvm->nh_hostflags.fields.vmentry = 0;
+	switch (vmret) {
+	case NESTEDHVM_VMEXIT_DONE:
+	case NESTEDHVM_VMEXIT_CONTINUE:
+	case NESTEDHVM_VMEXIT_HOST:
+		break;
+	default:
+		hvm_inject_exception(TRAP_gp_fault,
+			HVM_DELIVER_NO_ERROR_CODE, 0);
+		return TRAP_gp_fault;
+	}
+	return 0;
+}
+
+static enum nestedhvm_vmexits
+nestedhvm_vmexit_msr(unsigned long *msr_bitmap, uint32_t msr, bool_t write)
+{
+	bool_t enabled;
+	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;
+
+	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_CONTINUE;
+}
+
+int
+nestedhvm_vcpu_interrupt(struct vcpu *v, const struct hvm_intack intack)
+{
+	uint64_t exitcode = NESTEDHVM_INTERCEPT_INTR;
+	uint64_t exitinfo2 = 0;
+	struct nestedhvm *hvm = &VCPU_NESTEDHVM(v);
+	ASSERT(nestedhvm_vcpu_in_guestmode(v));
+
+	if ( hvm->nh_hostflags.fields.vintrmask )
+		if ( !hvm->nh_hostflags.fields.rflagsif )
+			return NESTEDHVM_INTR_MASKED;
+
+	switch (intack.source) {
+	case hvm_intsrc_pic:
+	case hvm_intsrc_lapic:
+		exitcode = NESTEDHVM_INTERCEPT_INTR;
+		exitinfo2 = intack.vector;
+		break;
+	case hvm_intsrc_nmi:
+		exitcode = NESTEDHVM_INTERCEPT_NMI;
+		exitinfo2 = intack.vector;
+		break;
+	case hvm_intsrc_mce:
+		exitcode = NESTEDHVM_INTERCEPT_MCE;
+		exitinfo2 = intack.vector;
+		break;
+	case hvm_intsrc_none:
+		return NESTEDHVM_INTR_NOTHANDLED;
+	default:
+		BUG();
+	}
+
+	hvm->nh_hostflags.fields.forcevmexit = 1;
+	hvm->nh_forcevmexit.exitcode = exitcode;
+	hvm->nh_forcevmexit.exitinfo1 = intack.source;
+	hvm->nh_forcevmexit.exitinfo2 = exitinfo2;
+	if ( hvm_nestedhvm_vm_intercepted_by_guest(v, exitcode) )
+		return NESTEDHVM_INTR_FORCEVMEXIT;
+
+	hvm->nh_hostflags.fields.forcevmexit = 0;
+	return NESTEDHVM_INTR_NOTINTERCEPTED;
+}
+
+static enum nestedhvm_vmexits
+nestedhvm_vmexit_intercepts(struct vcpu *v, struct cpu_user_regs *regs,
+	uint64_t exitcode)
+{
+	bool_t is_intercepted;
+	struct nestedhvm *hvm = &VCPU_NESTEDHVM(v);
+	uint64_t info1, info2;
+
+	is_intercepted = hvm_nestedhvm_vm_intercepted_by_guest(v, exitcode);
+
+	if (hvm->nh_hostflags.fields.forcevmexit) {
+		if (is_intercepted)
+			return NESTEDHVM_VMEXIT_INJECT;
+		gdprintk(XENLOG_ERR,
+			"forced VMEXIT can't happen as guest can't "
+			"handle the intercept\n");
+		return NESTEDHVM_VMEXIT_FATALERROR;
+	}
+
+	exitcode = hvm_nestedhvm_vm_exitcode_native2generic(v, regs, exitcode,
+						&info1, &info2);
+
+	switch (exitcode) {
+	case NESTEDHVM_INTERCEPT_INVALID:
+		if (is_intercepted)
+			return NESTEDHVM_VMEXIT_INJECT;
+		return NESTEDHVM_VMEXIT_HOST;
+
+	case NESTEDHVM_INTERCEPT_INTR:
+		return NESTEDHVM_VMEXIT_HOST;
+	case NESTEDHVM_INTERCEPT_NMI:
+		return NESTEDHVM_VMEXIT_HOST;
+
+	case NESTEDHVM_INTERCEPT_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 NESTEDHVM_INTERCEPT_PF:
+		if (nestedhvm_paging_mode_hap(v)) {
+			/* host nested paging + guest nested paging */
+			if (!is_intercepted)
+				/* guest intercepts #PF unnecessarily */
+				return NESTEDHVM_VMEXIT_HOST;
+			/* nested 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 NESTEDHVM_INTERCEPT_MSR_READ:
+		return nestedhvm_vmexit_msr(hvm->nh_cached_msrpm, info1, 1);
+	case NESTEDHVM_INTERCEPT_MSR_WRITE:
+		return nestedhvm_vmexit_msr(hvm->nh_cached_msrpm, info1, 0);
+	case NESTEDHVM_INTERCEPT_IOIO:
+		/* Always let the guest handle IO access */
+		return NESTEDHVM_VMEXIT_INJECT;
+	default:
+		break;
+	}
+
+	if (is_intercepted)
+		return NESTEDHVM_VMEXIT_CONTINUE;
+	return NESTEDHVM_VMEXIT_HOST;
+}
+
+static enum nestedhvm_vmexits
+nestedhvm_vmexit(struct vcpu *v, struct cpu_user_regs *regs, uint64_t exitcode)
+{
+	int rc;
+	enum nestedhvm_vmexits ret;
+
+	ASSERT(nestedhvm_vcpu_in_guestmode(v));
+
+	rc = hvm_nestedhvm_vm_prepare4vmexit(v);
+	if (rc) {
+		ret = NESTEDHVM_VMEXIT_ERROR;
+		goto err1;
+	}
+
+	ret = nestedhvm_vmexit_intercepts(v, regs, exitcode);
+	switch (ret) {
+	case NESTEDHVM_VMEXIT_CONTINUE:
+	case NESTEDHVM_VMEXIT_INJECT:
+		break;
+	case NESTEDHVM_VMEXIT_ERROR:
+	case NESTEDHVM_VMEXIT_FATALERROR:
+		goto err1;
+	case NESTEDHVM_VMEXIT_HOST:
+		return ret;
+	default:
+		break;
+	}
+
+	rc = hvm_nestedhvm_vcpu_hostrestore(v, regs);
+	if (rc) {
+		ret = NESTEDHVM_VMEXIT_FATALERROR;
+		goto err0;
+	}
+
+	nestedhvm_vcpu_exit_guestmode(v);
+
+	return ret;
+
+err1:
+	rc = hvm_nestedhvm_vcpu_hostrestore(v, regs);
+	if (rc)
+		ret = NESTEDHVM_VMEXIT_FATALERROR;
+err0:
+	nestedhvm_vcpu_exit_guestmode(v);
+	return ret;
+}
+
+/* The exitcode is in native SVM/VMX format. The forced exitcode
+ * is in generic format.
+ */
+enum nestedhvm_vmexits
+nestedhvm_vcpu_vmexit(struct vcpu *v, struct cpu_user_regs *regs,
+			uint64_t exitcode)
+{
+	int rc;
+	struct nestedhvm *hvm = &VCPU_NESTEDHVM(v);
+	enum nestedhvm_vmexits ret;
+	enum hvm_copy_result hvm_rc;
+
+	hvm->nh_hostflags.fields.vmentry = 1;
+	if (nestedhvm_vcpu_in_guestmode(v)) {
+		ret = nestedhvm_vmexit(v, regs, exitcode);
+		switch (ret) {
+		case NESTEDHVM_VMEXIT_FATALERROR:
+		case NESTEDHVM_VMEXIT_HOST:
+			hvm->nh_hostflags.fields.vmentry = 0;
+			return ret;
+		case NESTEDHVM_VMEXIT_ERROR:
+			hvm->nh_hostflags.fields.forcevmexit = 1;
+			hvm->nh_forcevmexit.exitcode = NESTEDHVM_INTERCEPT_INVALID;
+			hvm->nh_forcevmexit.exitinfo1 = 0;
+			hvm->nh_forcevmexit.exitinfo2 = 0;
+			break;
+		default:
+			ASSERT(!nestedhvm_vcpu_in_guestmode(v));
+			break;
+		}
+
+		/* host state has been restored */
+	}
+
+	nestedsvm_vcpu_clgi(v);
+
+	/* Prepare for running the guest. Do some final SVM/VMX
+	 * specific tweaks if necessary to make it work.
+	 */
+	rc = hvm_nestedhvm_vcpu_vmexit(v, regs, exitcode);
+	hvm->nh_hostflags.fields.forcevmexit = 0;
+	if (rc) {
+		hvm->nh_hostflags.fields.vmentry = 0;
+		return NESTEDHVM_VMEXIT_FATALERROR;
+	}
+
+	ASSERT(!nestedhvm_vcpu_in_guestmode(v));
+	/* Inject VMEXIT into guest. */
+	hvm_rc = nestedhvm_vm_toguest(hvm, hvm->nh_vmaddr);
+	switch (hvm_rc) {
+	case HVMCOPY_okay:
+		ret = NESTEDHVM_VMEXIT_DONE;
+		break;
+	default:
+		hvm->nh_hostflags.fields.vmentry = 0;
+		return NESTEDHVM_VMEXIT_FATALERROR;
+	}
+
+	hvm->nh_hostflags.fields.vmentry = 0;
+	return ret;
+}
+
+/* Virtual GIF */
+int
+nestedsvm_vcpu_clgi(struct vcpu *v)
+{
+	if (!nestedhvm_enabled(v->domain)) {
+		hvm_inject_exception(TRAP_invalid_op, 0, 0);
+		return -1;
+	}
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+		return 0;
+
+	/* clear gif flag */
+	VCPU_NESTEDHVM(v).nh_gif = 0;
+	local_event_delivery_disable(v); /* mask events for PV drivers */
+	return 0;
+}
+
+int
+nestedsvm_vcpu_stgi(struct vcpu *v)
+{
+	if (!nestedhvm_enabled(v->domain)) {
+		hvm_inject_exception(TRAP_invalid_op, 0, 0);
+		return -1;
+	}
+
+	/* Always set the GIF to make hvm_interrupt_blocked work. */
+	VCPU_NESTEDHVM(v).nh_gif = 1;
+
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+		return 0;
+
+	local_event_delivery_enable(v); /* unmask events for PV drivers */
+	return 0;
+}
+
+uint64_t
+nestedhvm_exception2exitcode(unsigned int trapnr)
+{
+    switch (trapnr) {
+    case TRAP_divide_error:
+        return NESTEDHVM_INTERCEPT_DE;
+    case TRAP_debug:
+        return NESTEDHVM_INTERCEPT_DB;
+    case TRAP_nmi:
+        return NESTEDHVM_INTERCEPT_NMI;
+    case TRAP_int3:
+        return NESTEDHVM_INTERCEPT_BP;
+    case TRAP_overflow:
+        return NESTEDHVM_INTERCEPT_OF;
+    case TRAP_bounds:
+        return NESTEDHVM_INTERCEPT_BR;
+    case TRAP_invalid_op:
+        return NESTEDHVM_INTERCEPT_UD;
+    case TRAP_no_device:
+        return NESTEDHVM_INTERCEPT_NM;
+    case TRAP_double_fault:
+        return NESTEDHVM_INTERCEPT_DF;
+    case TRAP_copro_seg:
+        return NESTEDHVM_INTERCEPT_09;
+    case TRAP_invalid_tss:
+        return NESTEDHVM_INTERCEPT_TS;
+    case TRAP_no_segment:
+        return NESTEDHVM_INTERCEPT_NP;
+    case TRAP_stack_error:
+        return NESTEDHVM_INTERCEPT_SS;
+    case TRAP_gp_fault:
+        return NESTEDHVM_INTERCEPT_GP;
+    case TRAP_page_fault:
+        return NESTEDHVM_INTERCEPT_PF;
+    case TRAP_spurious_int:
+        return NESTEDHVM_INTERCEPT_15;
+    case TRAP_copro_error:
+        return NESTEDHVM_INTERCEPT_MF;
+    case TRAP_alignment_check:
+        return NESTEDHVM_INTERCEPT_AC;
+    case TRAP_machine_check:
+        return NESTEDHVM_INTERCEPT_MCE;
+    case TRAP_simd_error:
+        return NESTEDHVM_INTERCEPT_XF;
+    }
+
+    BUG();
+    return 0;
+}
+
+unsigned int
+nestedhvm_exitcode2exception(uint64_t exitcode)
+{
+    switch (exitcode) {
+    case NESTEDHVM_INTERCEPT_DE:
+        return TRAP_divide_error;
+    case NESTEDHVM_INTERCEPT_DB:
+        return TRAP_debug;
+    case NESTEDHVM_INTERCEPT_NMI:
+        return TRAP_nmi;
+    case NESTEDHVM_INTERCEPT_BP:
+        return TRAP_int3;
+    case NESTEDHVM_INTERCEPT_OF:
+        return TRAP_overflow;
+    case NESTEDHVM_INTERCEPT_BR:
+        return TRAP_bounds;
+    case NESTEDHVM_INTERCEPT_UD:
+        return TRAP_invalid_op;
+    case NESTEDHVM_INTERCEPT_NM:
+        return TRAP_no_device;
+    case NESTEDHVM_INTERCEPT_DF:
+        return TRAP_double_fault;
+    case NESTEDHVM_INTERCEPT_09:
+        return TRAP_copro_seg;
+    case NESTEDHVM_INTERCEPT_TS:
+        return TRAP_invalid_tss;
+    case NESTEDHVM_INTERCEPT_NP:
+        return TRAP_no_segment;
+    case NESTEDHVM_INTERCEPT_SS:
+        return TRAP_stack_error;
+    case NESTEDHVM_INTERCEPT_GP:
+        return TRAP_gp_fault;
+    case NESTEDHVM_INTERCEPT_PF:
+        return TRAP_page_fault;
+    case NESTEDHVM_INTERCEPT_15:
+        return TRAP_spurious_int;
+    case NESTEDHVM_INTERCEPT_MF:
+        return TRAP_copro_error;
+    case NESTEDHVM_INTERCEPT_AC:
+        return TRAP_alignment_check;
+    case NESTEDHVM_INTERCEPT_MCE:
+        return TRAP_machine_check;
+    case NESTEDHVM_INTERCEPT_XF:
+        return TRAP_simd_error;
+    }
+
+    BUG();
+    return 0;
+}
diff -r c19b4e3959c5 -r 917f9eb07fc3 xen/include/asm-x86/hvm/nestedhvm.h
--- /dev/null
+++ b/xen/include/asm-x86/hvm/nestedhvm.h
@@ -0,0 +1,139 @@
+/*
+ * Nested HVM
+ * Copyright (c) 2010, Advanced Micro Devices, Inc.
+ * Author: Christoph Egger <Christoph.Egger@amd.com>
+ *
+ * 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 _HVM_NESTEDHVM_H
+#define _HVM_NESTEDHVM_H
+
+#include <xen/types.h>         /* for uintNN_t */
+#include <xen/sched.h>         /* for struct vcpu, struct domain */
+#include <asm/hvm/vcpu.h>      /* for VCPU_NESTEDHVM */
+
+enum nestedhvm_vmexits {
+	NESTEDHVM_VMEXIT_ERROR = 0, /* inject VMEXIT w/ invalid VMCB */
+	NESTEDHVM_VMEXIT_FATALERROR = 1, /* crash first level guest */
+	NESTEDHVM_VMEXIT_HOST = 2,  /* exit handled on host level */
+	NESTEDHVM_VMEXIT_CONTINUE = 3, /* further handling */
+	NESTEDHVM_VMEXIT_INJECT = 4, /* inject VMEXIT */
+	NESTEDHVM_VMEXIT_DONE = 5, /* VMEXIT handled */
+};
+
+/* Generic exit codes
+ * Note: This is not a complete list. Only maintain those which are
+ * used in the generic code. All other exit codes are represented
+ * by NESTEDHVM_INTERCEPT_LAST.
+ */
+enum nestedhvm_intercepts {
+	/* exitinfo1 and exitinfo2 undefined */
+	NESTEDHVM_INTERCEPT_INVALID = 0, /* INVALID vmcb/vmcs */
+	NESTEDHVM_INTERCEPT_SHUTDOWN = 1, /* kill guest */
+	NESTEDHVM_INTERCEPT_MCE = 2, /* machine check exception */
+
+	/* exitinfo1 is hvm_intsrc_*, exitinfo2 is the vector */
+	NESTEDHVM_INTERCEPT_INTR = 3, /* interrupt exit code */
+	NESTEDHVM_INTERCEPT_NMI = 4, /* NMI exit code */
+
+	/* exitinfo1 is msr, exitinfo2 undefined */
+	NESTEDHVM_INTERCEPT_MSR_READ = 5, /* MSR read access */
+	/* exitinfo1 is msr, exitinfo2 is msr value */
+	NESTEDHVM_INTERCEPT_MSR_WRITE = 6, /* MSR write access */
+
+	/* exitinfo1 not yet specified, exitinfo2: rip after instruction */
+	NESTEDHVM_INTERCEPT_IOIO = 7, /* IO port access */
+
+	/* exitinfo1 is PF error code, exitinfo2 is PF fault address */
+	NESTEDHVM_INTERCEPT_NPF = 8, /* nested page fault */
+	NESTEDHVM_INTERCEPT_PF = 9, /* page fault */
+
+	/* exceptions: exitinfo1 and exitinfo2 are undefined */
+	NESTEDHVM_INTERCEPT_DE = 10, /* divide by zero */
+	NESTEDHVM_INTERCEPT_OF = 11, /* overflow */
+	NESTEDHVM_INTERCEPT_BR = 12, /* bound-range */
+	NESTEDHVM_INTERCEPT_UD = 13, /* invalid-opcode */
+	NESTEDHVM_INTERCEPT_NM = 14, /* device-not-available */
+	NESTEDHVM_INTERCEPT_DF = 15, /* double-fault */
+	NESTEDHVM_INTERCEPT_09 = 16, /* unsupported (reserved) */
+	NESTEDHVM_INTERCEPT_XF = 17, /* simd, floating-point */
+
+	/* exceptions: exitinfo1 is cs, exitinfo2 is rip */
+	NESTEDHVM_INTERCEPT_DB = 18, /* debug */
+	NESTEDHVM_INTERCEPT_BP = 19, /* breakpoint */
+
+	/* exceptions: exitinfo1 and exitinfo2 still need to be defined */
+	NESTEDHVM_INTERCEPT_TS = 21, /* invalid-tss */
+
+	/* exceptions: exitinfo1 contains error code, exitinfo2 is undefined */
+	NESTEDHVM_INTERCEPT_NP = 22, /* segment-not-present */
+	NESTEDHVM_INTERCEPT_SS = 23, /* stack */
+	NESTEDHVM_INTERCEPT_GP = 24, /* general-protection */
+	NESTEDHVM_INTERCEPT_15 = 25, /* reserved */
+	NESTEDHVM_INTERCEPT_MF = 26, /* x87 floating-point exception-pending */
+	NESTEDHVM_INTERCEPT_AC = 27, /* alignment-check */
+
+	/* end mark */
+	NESTEDHVM_INTERCEPT_LAST,
+};
+
+/* Nested HVM on/off per domain */
+bool_t nestedhvm_enabled(struct domain *d);
+int nestedhvm_initialise(struct domain *d);
+
+/* Nested VM */
+enum hvm_copy_result
+nestedhvm_vm_fromguest(struct nestedhvm *hvm, uint64_t vmaddr);
+enum hvm_copy_result
+nestedhvm_vm_toguest(struct nestedhvm *hvm, uint64_t vmaddr);
+
+/* Nested VCPU */
+int nestedhvm_vcpu_initialise(struct vcpu *v);
+int nestedhvm_vcpu_destroy(struct vcpu *v);
+void nestedhvm_vcpu_reset(struct vcpu *v);
+bool_t nestedhvm_vcpu_in_guestmode(struct vcpu *v);
+#define nestedhvm_vcpu_enter_guestmode(v) VCPU_NESTEDHVM((v)).nh_guestmode = 1
+#define nestedhvm_vcpu_exit_guestmode(v) VCPU_NESTEDHVM((v)).nh_guestmode = 0
+int nestedhvm_vcpu_vmentry(struct vcpu *v, struct cpu_user_regs *regs,
+    uint64_t vmcbaddr, unsigned int inst_len);
+enum nestedhvm_vmexits nestedhvm_vcpu_vmexit(struct vcpu *v,
+    struct cpu_user_regs *regs, uint64_t exitcode);
+int nestedhvm_vcpu_state_validate(struct vcpu *v, uint64_t vmcbaddr);
+int nestedsvm_vcpu_clgi(struct vcpu *v);
+int nestedsvm_vcpu_stgi(struct vcpu *v);
+
+/* Interrupts */
+#define nestedsvm_gif_isset(v)	(!!VCPU_NESTEDHVM((v)).nh_gif)
+#define NESTEDHVM_INTR_NOTHANDLED     3
+#define NESTEDHVM_INTR_NOTINTERCEPTED 2
+#define NESTEDHVM_INTR_FORCEVMEXIT    1
+#define NESTEDHVM_INTR_MASKED         0
+int nestedhvm_vcpu_interrupt(struct vcpu *v, const struct hvm_intack intack);
+
+/* Nested paging */
+#define NESTEDHVM_PAGEFAULT_DONE   0
+#define NESTEDHVM_PAGEFAULT_INJECT 1
+#define NESTEDHVM_PAGEFAULT_ERROR  2
+int nestedhvm_hap_nested_page_fault(struct vcpu *v, paddr_t L2_gpa);
+
+/* Misc */
+#define nestedhvm_paging_mode_hap(v) (!!VCPU_NESTEDHVM((v)).nh_hap_enabled)
+#define nestedhvm_vmentry_emulate(v)   \
+    (!!VCPU_NESTEDHVM((v)).nh_hostflags.fields.vmentry)
+bool_t nestedhvm_vmaddr_isvalid(struct nestedhvm *hvm, uint64_t addr);
+uint64_t nestedhvm_exception2exitcode(unsigned int trapnr);
+unsigned int nestedhvm_exitcode2exception(uint64_t exitcode);
+
+#endif /* _HVM_NESTEDHVM_H */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 05/14] Nested Virtualization: core
  2010-08-05 15:01 [PATCH 05/14] Nested Virtualization: core Christoph Egger
@ 2010-08-09 12:38 ` Tim Deegan
  2010-08-10  8:36   ` Christoph Egger
  0 siblings, 1 reply; 3+ messages in thread
From: Tim Deegan @ 2010-08-09 12:38 UTC (permalink / raw)
  To: Christoph Egger; +Cc: xen-devel@lists.xensource.com

Hi, 

> +int
> +nestedhvm_vcpu_destroy(struct vcpu *v)
> +{
> +	int ret = 0;
> +
> +	if (!nestedhvm_enabled(v->domain))
> +		return 0;
> +
> +	if (nestedhvm_vcpu_in_guestmode(v)) {
> +		nestedhvm_vcpu_exit_guestmode(v);
> +		ret = -EBUSY;
> +	}

This still bothers me, since we go on to complete the teardown anyway,
and this function's only caller does nothing interesting with the
result.

> +	/* Enable interrupts or the guest won't see any interrupts
> +	 * after nested guest exited.
> +	 */
> +	nestedsvm_vcpu_stgi(v);
> +
> +	hvm_nestedhvm_vcpu_destroy(v);

While I'm complaining about unchecked return values, I should point out
that your implementation of this returns an integer (which in turn is
always 0).

> +	return ret;
> +}

Cheers,

Tim.

-- 
Tim Deegan <Tim.Deegan@citrix.com>
Principal Software Engineer, XenServer Engineering
Citrix Systems UK Ltd.  (Company #02937203, SL9 0BG)

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 05/14] Nested Virtualization: core
  2010-08-09 12:38 ` Tim Deegan
@ 2010-08-10  8:36   ` Christoph Egger
  0 siblings, 0 replies; 3+ messages in thread
From: Christoph Egger @ 2010-08-10  8:36 UTC (permalink / raw)
  To: Tim Deegan; +Cc: xen-devel@lists.xensource.com


Hi Tim,

It looks like I have missed this from your first review. Thanks for bringing
this up again.

On Monday 09 August 2010 14:38:48 Tim Deegan wrote:
> Hi,
>
> > +int
> > +nestedhvm_vcpu_destroy(struct vcpu *v)
> > +{
> > +	int ret = 0;
> > +
> > +	if (!nestedhvm_enabled(v->domain))
> > +		return 0;
> > +
> > +	if (nestedhvm_vcpu_in_guestmode(v)) {
> > +		nestedhvm_vcpu_exit_guestmode(v);
> > +		ret = -EBUSY;
> > +	}
>
> This still bothers me, since we go on to complete the teardown anyway,
> and this function's only caller does nothing interesting with the
> result.

I removed "vcpu in guestmode" check completely.

> > +	/* Enable interrupts or the guest won't see any interrupts
> > +	 * after nested guest exited.
> > +	 */
> > +	nestedsvm_vcpu_stgi(v);

This stgi call is gone.

> > +
> > +	hvm_nestedhvm_vcpu_destroy(v);
>
> While I'm complaining about unchecked return values, I should point out
> that your implementation of this returns an integer (which in turn is
> always 0).

I changed this to 'return hvm_nestedhvm_vcpu_destroy(v);'

> > +	return ret;

This return is gone.

> > +}


Christoph

-- 
---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

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-08-10  8:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-05 15:01 [PATCH 05/14] Nested Virtualization: core Christoph Egger
2010-08-09 12:38 ` Tim Deegan
2010-08-10  8:36   ` Christoph Egger

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.