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