Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 May 2014 03:50:07 +0000 (UTC)
From:      Neel Natu <neel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r266424 - in head/sys/amd64: include vmm vmm/intel
Message-ID:  <201405190350.s4J3o7VL064868@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: neel
Date: Mon May 19 03:50:07 2014
New Revision: 266424
URL: http://svnweb.freebsd.org/changeset/base/266424

Log:
  Add PG_U (user/supervisor) checks when translating a guest linear address
  to a guest physical address.
  
  PG_PS (page size) field is valid only in a PDE or a PDPTE so it is now
  checked only in non-terminal paging entries.
  
  Ignore the upper 32-bits of the CR3 for PAE paging.

Modified:
  head/sys/amd64/include/vmm.h
  head/sys/amd64/include/vmm_instruction_emul.h
  head/sys/amd64/vmm/intel/vmx.c
  head/sys/amd64/vmm/vmm.c
  head/sys/amd64/vmm/vmm_instruction_emul.c

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h	Mon May 19 01:21:02 2014	(r266423)
+++ head/sys/amd64/include/vmm.h	Mon May 19 03:50:07 2014	(r266424)
@@ -361,6 +361,7 @@ struct vm_exit {
 			uint64_t	cr3;
 			enum vie_cpu_mode cpu_mode;
 			enum vie_paging_mode paging_mode;
+			int		cpl;
 			struct vie	vie;
 		} inst_emul;
 		/*

Modified: head/sys/amd64/include/vmm_instruction_emul.h
==============================================================================
--- head/sys/amd64/include/vmm_instruction_emul.h	Mon May 19 01:21:02 2014	(r266423)
+++ head/sys/amd64/include/vmm_instruction_emul.h	Mon May 19 03:50:07 2014	(r266424)
@@ -119,7 +119,8 @@ int vmm_emulate_instruction(void *vm, in
  */
 int vmm_fetch_instruction(struct vm *vm, int cpuid,
 			  uint64_t rip, int inst_length, uint64_t cr3,
-			  enum vie_paging_mode paging_mode, struct vie *vie);
+			  enum vie_paging_mode paging_mode, int cpl,
+			  struct vie *vie);
 
 void vie_init(struct vie *vie);
 

Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c	Mon May 19 01:21:02 2014	(r266423)
+++ head/sys/amd64/vmm/intel/vmx.c	Mon May 19 03:50:07 2014	(r266424)
@@ -1492,6 +1492,18 @@ vmx_emulate_cr_access(struct vmx *vmx, i
 	return (HANDLED);
 }
 
+/*
+ * From section "Guest Register State" in the Intel SDM: CPL = SS.DPL
+ */
+static int
+vmx_cpl(void)
+{
+	uint32_t ssar;
+
+	ssar = vmcs_read(VMCS_GUEST_SS_ACCESS_RIGHTS);
+	return ((ssar >> 5) & 0x3);
+}
+
 static enum vie_cpu_mode
 vmx_cpu_mode(void)
 {
@@ -1516,6 +1528,18 @@ vmx_paging_mode(void)
 		return (PAGING_MODE_PAE);
 }
 
+static void
+vmexit_inst_emul(struct vm_exit *vmexit, uint64_t gpa, uint64_t gla)
+{
+	vmexit->exitcode = VM_EXITCODE_INST_EMUL;
+	vmexit->u.inst_emul.gpa = gpa;
+	vmexit->u.inst_emul.gla = gla;
+	vmexit->u.inst_emul.cr3 = vmcs_guest_cr3();
+	vmexit->u.inst_emul.cpu_mode = vmx_cpu_mode();
+	vmexit->u.inst_emul.paging_mode = vmx_paging_mode();
+	vmexit->u.inst_emul.cpl = vmx_cpl();
+}
+
 static int
 ept_fault_type(uint64_t ept_qual)
 {
@@ -1707,12 +1731,8 @@ vmx_handle_apic_access(struct vmx *vmx, 
 	}
 
 	if (allowed) {
-		vmexit->exitcode = VM_EXITCODE_INST_EMUL;
-		vmexit->u.inst_emul.gpa = DEFAULT_APIC_BASE + offset;
-		vmexit->u.inst_emul.gla = VIE_INVALID_GLA;
-		vmexit->u.inst_emul.cr3 = vmcs_guest_cr3();
-		vmexit->u.inst_emul.cpu_mode = vmx_cpu_mode();
-		vmexit->u.inst_emul.paging_mode = vmx_paging_mode();
+		vmexit_inst_emul(vmexit, DEFAULT_APIC_BASE + offset,
+		    VIE_INVALID_GLA);
 	}
 
 	/*
@@ -1943,12 +1963,7 @@ vmx_exit_process(struct vmx *vmx, int vc
 			vmexit->u.paging.fault_type = ept_fault_type(qual);
 			vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NESTED_FAULT, 1);
 		} else if (ept_emulation_fault(qual)) {
-			vmexit->exitcode = VM_EXITCODE_INST_EMUL;
-			vmexit->u.inst_emul.gpa = gpa;
-			vmexit->u.inst_emul.gla = vmcs_gla();
-			vmexit->u.inst_emul.cr3 = vmcs_guest_cr3();
-			vmexit->u.inst_emul.cpu_mode = vmx_cpu_mode();
-			vmexit->u.inst_emul.paging_mode = vmx_paging_mode();
+			vmexit_inst_emul(vmexit, gpa, vmcs_gla());
 			vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INST_EMUL, 1);
 		}
 		/*

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c	Mon May 19 01:21:02 2014	(r266423)
+++ head/sys/amd64/vmm/vmm.c	Mon May 19 03:50:07 2014	(r266424)
@@ -1131,7 +1131,7 @@ vm_handle_inst_emul(struct vm *vm, int v
 	struct vie *vie;
 	struct vcpu *vcpu;
 	struct vm_exit *vme;
-	int error, inst_length;
+	int cpl, error, inst_length;
 	uint64_t rip, gla, gpa, cr3;
 	enum vie_cpu_mode cpu_mode;
 	enum vie_paging_mode paging_mode;
@@ -1147,6 +1147,7 @@ vm_handle_inst_emul(struct vm *vm, int v
 	gla = vme->u.inst_emul.gla;
 	gpa = vme->u.inst_emul.gpa;
 	cr3 = vme->u.inst_emul.cr3;
+	cpl = vme->u.inst_emul.cpl;
 	cpu_mode = vme->u.inst_emul.cpu_mode;
 	paging_mode = vme->u.inst_emul.paging_mode;
 	vie = &vme->u.inst_emul.vie;
@@ -1155,7 +1156,7 @@ vm_handle_inst_emul(struct vm *vm, int v
 
 	/* Fetch, decode and emulate the faulting instruction */
 	if (vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3,
-	    paging_mode, vie) != 0)
+	    paging_mode, cpl, vie) != 0)
 		return (EFAULT);
 
 	if (vmm_decode_instruction(vm, vcpuid, gla, cpu_mode, vie) != 0)

Modified: head/sys/amd64/vmm/vmm_instruction_emul.c
==============================================================================
--- head/sys/amd64/vmm/vmm_instruction_emul.c	Mon May 19 01:21:02 2014	(r266423)
+++ head/sys/amd64/vmm/vmm_instruction_emul.c	Mon May 19 03:50:07 2014	(r266424)
@@ -572,14 +572,16 @@ vie_init(struct vie *vie)
 }
 
 static int
-gla2gpa(struct vm *vm, uint64_t gla, uint64_t ptpphys,
-	uint64_t *gpa, enum vie_paging_mode paging_mode)
+gla2gpa(struct vm *vm, uint64_t gla, uint64_t ptpphys, uint64_t *gpa,
+    enum vie_paging_mode paging_mode, int cpl)
 {
-	int nlevels, ptpshift, ptpindex;
+	int nlevels, ptpshift, ptpindex, usermode;
 	uint64_t *ptpbase, pte, pgsize;
 	uint32_t *ptpbase32, pte32;
 	void *cookie;
 
+	usermode = (cpl == 3 ? 1 : 0);
+
 	if (paging_mode == PAGING_MODE_FLAT) {
 		*gpa = gla;
 		return (0);
@@ -593,7 +595,7 @@ gla2gpa(struct vm *vm, uint64_t gla, uin
 
 			ptpbase32 = vm_gpa_hold(vm, ptpphys, PAGE_SIZE,
 						VM_PROT_READ, &cookie);
-			
+
 			if (ptpbase32 == NULL)
 				goto error;
 
@@ -608,7 +610,11 @@ gla2gpa(struct vm *vm, uint64_t gla, uin
 			if ((pte32 & PG_V) == 0)
 				goto error;
 
-			if (pte32 & PG_PS)
+			if (usermode && (pte32 & PG_U) == 0)
+				goto error;
+
+			/* XXX must be ignored if CR4.PSE=0 */
+			if (nlevels > 0 && (pte32 & PG_PS) != 0)
 				break;
 
 			ptpphys = pte32;
@@ -621,8 +627,8 @@ gla2gpa(struct vm *vm, uint64_t gla, uin
 	}
 
 	if (paging_mode == PAGING_MODE_PAE) {
-		/* Zero out the lower 5 bits and the upper 12 bits */
-		ptpphys >>= 5; ptpphys <<= 17; ptpphys >>= 12;
+		/* Zero out the lower 5 bits and the upper 32 bits */
+		ptpphys &= 0xffffffe0UL;
 
 		ptpbase = vm_gpa_hold(vm, ptpphys, sizeof(*ptpbase) * 4,
 				      VM_PROT_READ, &cookie);
@@ -663,7 +669,10 @@ gla2gpa(struct vm *vm, uint64_t gla, uin
 		if ((pte & PG_V) == 0)
 			goto error;
 
-		if (pte & PG_PS) {
+		if (usermode && (pte & PG_U) == 0)
+			goto error;
+
+		if (nlevels > 0 && (pte & PG_PS) != 0) {
 			if (pgsize > 1 * GB)
 				goto error;
 			else
@@ -684,7 +693,7 @@ error:
 
 int
 vmm_fetch_instruction(struct vm *vm, int cpuid, uint64_t rip, int inst_length,
-		      uint64_t cr3, enum vie_paging_mode paging_mode,
+		      uint64_t cr3, enum vie_paging_mode paging_mode, int cpl,
 		      struct vie *vie)
 {
 	int n, err, prot;
@@ -701,7 +710,7 @@ vmm_fetch_instruction(struct vm *vm, int
 
 	/* Copy the instruction into 'vie' */
 	while (vie->num_valid < inst_length) {
-		err = gla2gpa(vm, rip, cr3, &gpa, paging_mode);
+		err = gla2gpa(vm, rip, cr3, &gpa, paging_mode, cpl);
 		if (err)
 			break;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405190350.s4J3o7VL064868>