Module Name:    src
Committed By:   maxv
Date:           Tue Feb 14 09:11:05 UTC 2017

Modified Files:
        src/sys/arch/amd64/amd64: trap.c
        src/sys/arch/x86/x86: sys_machdep.c

Log Message:
Add most of my USER_LDT code for amd64, but disable it and put a comment
about why Wine still does not work.

Nothing changes, but at least it is a step forward.


To generate a diff of this commit:
cvs rdiff -u -r1.89 -r1.90 src/sys/arch/amd64/amd64/trap.c
cvs rdiff -u -r1.31 -r1.32 src/sys/arch/x86/x86/sys_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/amd64/amd64/trap.c
diff -u src/sys/arch/amd64/amd64/trap.c:1.89 src/sys/arch/amd64/amd64/trap.c:1.90
--- src/sys/arch/amd64/amd64/trap.c:1.89	Wed Jan 18 05:11:59 2017
+++ src/sys/arch/amd64/amd64/trap.c	Tue Feb 14 09:11:05 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.89 2017/01/18 05:11:59 kamil Exp $	*/
+/*	$NetBSD: trap.c,v 1.90 2017/02/14 09:11:05 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.89 2017/01/18 05:11:59 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.90 2017/02/14 09:11:05 maxv Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -373,6 +373,10 @@ kernelfault:
 			break;
 		case 0x848e:	/* mov 0xa8(%rsp),%es (8e 84 24 a8 00 00 00) */
 		case 0x9c8e:	/* mov 0xb0(%rsp),%ds (8e 9c 24 b0 00 00 00) */
+#ifdef USER_LDT
+		case 0xa48e:	/* mov 0xa0(%rsp),%fs (8e a4 24 a0 00 00 00) */
+		case 0xac8e:	/* mov 0x98(%rsp),%gs (8e ac 24 98 00 00 00) */
+#endif
 			/*
 			 * We faulted loading one of the user segment registers.
 			 * The stack frame containing the user registers is

Index: src/sys/arch/x86/x86/sys_machdep.c
diff -u src/sys/arch/x86/x86/sys_machdep.c:1.31 src/sys/arch/x86/x86/sys_machdep.c:1.32
--- src/sys/arch/x86/x86/sys_machdep.c:1.31	Sun Feb  5 10:42:21 2017
+++ src/sys/arch/x86/x86/sys_machdep.c	Tue Feb 14 09:11:05 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_machdep.c,v 1.31 2017/02/05 10:42:21 maxv Exp $	*/
+/*	$NetBSD: sys_machdep.c,v 1.32 2017/02/14 09:11:05 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2007, 2009 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.31 2017/02/05 10:42:21 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.32 2017/02/14 09:11:05 maxv Exp $");
 
 #include "opt_mtrr.h"
 #include "opt_perfctrs.h"
@@ -68,8 +68,23 @@ __KERNEL_RCSID(0, "$NetBSD: sys_machdep.
 #include <machine/mtrr.h>
 
 #ifdef __x86_64__
-/* Need to be checked. */
+/*
+ * The code for USER_LDT on amd64 is mostly functional, but it is still not
+ * enabled.
+ *
+ * On amd64 we are allowing only 8-byte-sized entries in the LDT, and we are
+ * not allowing the user to overwrite the existing entries (below LDT_SIZE).
+ * Note that USER_LDT is used only by 32bit applications, under compat_netbsd32.
+ * This is theoretically enough for Wine to work.
+ *
+ * However, letting segment registers have different location breaks amd64's
+ * Thread Local Storage: %fs and %gs must be reloaded when returning to
+ * userland. See the tech-kern@ archive from February 2017. A patch has been
+ * proposed to fix that, but Wine still randomly crashes; it is not clear
+ * whether the issues come from Wine, from netbsd32 or from the patch itself.
+ */
 #undef	USER_LDT
+/* Need to be checked. */
 #undef	PERFCTRS
 #undef	IOPERM
 #else
@@ -168,14 +183,23 @@ x86_get_ldt1(struct lwp *l, struct x86_g
 	    ua->start + ua->num > 8192)
 		return (EINVAL);
 
+#ifdef __x86_64__
+	if (ua->start * sizeof(union descriptor) < LDT_SIZE)
+		return EINVAL;
+#endif
+
 	mutex_enter(&cpu_lock);
 
 	if (pmap->pm_ldt != NULL) {
 		nldt = pmap->pm_ldt_len / sizeof(*lp);
 		lp = pmap->pm_ldt;
 	} else {
+#ifdef __x86_64__
+		nldt = LDT_SIZE / sizeof(*lp);
+#else
 		nldt = NLDT;
-		lp = ldtstore;
+#endif
+		lp = (union descriptor *)ldtstore;
 	}
 
 	if (ua->start > nldt) {
@@ -244,6 +268,12 @@ x86_set_ldt1(struct lwp *l, struct x86_s
 	size_t old_len, new_len;
 	union descriptor *old_ldt, *new_ldt;
 
+#ifdef __x86_64__
+	const size_t min_ldt_size = LDT_SIZE;
+#else
+	const size_t min_ldt_size = NLDT * sizeof(union descriptor);
+#endif
+
 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_SET,
 	    NULL, NULL, NULL, NULL);
 	if (error)
@@ -253,6 +283,11 @@ x86_set_ldt1(struct lwp *l, struct x86_s
 	    ua->start + ua->num > 8192)
 		return (EINVAL);
 
+#ifdef __x86_64__
+	if (ua->start * sizeof(union descriptor) < LDT_SIZE)
+		return EINVAL;
+#endif
+
 	/* Check descriptors for access violations. */
 	for (i = 0; i < ua->num; i++) {
 		union descriptor *desc = &descv[i];
@@ -261,6 +296,12 @@ x86_set_ldt1(struct lwp *l, struct x86_s
 		case SDT_SYSNULL:
 			desc->sd.sd_p = 0;
 			break;
+#ifdef __x86_64__
+		case SDT_SYS286CGT:
+		case SDT_SYS386CGT:
+			/* We don't allow these on amd64. */
+			return EACCES;
+#else
 		case SDT_SYS286CGT:
 		case SDT_SYS386CGT:
 			/*
@@ -277,6 +318,7 @@ x86_set_ldt1(struct lwp *l, struct x86_s
 				return EACCES;
 			}
 			break;
+#endif
 		case SDT_MEMEC:
 		case SDT_MEMEAC:
 		case SDT_MEMERC:
@@ -324,7 +366,7 @@ x86_set_ldt1(struct lwp *l, struct x86_s
 	for (;;) {
 		new_len = (ua->start + ua->num) * sizeof(union descriptor);
 		new_len = max(new_len, pmap->pm_ldt_len);
-		new_len = max(new_len, NLDT * sizeof(union descriptor));
+		new_len = max(new_len, min_ldt_size);
 		new_len = round_page(new_len);
 		new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
 		    new_len, 0, UVM_KMF_WIRED | UVM_KMF_ZERO | UVM_KMF_WAITVA);
@@ -347,7 +389,7 @@ x86_set_ldt1(struct lwp *l, struct x86_s
 		old_ldt = NULL;
 		old_len = 0;
 		old_sel = -1;
-		memcpy(new_ldt, ldtstore, NLDT * sizeof(union descriptor));
+		memcpy(new_ldt, ldtstore, min_ldt_size);
 	}
 
 	/* Apply requested changes. */
@@ -768,6 +810,10 @@ sys_sysarch(struct lwp *l, const struct 
 		error = x86_iopl(l, SCARG(uap, parms), retval);
 		break;
 
+#ifdef i386
+	/*
+	 * On amd64, this is done via netbsd32_sysarch.
+	 */
 	case X86_GET_LDT: 
 		error = x86_get_ldt(l, SCARG(uap, parms), retval);
 		break;
@@ -775,6 +821,7 @@ sys_sysarch(struct lwp *l, const struct 
 	case X86_SET_LDT: 
 		error = x86_set_ldt(l, SCARG(uap, parms), retval);
 		break;
+#endif
 
 	case X86_GET_IOPERM: 
 		error = x86_get_ioperm(l, SCARG(uap, parms), retval);

Reply via email to