Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 May 2014 08:56:07 -0700
From:      Anish <akgupt3@gmail.com>
To:        Andriy Gapon <avg@freebsd.org>
Cc:        FreeBSD virtualization <freebsd-virtualization@freebsd.org>, Neel Natu <neel@freebsd.org>
Subject:   Re: bhyve: svm (amd-v) update
Message-ID:  <CALnRwMRpwc=DHib%2BeooftCkSP_K6XtVuR11AceDYju=mMBE2%2Bw@mail.gmail.com>
In-Reply-To: <53748481.8010108@FreeBSD.org>
References:  <53748481.8010108@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi Andriy,
 Thanks for your interest in SVM port of bhyve. I do have patch to sync it
to http://svnweb.freebsd.org/base?view=revision&revision=263780(3/26). If
patches looks good to you, we can submit it. I have been testing it on
Phenom box which lacks some of newer SVM features.

Thanks and regards,
Anish


On Thu, May 15, 2014 at 2:10 AM, Andriy Gapon <avg@freebsd.org> wrote:

>
> It seems that the bhyve_svm branch is a bit behind the latest interface
> changes
> in head.  Is anyone working on sync-ing up the branch with the head?
>
> Some examples:
> - change of init method in vmm_ops
> - addition of resume, vlapic_init and vlapic_cleanup methods to vmm_ops
> - replacement of lapic_pending_intr and lapic_intr_accepted with
> vlapic_pending_intr and vlapic_intr_accepted
> - changes in struct vm_exit
> - VMEXIT_EPT_FAULT ==> VMEXIT_NESTED_FAULT
>
> Thanks!
> --
> Andriy Gapon
>
> _______________________________________________
> freebsd-virtualization@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-virtualization
> To unsubscribe, send any mail to "
> freebsd-virtualization-unsubscribe@freebsd.org"
>

[-- Attachment #2 --]
diff -aurP -x '*.orig' -x .svn /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/npt.c /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/npt.c
--- /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/npt.c	2014-04-11 13:51:45.000000000 +0000
+++ /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/npt.c	2014-04-06 04:34:17.000000000 +0000
@@ -52,14 +52,17 @@
 static int npt_flags;
 SYSCTL_INT(_hw_vmm_npt, OID_AUTO, pmap_flags, CTLFLAG_RD,
 	&npt_flags, 0, NULL);
+
+#define NPT_IPIMASK	0xFF
 /*
  * AMD nested page table init.
  */
 int
-svm_npt_init(void)
+svm_npt_init(int ipinum)
 {
 	int enable_superpage = 1;
 
+	npt_flags = ipinum & NPT_IPIMASK;
 	TUNABLE_INT_FETCH("hw.vmm.npt.enable_superpage", &enable_superpage);
 	if (enable_superpage)
 		npt_flags |= PMAP_PDE_SUPERPAGE; 
diff -aurP -x '*.orig' -x .svn /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/npt.h /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/npt.h
--- /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/npt.h	2014-04-11 13:51:45.000000000 +0000
+++ /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/npt.h	2014-04-06 04:34:17.000000000 +0000
@@ -31,7 +31,7 @@
 
 struct svm_softc;
 
-int 	svm_npt_init(void);
+int 	svm_npt_init(int ipinum);
 struct	vmspace *svm_npt_alloc(vm_offset_t min, vm_offset_t max);
 void	svm_npt_free(struct vmspace *vmspace);
 #endif /* _SVM_NPT_H_ */
diff -aurP -x '*.orig' -x .svn /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/svm.c /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/svm.c
--- /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/svm.c	2014-04-11 13:51:45.000000000 +0000
+++ /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/svm.c	2014-04-12 11:51:53.000000000 +0000
@@ -46,6 +46,7 @@
 #include <machine/specialreg.h>
 #include <machine/segments.h>
 #include <machine/vmm.h>
+#include <machine/vmm_dev.h>
 
 #include <x86/apicreg.h>
 
@@ -53,6 +54,8 @@
 #include "vmm_msr.h"
 #include "vmm_stat.h"
 #include "vmm_ktr.h"
+#include "vlapic.h"
+#include "vlapic_priv.h"
 
 #include "x86.h"
 #include "vmcb.h"
@@ -75,6 +78,7 @@
 #define AMD_CPUID_SVM_PAUSE_FTH		BIT(12) /* Pause filter threshold */
 
 MALLOC_DEFINE(M_SVM, "svm", "svm");
+MALLOC_DEFINE(M_SVM_VLAPIC, "svm-vlapic", "svm-vlapic");
 
 /* Per-CPU context area. */
 extern struct pcpu __pcpu[];
@@ -249,7 +253,7 @@
  * Enable SVM on CPU and initialize nested page table h/w.
  */
 static int
-svm_init(void)
+svm_init(int ipinum)
 {
 	int err;
 
@@ -258,7 +262,7 @@
 		return (err);
 	
 
-	svm_npt_init();
+	svm_npt_init(ipinum);
 	
 	/* Start SVM on all CPUs */
 	smp_rendezvous(NULL, svm_enable, NULL, NULL);
@@ -266,6 +270,11 @@
 	return (0);
 }
 
+static void
+svm_restore(void)
+{
+	svm_enable(NULL);
+}		
 /*
  * Get index and bit position for a MSR in MSR permission
  * bitmap. Two bits are used for each MSR, lower bit is
@@ -365,7 +374,6 @@
 	
 	return (0);
 }
-		
 /*
  * Initialise a virtual machine.
  */
@@ -519,6 +527,29 @@
 	}
 }
 
+static enum vie_cpu_mode
+svm_vcpu_mode(uint64_t efer)
+{
+
+	if (efer & EFER_LMA)
+		return (CPU_MODE_64BIT);
+	else
+		return (CPU_MODE_COMPATIBILITY);
+}
+
+static enum vie_paging_mode
+svm_paging_mode(uint64_t cr0, uint64_t cr4, uint64_t efer)
+{
+
+	if ((cr0 & CR0_PG) == 0)
+		return (PAGING_MODE_FLAT);
+	if ((cr4 & CR4_PAE) == 0)
+		return (PAGING_MODE_32);
+	if (efer & EFER_LME)
+		return (PAGING_MODE_64);
+	else
+		return (PAGING_MODE_PAE);
+}
 /*
  * Determine the cause of virtual cpu exit and handle VMEXIT.
  * Return: false - Break vcpu execution loop and handle vmexit
@@ -547,7 +578,7 @@
 	update_rip = true;
 	loop = true;
 	vmexit->exitcode = VM_EXITCODE_VMX;
-	vmexit->u.vmx.error = 0;
+	vmexit->u.vmx.status = 0;
 
 	switch (code) {
 		case	VMCB_EXIT_MC: /* Machine Check. */
@@ -667,7 +698,6 @@
 		case VMCB_EXIT_NPF:
 			loop = false;
 			update_rip = false;
-			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_EPT_FAULT, 1);
 
         		if (info1 & VMCB_NPF_INFO1_RSV) {
  				VCPU_CTR2(svm_sc->vm, vcpu, "SVM_ERR:NPT"
@@ -686,15 +716,24 @@
 				vmexit->u.paging.gpa = info2;
 				vmexit->u.paging.fault_type = 
 					svm_npf_paging(info1);
+				vmm_stat_incr(svm_sc->vm, vcpu, 
+					VMEXIT_NESTED_FAULT, 1);
 			} else if (svm_npf_emul_fault(info1)) {
- 				VCPU_CTR3(svm_sc->vm, vcpu, "SVM:NPF-inst_emul,"
+ 				VCPU_CTR3(svm_sc->vm, vcpu, "SVM:NPF inst_emul,"
 					"RIP:0x%lx INFO1:0x%lx INFO2:0x%lx .\n",
 					state->rip, info1, info2);
 				vmexit->exitcode = VM_EXITCODE_INST_EMUL;
 				vmexit->u.inst_emul.gpa = info2;
 				vmexit->u.inst_emul.gla = VIE_INVALID_GLA;
 				vmexit->u.inst_emul.cr3 = state->cr3;
+				vmexit->u.inst_emul.cpu_mode = 
+					svm_vcpu_mode(state->efer);
+				vmexit->u.inst_emul.paging_mode =
+					svm_paging_mode(state->cr0, state->cr4,
+						 state->efer);
 				vmexit->inst_length = VIE_INST_SIZE;
+				vmm_stat_incr(svm_sc->vm, vcpu, 
+					VMEXIT_INST_EMUL, 1);
 			}
 			
 			break;
@@ -762,7 +801,7 @@
 		return (0);
 
 	 /* Inject NMI, vector number is not used.*/
-	if (vmcb_eventinject(ctrl, VM_NMI, IDT_NMI, 0, false)) {
+	if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_NMI, IDT_NMI, 0, false)) {
 		VCPU_CTR0(svm_sc->vm, vcpu, "SVM:NMI injection failed.\n");
 		return (EIO);
 	}
@@ -779,10 +818,11 @@
  * Inject event to virtual cpu.
  */
 static void
-svm_inj_interrupts(struct svm_softc *svm_sc, int vcpu)
+svm_inj_interrupts(struct svm_softc *svm_sc, int vcpu, struct vlapic *vlapic)
 {
 	struct vmcb_ctrl *ctrl;
 	struct vmcb_state *state;
+	struct vm_exception exc;
 	int vector;
 	
 	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
@@ -802,17 +842,26 @@
 		VCPU_CTR0(svm_sc->vm, vcpu, "SVM:Guest in interrupt shadow.\n");
 		return;
 	}
-
+	
+	if (vm_exception_pending(svm_sc->vm, vcpu, &exc)) {
+		KASSERT(exc.vector >= 0 && exc.vector < 32,
+			("Exception vector% invalid", exc.vector));
+		if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_EXCEPTION, 
+			exc.vector, exc.error_code, 
+			exc.error_code_valid)) {
+			VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Exception%d injection"
+				" failed.\n", exc.vector);
+			return;
+		}
+	}
 	/* NMI event has priority over interrupts.*/
 	if (svm_inject_nmi(svm_sc, vcpu)) {
 		return;
 	}
 
-	vector = lapic_pending_intr(svm_sc->vm, vcpu);
-
-	/* No interrupt is pending. */	
-	if (vector < 0)
-		return;
+        /* Ask the local apic for a vector to inject */
+        if (!vlapic_pending_intr(vlapic, &vector))
+                return;
 	
 	if (vector < 32 || vector > 255) {
 		VCPU_CTR1(svm_sc->vm, vcpu, "SVM_ERR:Event injection"
@@ -826,14 +875,14 @@
 		return;
 	}
 
-	if (vmcb_eventinject(ctrl, VM_HW_INTR, vector, 0, false)) {
+	if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_INTR, vector, 0, false)) {
 		VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Event injection failed to"
 			" vector=%d.\n", vector);
 		return;
 	}	
 
 	/* Acknowledge that event is accepted.*/
-	lapic_intr_accepted(svm_sc->vm, vcpu, vector);
+	vlapic_intr_accepted(vlapic, vector);
 	VCPU_CTR1(svm_sc->vm, vcpu, "SVM:event injected,vector=%d.\n", vector);
 }
 
@@ -887,7 +936,8 @@
  * Start vcpu with specified RIP.
  */
 static int
-svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap)
+svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap, 
+	void *rend_cookie, void *suspended_cookie)
 {
 	struct svm_regctx *hctx, *gctx;
 	struct svm_softc *svm_sc;
@@ -895,17 +945,21 @@
 	struct vmcb_state *state;
 	struct vmcb_ctrl *ctrl;
 	struct vm_exit *vmexit;
+	struct vlapic *vlapic;
+	struct vm *vm;
 	uint64_t vmcb_pa;
 	static uint64_t host_cr2;
 	bool loop;	/* Continue vcpu execution loop. */
 
 	loop = true;
 	svm_sc = arg;
-	
+	vm = svm_sc->vm;
+
 	vcpustate = svm_get_vcpu(svm_sc, vcpu);
 	state = svm_get_vmcb_state(svm_sc, vcpu);
 	ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
-	vmexit = vm_exitinfo(svm_sc->vm, vcpu);
+	vmexit = vm_exitinfo(vm, vcpu);
+	vlapic = vm_lapic(vm, vcpu);
 
 	gctx = svm_get_guest_regctx(svm_sc, vcpu);
 	hctx = &host_ctx[curcpu]; 
@@ -913,7 +967,7 @@
 
 	if (vcpustate->lastcpu != curcpu) {
 		/* Virtual CPU is running on a diiferent CPU now.*/
-		vmm_stat_incr(svm_sc->vm, vcpu, VCPU_MIGRATIONS, 1);
+		vmm_stat_incr(vm, vcpu, VCPU_MIGRATIONS, 1);
 
 		/*
 		 * Flush all TLB mapping for this guest on this CPU,
@@ -946,7 +1000,7 @@
 	}
 
 	vcpustate->lastcpu = curcpu;
-	VCPU_CTR3(svm_sc->vm, vcpu, "SVM:Enter vmrun old RIP:0x%lx"
+	VCPU_CTR3(vm, vcpu, "SVM:Enter vmrun old RIP:0x%lx"
 		" new RIP:0x%lx inst len=%d\n",
 		state->rip, rip, vmexit->inst_length);
 	/* Update Guest RIP */
@@ -957,9 +1011,25 @@
 		 /* We are asked to give the cpu by scheduler. */
 		if (curthread->td_flags & (TDF_ASTPENDING | TDF_NEEDRESCHED)) {
 			vmexit->exitcode = VM_EXITCODE_BOGUS;
-			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_ASTPENDING, 1);
-			VCPU_CTR1(svm_sc->vm, vcpu, 
-				"SVM: gave up CPU, RIP:0x%lx\n", state->rip);
+			vmm_stat_incr(vm, vcpu, VMEXIT_ASTPENDING, 1);
+			VCPU_CTR1(vm, vcpu, 
+				"SVM: ASTPENDING, RIP:0x%lx\n", state->rip);
+			vmexit->rip = state->rip;
+			break;
+		}
+
+		if (vcpu_suspended(suspended_cookie)) {
+			vmexit->exitcode = VM_EXITCODE_SUSPENDED;
+			vmexit->rip = state->rip;
+			break;
+		}
+
+		if (vcpu_rendezvous_pending(rend_cookie)) {
+			vmexit->exitcode = VM_EXITCODE_RENDEZVOUS;
+			vmm_stat_incr(vm, vcpu, VMEXIT_RENDEZVOUS, 1);
+			VCPU_CTR1(vm, vcpu, 
+				"SVM: VCPU rendezvous, RIP:0x%lx\n", 
+				state->rip);
 			vmexit->rip = state->rip;
 			break;
 		}
@@ -968,7 +1038,7 @@
 		
 		svm_handle_exitintinfo(svm_sc, vcpu);
 		
-		(void)svm_inj_interrupts(svm_sc, vcpu);
+		(void)svm_inj_interrupts(svm_sc, vcpu, vlapic);
 	
 		/* Change TSS type to available.*/
 		setup_tss_type();
@@ -1017,7 +1087,7 @@
 		/* Handle #VMEXIT and if required return to user space. */
 		loop = svm_vmexit(svm_sc, vcpu, vmexit);
 		vcpustate->loop++;
-		vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_COUNT, 1);
+		vmm_stat_incr(vm, vcpu, VMEXIT_COUNT, 1);
 
 	} while (loop);
 		
@@ -1209,24 +1279,6 @@
 }
 
 static int
-svm_inject_event(void *arg, int vcpu, int type, int vector,
-		  uint32_t error, int ec_valid)
-{
-	struct svm_softc *svm_sc;
-	struct vmcb_ctrl *ctrl;
-
-	svm_sc = arg;
-	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
-
-	ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
-	VCPU_CTR3(svm_sc->vm, vcpu, "Injecting event type:0x%x vector:0x%x"
-		"error:0x%x\n", type, vector, error);
-
-	return (vmcb_eventinject(ctrl, type, vector, error,
-		ec_valid ? TRUE : FALSE));
-}
-
-static int
 svm_setcap(void *arg, int vcpu, int type, int val)
 {
 	struct svm_softc *svm_sc;
@@ -1324,9 +1376,35 @@
 	return (0);
 }
 
+static struct vlapic *
+svm_vlapic_init(void *arg, int vcpuid)
+{
+	struct svm_softc *svm_sc;
+	struct vlapic *vlapic;
+
+	svm_sc = arg;
+	vlapic = malloc(sizeof(struct vlapic), M_SVM_VLAPIC, M_WAITOK | M_ZERO);
+	vlapic->vm = svm_sc->vm;
+	vlapic->vcpuid = vcpuid;
+	vlapic->apic_page = (struct LAPIC *)&svm_sc->apic_page[vcpuid];
+
+	vlapic_init(vlapic);
+	
+	return (vlapic);
+}
+
+static void
+svm_vlapic_cleanup(void *arg, struct vlapic *vlapic)
+{
+
+        vlapic_cleanup(vlapic);
+        free(vlapic, M_SVM_VLAPIC);
+}
+
 struct vmm_ops vmm_ops_amd = {
 	svm_init,
 	svm_cleanup,
+	svm_restore,
 	svm_vminit,
 	svm_vmrun,
 	svm_vmcleanup,
@@ -1334,9 +1412,10 @@
 	svm_setreg,
 	svm_getdesc,
 	svm_setdesc,
-	svm_inject_event,
 	svm_getcap,
 	svm_setcap,
 	svm_npt_alloc,
-	svm_npt_free
+	svm_npt_free,
+	svm_vlapic_init,
+	svm_vlapic_cleanup	
 };
diff -aurP -x '*.orig' -x .svn /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/svm_softc.h /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/svm_softc.h
--- /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/svm_softc.h	2014-04-11 13:51:45.000000000 +0000
+++ /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/svm_softc.h	2014-04-06 04:34:17.000000000 +0000
@@ -61,6 +61,7 @@
 	 */
 	uint8_t	msr_bitmap[SVM_MSR_BITMAP_SIZE];
 
+	uint8_t apic_page[VM_MAXCPU][PAGE_SIZE];
 	/* Nested Paging */
 	vm_offset_t 	nptp;	
 
diff -aurP -x '*.orig' -x .svn /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/vmcb.c /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/vmcb.c
--- /mnt/sync_next2/bhyve_svm_HEAD_r263780_base//sys/amd64/vmm/amd/vmcb.c	2014-04-11 13:51:45.000000000 +0000
+++ /mnt/sync_next2/bhyve_svm_HEAD_r263780_WIP/sys/amd64/vmm/amd/vmcb.c	2014-04-06 04:34:17.000000000 +0000
@@ -354,25 +354,12 @@
  * Inject an event to vcpu as described in section 15.20, "Event injection".
  */
 int
-vmcb_eventinject(struct vmcb_ctrl *ctrl, int type, int vector,
+vmcb_eventinject(struct vmcb_ctrl *ctrl, int intr_type, int vector,
 		 uint32_t error, bool ec_valid)
 {
-	int intr_type;
-
-	static uint8_t  svm_intr_type_map[VM_EVENT_MAX] = {
-		-1,				/* VM_EVENT_NONE */
-		VMCB_EVENTINJ_TYPE_INTR,	/* VM_HW_INTR */
-		VMCB_EVENTINJ_TYPE_NMI,	 	/* VM_NMI */
-		VMCB_EVENTINJ_TYPE_EXCEPTION,	/* VM_HW_EXCEPTION */
-		VMCB_EVENTINJ_TYPE_INTn, 	/* VM_SW_INTR, INT */
-		VMCB_EVENTINJ_TYPE_INTn, 	/* VM_PRIV_SW_EXCEPTION */
-		VMCB_EVENTINJ_TYPE_INTn, 	/* VM_SW_EXCEPTION */
-	};
-
-	intr_type = svm_intr_type_map[type];
 	if (intr_type < VMCB_EVENTINJ_TYPE_INTR ||
 	    intr_type > VMCB_EVENTINJ_TYPE_INTn) {
-		ERR("Event:%d is not supported by SVM.\n", type);
+		ERR("Event:%d is not supported by SVM.\n", intr_type);
 		return (EINVAL);
 	}
 

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CALnRwMRpwc=DHib%2BeooftCkSP_K6XtVuR11AceDYju=mMBE2%2Bw>