From da59a31c010d611a4ce90a96c378773f56d9a35a Mon Sep 17 00:00:00 2001
From: David Greenman <dg@FreeBSD.org>
Date: Mon, 31 Jan 1994 10:27:13 +0000
Subject: [PATCH]   WINE/user LDT support from John Brezak, ported to FreeBSD
 by Jeffrey Hsu <hsu@soda.berkeley.edu>.

---
 sys/amd64/amd64/cpu_switch.S  |  17 ++-
 sys/amd64/amd64/machdep.c     |  90 +++++++-------
 sys/amd64/amd64/swtch.s       |  17 ++-
 sys/amd64/amd64/sys_machdep.c | 223 +++++++++++++++++++++++++++++++++-
 sys/amd64/include/frame.h     |   5 +-
 sys/amd64/include/reg.h       |   4 +-
 sys/amd64/include/segments.h  |  42 ++++++-
 sys/conf/NOTES                |   4 +-
 sys/i386/conf/LINT            |   4 +-
 sys/i386/conf/NOTES           |   4 +-
 sys/i386/i386/machdep.c       |  90 +++++++-------
 sys/i386/i386/swtch.s         |  17 ++-
 sys/i386/i386/sys_machdep.c   | 223 +++++++++++++++++++++++++++++++++-
 sys/i386/include/frame.h      |   5 +-
 sys/i386/include/reg.h        |   4 +-
 sys/i386/include/segments.h   |  42 ++++++-
 16 files changed, 679 insertions(+), 112 deletions(-)

diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index 731359e63dac..ab5cb7a46b92 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: swtch.s,v 1.2 1994/01/14 16:23:40 davidg Exp $
+ *	$Id: swtch.s,v 1.3 1994/01/17 09:32:27 davidg Exp $
  */
 
 #include "npx.h"	/* for NNPX */
@@ -273,6 +273,21 @@ swfnd:
 	movl	%ecx,_curproc			/* into next process */
 	movl	%edx,_curpcb
 
+#ifdef	USER_LDT
+	cmpl	$0, PCB_USERLDT(%edx)
+	jnz	1f
+	movl	__default_ldt,%eax
+	cmpl	_currentldt,%eax
+	je	2f
+	lldt	__default_ldt
+	movl	%eax,_currentldt
+	jmp	2f
+1:	pushl	%edx
+	call	_set_user_ldt
+	popl	%edx
+2:
+#endif
+
 	pushl	%edx				/* save p to return */
 /*
  * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 2ed621715182..ea319162baaf 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)machdep.c	7.4 (Berkeley) 6/3/91
- *	$Id: machdep.c,v 1.29 1994/01/21 09:56:05 davidg Exp $
+ *	$Id: machdep.c,v 1.30 1994/01/31 04:18:32 davidg Exp $
  */
 
 #include "npx.h"
@@ -453,9 +453,17 @@ sendsig(catcher, sig, mask, code)
 	fp->sf_handler = catcher;
 
 	/* save scratch registers */
-	fp->sf_eax = regs[tEAX];
-	fp->sf_edx = regs[tEDX];
-	fp->sf_ecx = regs[tECX];
+	fp->sf_sc.sc_eax = regs[tEAX];
+	fp->sf_sc.sc_ebx = regs[tEBX];
+	fp->sf_sc.sc_ecx = regs[tECX];
+	fp->sf_sc.sc_edx = regs[tEDX];
+	fp->sf_sc.sc_esi = regs[tESI];
+	fp->sf_sc.sc_edi = regs[tEDI];
+	fp->sf_sc.sc_cs = regs[tCS];
+	fp->sf_sc.sc_ds = regs[tDS];
+	fp->sf_sc.sc_ss = regs[tSS];
+	fp->sf_sc.sc_es = regs[tES];
+	fp->sf_sc.sc_isp = regs[tISP];
 
 	/*
 	 * Build the signal context to be used by sigreturn.
@@ -508,9 +516,17 @@ sigreturn(p, uap, retval)
 		return(EINVAL);
 
 	/* restore scratch registers */
-	regs[tEAX] = fp->sf_eax ;
-	regs[tEDX] = fp->sf_edx ;
-	regs[tECX] = fp->sf_ecx ;
+	regs[tEAX] = scp->sc_eax;
+	regs[tEBX] = scp->sc_ebx;
+	regs[tECX] = scp->sc_ecx;
+	regs[tEDX] = scp->sc_edx;
+	regs[tESI] = scp->sc_esi;
+	regs[tEDI] = scp->sc_edi;
+	regs[tCS] = scp->sc_cs;
+	regs[tDS] = scp->sc_ds;
+	regs[tES] = scp->sc_es;
+	regs[tSS] = scp->sc_ss;
+	regs[tISP] = scp->sc_isp;
 
 	if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
 		return(EINVAL);
@@ -765,32 +781,12 @@ setregs(p, entry, stack)
 /*
  * Initialize segments & interrupt table
  */
-#define DESCRIPTOR_SIZE	8
 
-#define	GNULL_SEL	0	/* Null Descriptor */
-#define	GCODE_SEL	1	/* Kernel Code Descriptor */
-#define	GDATA_SEL	2	/* Kernel Data Descriptor */
-#define	GLDT_SEL	3	/* LDT - eventually one per process */
-#define	GTGATE_SEL	4	/* Process task switch gate */
-#define	GPANIC_SEL	5	/* Task state to consider panic from */
-#define	GPROC0_SEL	6	/* Task state process slot zero and up */
-#define NGDT 	GPROC0_SEL+1
+union descriptor gdt[NGDT];
+union descriptor ldt[NLDT];		/* local descriptor table */
+struct gate_descriptor idt[NIDT];	/* interrupt descriptor table */
 
-unsigned char gdt[GPROC0_SEL+1][DESCRIPTOR_SIZE];
-
-/* interrupt descriptor table */
-struct gate_descriptor idt[NIDT];
-
-/* local descriptor table */
-unsigned char ldt[5][DESCRIPTOR_SIZE];
-#define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
-#define	LSYS5SIGR_SEL	1
-
-#define	L43BSDCALLS_SEL	2	/* notyet */
-#define	LUCODE_SEL	3
-#define	LUDATA_SEL	4
-/* seperate stack, es,fs,gs sels ? */
-/* #define	LPOSIXCALLS_SEL	5*/	/* notyet */
+int _default_ldt, currentldt;
 
 struct	i386tss	tss, panic_tss;
 
@@ -860,7 +856,17 @@ struct soft_segment_descriptor gdt_segs[] = {
 	1,			/* segment descriptor present */
 	0, 0,
 	0,			/* unused - default 32 vs 16 bit size */
-	0  			/* limit granularity (byte/page units)*/ }};
+	0  			/* limit granularity (byte/page units)*/ },
+	/* User LDT Descriptor per process */
+{	(int) ldt,			/* segment base address  */
+	(512 * sizeof(union descriptor)-1),		/* length */
+	SDT_SYSLDT,		/* segment type */
+	0,			/* segment descriptor priority level */
+	1,			/* segment descriptor present */
+	0, 0,
+	0,			/* unused - default 32 vs 16 bit size */
+	0  			/* limit granularity (byte/page units)*/ },
+};
 
 struct soft_segment_descriptor ldt_segs[] = {
 	/* Null Descriptor - overwritten by call gate */
@@ -953,7 +959,7 @@ init386(first)
 	struct gate_descriptor *gdp;
 	extern int sigcode,szsigcode;
 	/* table descriptors - used to load tables by microp */
-	unsigned short	r_gdt[3], r_idt[3];
+	struct region_descriptor r_gdt, r_idt;
 	int	pagesinbase, pagesinext;
 
 
@@ -1036,15 +1042,15 @@ init386(first)
 	isa_defaultirq();
 #endif
 
-	r_gdt[0] = (unsigned short) (sizeof(gdt) - 1);
-	r_gdt[1] = (unsigned short) ((int) gdt & 0xffff);
-	r_gdt[2] = (unsigned short) ((int) gdt >> 16);
+	r_gdt.rd_limit = sizeof(gdt) - 1;
+	r_gdt.rd_base =  (int) gdt;
 	lgdt(&r_gdt);
-	r_idt[0] = (unsigned short) (sizeof(idt) - 1);
-	r_idt[1] = (unsigned short) ((int) idt & 0xfffff);
-	r_idt[2] = (unsigned short) ((int) idt >> 16);
+	r_idt.rd_limit = sizeof(idt) - 1;
+	r_idt.rd_base = (int) idt;
 	lidt(&r_idt);
-	lldt(GSEL(GLDT_SEL, SEL_KPL));
+	_default_ldt = GSEL(GLDT_SEL, SEL_KPL);
+	lldt(_default_ldt);
+	currentldt = _default_ldt;
 
 #include "ddb.h"
 #if NDDB > 0
@@ -1145,8 +1151,8 @@ init386(first)
 	ltr(_gsel_tss);
 
 	/* make a call gate to reenter kernel with */
-	gdp = (struct gate_descriptor *) &ldt[LSYS5CALLS_SEL][0];
-	
+	gdp = &ldt[LSYS5CALLS_SEL].gd;
+
 	x = (int) &IDTVEC(syscall);
 	gdp->gd_looffset = x++;
 	gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
diff --git a/sys/amd64/amd64/swtch.s b/sys/amd64/amd64/swtch.s
index 731359e63dac..ab5cb7a46b92 100644
--- a/sys/amd64/amd64/swtch.s
+++ b/sys/amd64/amd64/swtch.s
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: swtch.s,v 1.2 1994/01/14 16:23:40 davidg Exp $
+ *	$Id: swtch.s,v 1.3 1994/01/17 09:32:27 davidg Exp $
  */
 
 #include "npx.h"	/* for NNPX */
@@ -273,6 +273,21 @@ swfnd:
 	movl	%ecx,_curproc			/* into next process */
 	movl	%edx,_curpcb
 
+#ifdef	USER_LDT
+	cmpl	$0, PCB_USERLDT(%edx)
+	jnz	1f
+	movl	__default_ldt,%eax
+	cmpl	_currentldt,%eax
+	je	2f
+	lldt	__default_ldt
+	movl	%eax,_currentldt
+	jmp	2f
+1:	pushl	%edx
+	call	_set_user_ldt
+	popl	%edx
+2:
+#endif
+
 	pushl	%edx				/* save p to return */
 /*
  * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c
index 2b63cee6fb13..92758ad8481a 100644
--- a/sys/amd64/amd64/sys_machdep.c
+++ b/sys/amd64/amd64/sys_machdep.c
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)sys_machdep.c	5.5 (Berkeley) 1/19/91
- *	$Id$
+ *	$Id: sys_machdep.c,v 1.3 1993/10/16 14:15:10 rgrimes Exp $
  */
 
 #include "param.h"
@@ -49,6 +49,13 @@
 #include "buf.h"
 #include "trace.h"
 
+#ifdef USER_LDT
+#include "user.h"
+#include "machine/cpu.h"
+#include "machine/sysarch.h"
+#include "vm/vm_kern.h"		/* for kernel_map */
+#endif
+
 #ifdef TRACE
 int	nvualarm;
 
@@ -105,3 +112,217 @@ vdoualarm(arg)
 	nvualarm--;
 }
 #endif
+
+#ifdef USER_LDT
+void
+set_user_ldt(struct pcb *pcb)
+{
+	gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt;
+	gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1;
+	ssdtosd(gdt_segs+GUSERLDT_SEL, gdt+GUSERLDT_SEL);
+	lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
+	currentldt = GSEL(GUSERLDT_SEL, SEL_KPL);
+}
+
+struct i386_get_ldt_args {
+	int start;
+	union descriptor *desc;
+	int num;
+};
+
+int
+i386_get_ldt(p, args, retval)
+	struct proc *p;
+	char *args;
+	int *retval;
+{
+	int error = 0;
+	struct pcb *pcb = &p->p_addr->u_pcb;
+	int nldt, num;
+	union descriptor *lp;
+	int s;
+	struct i386_get_ldt_args ua, *uap;
+
+	if ((error = copyin(args, &ua, sizeof(struct i386_get_ldt_args))) < 0)
+		return(error);
+
+	uap = &ua;
+#ifdef	DEBUG
+	printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+	if (uap->start < 0 || uap->num < 0)
+		return(EINVAL);
+
+	s = splhigh();
+
+	if (pcb->pcb_ldt) {
+		nldt = pcb->pcb_ldt_len;
+		num = min(uap->num, nldt);
+		lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start];
+	} else {
+		nldt = sizeof(ldt)/sizeof(ldt[0]);
+		num = min(uap->num, nldt);
+		lp = &ldt[uap->start];
+	}
+	if (uap->start > nldt) {
+		splx(s);
+		return(EINVAL);
+	}
+
+	error = copyout(lp, uap->desc, num * sizeof(union descriptor));
+	if (!error)
+		*retval = num;
+
+	splx(s);
+	return(error);
+}
+
+struct i386_set_ldt_args {
+	int start;
+	union descriptor *desc;
+	int num;
+};
+
+int
+i386_set_ldt(p, args, retval)
+	struct proc *p;
+	char *args;
+	int *retval;
+{
+	int error = 0, i, n;
+	struct pcb *pcb = &p->p_addr->u_pcb;
+	union descriptor *lp;
+	int s;
+	struct i386_set_ldt_args ua, *uap;
+
+	if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0)
+		return(error);
+
+	uap = &ua;
+
+#ifdef	DEBUG
+	printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+	if (uap->start < 0 || uap->num < 0)
+		return(EINVAL);
+
+	/* XXX Should be 8192 ! */
+	if (uap->start > 512 ||
+	    (uap->start + uap->num) > 512)
+		return(EINVAL);
+
+	/* allocate user ldt */
+	if (!pcb->pcb_ldt) {
+		union descriptor *new_ldt =
+			(union descriptor *)kmem_alloc(kernel_map, 512*sizeof(union descriptor));
+		bzero(new_ldt, 512*sizeof(union descriptor));
+		bcopy(ldt, new_ldt, sizeof(ldt));
+		pcb->pcb_ldt = (caddr_t)new_ldt;
+		pcb->pcb_ldt_len = 512;		/* XXX need to grow */
+#ifdef DEBUG
+		printf("i386_set_ldt(%d): new_ldt=%x\n", p->p_pid, new_ldt);
+#endif
+	}
+
+	/* Check descriptors for access violations */
+	for (i = 0, n = uap->start; i < uap->num; i++, n++) {
+		union descriptor desc, *dp;
+		dp = &uap->desc[i];
+		error = copyin(dp, &desc, sizeof(union descriptor));
+		if (error)
+			return(error);
+
+		/* Only user (ring-3) descriptors */
+		if (desc.sd.sd_dpl != SEL_UPL)
+			return(EACCES);
+
+		/* Must be "present" */
+		if (desc.sd.sd_p == 0)
+			return(EACCES);
+
+		switch (desc.sd.sd_type) {
+		case SDT_SYSNULL:
+		case SDT_SYS286CGT:
+		case SDT_SYS386CGT:
+			break;
+		case SDT_MEMRO:
+		case SDT_MEMROA:
+		case SDT_MEMRW:
+		case SDT_MEMRWA:
+		case SDT_MEMROD:
+		case SDT_MEMRODA:
+		case SDT_MEME:
+		case SDT_MEMEA:
+		case SDT_MEMER:
+		case SDT_MEMERA:
+		case SDT_MEMEC:
+		case SDT_MEMEAC:
+		case SDT_MEMERC:
+		case SDT_MEMERAC: {
+#if 0
+			unsigned long base = (desc.sd.sd_hibase << 24)&0xFF000000;
+			base |= (desc.sd.sd_lobase&0x00FFFFFF);
+			if (base >= KERNBASE)
+				return(EACCES);
+#endif
+			break;
+		}
+		default:
+			return(EACCES);
+			/*NOTREACHED*/
+		}
+	}
+
+	s = splhigh();
+
+	/* Fill in range */
+	for (i = 0, n = uap->start; i < uap->num && !error; i++, n++) {
+		union descriptor desc, *dp;
+		dp = &uap->desc[i];
+		lp = &((union descriptor *)(pcb->pcb_ldt))[n];
+#ifdef DEBUG
+		printf("i386_set_ldt(%d): ldtp=%x\n", p->p_pid, lp);
+#endif
+		error = copyin(dp, lp, sizeof(union descriptor));
+	}
+	if (!error) {
+		*retval = uap->start;
+/*		need_resched(); */
+	}
+
+	splx(s);
+	return(error);
+}
+#endif	/* USER_LDT */
+
+struct sysarch_args {
+	int op;
+	char *parms;
+};
+
+int
+sysarch(p, uap, retval)
+	struct proc *p;
+	register struct sysarch_args *uap;
+	int *retval;
+{
+	int error = 0;
+
+	switch(uap->op) {
+#ifdef	USER_LDT
+	case I386_GET_LDT: 
+		error = i386_get_ldt(p, uap->parms, retval);
+		break;
+
+	case I386_SET_LDT: 
+		error = i386_set_ldt(p, uap->parms, retval);
+		break;
+#endif
+	default:
+		error = EINVAL;
+		break;
+	}
+	return(error);
+}
diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h
index b36c141e7f83..05bf26504620 100644
--- a/sys/amd64/include/frame.h
+++ b/sys/amd64/include/frame.h
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)frame.h	5.2 (Berkeley) 1/18/91
- *	$Id: frame.h,v 1.6 1993/12/19 00:50:15 wollman Exp $
+ *	$Id: frame.h,v 1.7 1994/01/03 07:55:32 davidg Exp $
  */
 
 #ifndef _MACHINE_FRAME_H_
@@ -109,9 +109,6 @@ struct sigframe {
 	struct	sigcontext *sf_scp;
 	char	*sf_addr;
 	sig_t	sf_handler;
-	int	sf_eax;	
-	int	sf_edx;	
-	int	sf_ecx;	
 	struct	sigcontext sf_sc;
 };
 #endif /* _MACHINE_FRAME_H_ */
diff --git a/sys/amd64/include/reg.h b/sys/amd64/include/reg.h
index 4cefae0e1305..d20f8d0c85e1 100644
--- a/sys/amd64/include/reg.h
+++ b/sys/amd64/include/reg.h
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)reg.h	5.5 (Berkeley) 1/18/91
- *	$Id: reg.h,v 1.5 1993/12/03 05:10:08 alm Exp $
+ *	$Id: reg.h,v 1.6 1994/01/03 07:55:34 davidg Exp $
  */
 
 #ifndef _MACHINE_REG_H_
@@ -54,7 +54,7 @@
 #define	tEDI	(2)
 #define	tESI	(3)
 #define	tEBP	(4)
-
+#define	tISP	(5)
 #define	tEBX	(6)
 #define	tEDX	(7)
 #define	tECX	(8)
diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h
index a7ed23442fc5..023a0cfd3216 100644
--- a/sys/amd64/include/segments.h
+++ b/sys/amd64/include/segments.h
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)segments.h	7.1 (Berkeley) 5/9/91
- *	$Id: segments.h,v 1.2 1993/10/16 14:39:30 rgrimes Exp $
+ *	$Id: segments.h,v 1.3 1993/11/07 17:43:08 wollman Exp $
  */
 
 #ifndef _MACHINE_SEGMENTS_H_
@@ -64,7 +64,8 @@
  */
 struct	segment_descriptor	{
 	unsigned sd_lolimit:16 ;	/* segment extent (lsb) */
-	unsigned sd_lobase:24 ;		/* segment base address (lsb) */
+	unsigned sd_lobase:24 __attribute__ ((packed));
+					/* segment base address (lsb) */
 	unsigned sd_type:5 ;		/* segment type */
 	unsigned sd_dpl:2 ;		/* segment descriptor priority level */
 	unsigned sd_p:1 ;		/* segment descriptor present */
@@ -178,8 +179,8 @@ extern sdtossd() ;	/* to encode a sd */
  * region descriptors, used to load gdt/idt tables before segments yet exist.
  */
 struct region_descriptor {
-	unsigned rd_limit:16;		/* segment extent */
-	unsigned rd_base:32;		/* base address  */
+	unsigned rd_limit:16;				/* segment extent */
+	unsigned rd_base:32 __attribute__ ((packed));	/* base address  */
 };
 
 /*
@@ -198,4 +199,37 @@ struct region_descriptor {
 
 #define	NIDT	256
 #define	NRSVIDT	32		/* reserved entries for cpu exceptions */
+
+/*
+ * Entries in the Global Descriptor Table (GDT)
+ */
+#define	GNULL_SEL	0	/* Null Descriptor */
+#define	GCODE_SEL	1	/* Kernel Code Descriptor */
+#define	GDATA_SEL	2	/* Kernel Data Descriptor */
+#define	GLDT_SEL	3	/* LDT - eventually one per process */
+#define	GTGATE_SEL	4	/* Process task switch gate */
+#define	GPANIC_SEL	5	/* Task state to consider panic from */
+#define	GPROC0_SEL	6	/* Task state process slot zero and up */
+#define	GUSERLDT_SEL	7	/* User LDT */
+#define NGDT 	GUSERLDT_SEL+1
+
+/*
+ * Entries in the Local Descriptor Table (LDT)
+ */
+#define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
+#define	LSYS5SIGR_SEL	1
+#define	L43BSDCALLS_SEL	2	/* notyet */
+#define	LUCODE_SEL	3
+#define	LUDATA_SEL	4
+/* seperate stack, es,fs,gs sels ? */
+/* #define	LPOSIXCALLS_SEL	5*/	/* notyet */
+#define NLDT		LUDATA_SEL+1
+
+#ifdef KERNEL
+extern int currentldt;
+extern union descriptor gdt[NGDT];
+extern union descriptor ldt[NLDT];
+extern struct soft_segment_descriptor gdt_segs[];
+#endif
+
 #endif /* _MACHINE_SEGMENTS_H_ */
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 67f620e498b0..9635d0eb3d7b 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -4,7 +4,7 @@
 #
 #	This kernel is NOT MEANT to be runnable!
 #
-#	$Id: LINT,v 1.47 1994/01/29 03:17:39 ache Exp $
+#	$Id: LINT,v 1.48 1994/01/29 21:41:36 rgrimes Exp $
 #
 
 machine		"i386"
@@ -55,6 +55,8 @@ options		"EXCLUDE_MPU401"	#  \ exclude specified
 options		EXCLUDE_GUS		#  / device or chip
 options		EXCLUDE_SBPRO		# /  from driver
 
+options		USER_LDT		#allow user-level control of i386 ldt
+
 #
 # options that are in sys/conf/files
 #
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 67f620e498b0..9635d0eb3d7b 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -4,7 +4,7 @@
 #
 #	This kernel is NOT MEANT to be runnable!
 #
-#	$Id: LINT,v 1.47 1994/01/29 03:17:39 ache Exp $
+#	$Id: LINT,v 1.48 1994/01/29 21:41:36 rgrimes Exp $
 #
 
 machine		"i386"
@@ -55,6 +55,8 @@ options		"EXCLUDE_MPU401"	#  \ exclude specified
 options		EXCLUDE_GUS		#  / device or chip
 options		EXCLUDE_SBPRO		# /  from driver
 
+options		USER_LDT		#allow user-level control of i386 ldt
+
 #
 # options that are in sys/conf/files
 #
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 67f620e498b0..9635d0eb3d7b 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -4,7 +4,7 @@
 #
 #	This kernel is NOT MEANT to be runnable!
 #
-#	$Id: LINT,v 1.47 1994/01/29 03:17:39 ache Exp $
+#	$Id: LINT,v 1.48 1994/01/29 21:41:36 rgrimes Exp $
 #
 
 machine		"i386"
@@ -55,6 +55,8 @@ options		"EXCLUDE_MPU401"	#  \ exclude specified
 options		EXCLUDE_GUS		#  / device or chip
 options		EXCLUDE_SBPRO		# /  from driver
 
+options		USER_LDT		#allow user-level control of i386 ldt
+
 #
 # options that are in sys/conf/files
 #
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 2ed621715182..ea319162baaf 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)machdep.c	7.4 (Berkeley) 6/3/91
- *	$Id: machdep.c,v 1.29 1994/01/21 09:56:05 davidg Exp $
+ *	$Id: machdep.c,v 1.30 1994/01/31 04:18:32 davidg Exp $
  */
 
 #include "npx.h"
@@ -453,9 +453,17 @@ sendsig(catcher, sig, mask, code)
 	fp->sf_handler = catcher;
 
 	/* save scratch registers */
-	fp->sf_eax = regs[tEAX];
-	fp->sf_edx = regs[tEDX];
-	fp->sf_ecx = regs[tECX];
+	fp->sf_sc.sc_eax = regs[tEAX];
+	fp->sf_sc.sc_ebx = regs[tEBX];
+	fp->sf_sc.sc_ecx = regs[tECX];
+	fp->sf_sc.sc_edx = regs[tEDX];
+	fp->sf_sc.sc_esi = regs[tESI];
+	fp->sf_sc.sc_edi = regs[tEDI];
+	fp->sf_sc.sc_cs = regs[tCS];
+	fp->sf_sc.sc_ds = regs[tDS];
+	fp->sf_sc.sc_ss = regs[tSS];
+	fp->sf_sc.sc_es = regs[tES];
+	fp->sf_sc.sc_isp = regs[tISP];
 
 	/*
 	 * Build the signal context to be used by sigreturn.
@@ -508,9 +516,17 @@ sigreturn(p, uap, retval)
 		return(EINVAL);
 
 	/* restore scratch registers */
-	regs[tEAX] = fp->sf_eax ;
-	regs[tEDX] = fp->sf_edx ;
-	regs[tECX] = fp->sf_ecx ;
+	regs[tEAX] = scp->sc_eax;
+	regs[tEBX] = scp->sc_ebx;
+	regs[tECX] = scp->sc_ecx;
+	regs[tEDX] = scp->sc_edx;
+	regs[tESI] = scp->sc_esi;
+	regs[tEDI] = scp->sc_edi;
+	regs[tCS] = scp->sc_cs;
+	regs[tDS] = scp->sc_ds;
+	regs[tES] = scp->sc_es;
+	regs[tSS] = scp->sc_ss;
+	regs[tISP] = scp->sc_isp;
 
 	if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
 		return(EINVAL);
@@ -765,32 +781,12 @@ setregs(p, entry, stack)
 /*
  * Initialize segments & interrupt table
  */
-#define DESCRIPTOR_SIZE	8
 
-#define	GNULL_SEL	0	/* Null Descriptor */
-#define	GCODE_SEL	1	/* Kernel Code Descriptor */
-#define	GDATA_SEL	2	/* Kernel Data Descriptor */
-#define	GLDT_SEL	3	/* LDT - eventually one per process */
-#define	GTGATE_SEL	4	/* Process task switch gate */
-#define	GPANIC_SEL	5	/* Task state to consider panic from */
-#define	GPROC0_SEL	6	/* Task state process slot zero and up */
-#define NGDT 	GPROC0_SEL+1
+union descriptor gdt[NGDT];
+union descriptor ldt[NLDT];		/* local descriptor table */
+struct gate_descriptor idt[NIDT];	/* interrupt descriptor table */
 
-unsigned char gdt[GPROC0_SEL+1][DESCRIPTOR_SIZE];
-
-/* interrupt descriptor table */
-struct gate_descriptor idt[NIDT];
-
-/* local descriptor table */
-unsigned char ldt[5][DESCRIPTOR_SIZE];
-#define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
-#define	LSYS5SIGR_SEL	1
-
-#define	L43BSDCALLS_SEL	2	/* notyet */
-#define	LUCODE_SEL	3
-#define	LUDATA_SEL	4
-/* seperate stack, es,fs,gs sels ? */
-/* #define	LPOSIXCALLS_SEL	5*/	/* notyet */
+int _default_ldt, currentldt;
 
 struct	i386tss	tss, panic_tss;
 
@@ -860,7 +856,17 @@ struct soft_segment_descriptor gdt_segs[] = {
 	1,			/* segment descriptor present */
 	0, 0,
 	0,			/* unused - default 32 vs 16 bit size */
-	0  			/* limit granularity (byte/page units)*/ }};
+	0  			/* limit granularity (byte/page units)*/ },
+	/* User LDT Descriptor per process */
+{	(int) ldt,			/* segment base address  */
+	(512 * sizeof(union descriptor)-1),		/* length */
+	SDT_SYSLDT,		/* segment type */
+	0,			/* segment descriptor priority level */
+	1,			/* segment descriptor present */
+	0, 0,
+	0,			/* unused - default 32 vs 16 bit size */
+	0  			/* limit granularity (byte/page units)*/ },
+};
 
 struct soft_segment_descriptor ldt_segs[] = {
 	/* Null Descriptor - overwritten by call gate */
@@ -953,7 +959,7 @@ init386(first)
 	struct gate_descriptor *gdp;
 	extern int sigcode,szsigcode;
 	/* table descriptors - used to load tables by microp */
-	unsigned short	r_gdt[3], r_idt[3];
+	struct region_descriptor r_gdt, r_idt;
 	int	pagesinbase, pagesinext;
 
 
@@ -1036,15 +1042,15 @@ init386(first)
 	isa_defaultirq();
 #endif
 
-	r_gdt[0] = (unsigned short) (sizeof(gdt) - 1);
-	r_gdt[1] = (unsigned short) ((int) gdt & 0xffff);
-	r_gdt[2] = (unsigned short) ((int) gdt >> 16);
+	r_gdt.rd_limit = sizeof(gdt) - 1;
+	r_gdt.rd_base =  (int) gdt;
 	lgdt(&r_gdt);
-	r_idt[0] = (unsigned short) (sizeof(idt) - 1);
-	r_idt[1] = (unsigned short) ((int) idt & 0xfffff);
-	r_idt[2] = (unsigned short) ((int) idt >> 16);
+	r_idt.rd_limit = sizeof(idt) - 1;
+	r_idt.rd_base = (int) idt;
 	lidt(&r_idt);
-	lldt(GSEL(GLDT_SEL, SEL_KPL));
+	_default_ldt = GSEL(GLDT_SEL, SEL_KPL);
+	lldt(_default_ldt);
+	currentldt = _default_ldt;
 
 #include "ddb.h"
 #if NDDB > 0
@@ -1145,8 +1151,8 @@ init386(first)
 	ltr(_gsel_tss);
 
 	/* make a call gate to reenter kernel with */
-	gdp = (struct gate_descriptor *) &ldt[LSYS5CALLS_SEL][0];
-	
+	gdp = &ldt[LSYS5CALLS_SEL].gd;
+
 	x = (int) &IDTVEC(syscall);
 	gdp->gd_looffset = x++;
 	gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s
index 731359e63dac..ab5cb7a46b92 100644
--- a/sys/i386/i386/swtch.s
+++ b/sys/i386/i386/swtch.s
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: swtch.s,v 1.2 1994/01/14 16:23:40 davidg Exp $
+ *	$Id: swtch.s,v 1.3 1994/01/17 09:32:27 davidg Exp $
  */
 
 #include "npx.h"	/* for NNPX */
@@ -273,6 +273,21 @@ swfnd:
 	movl	%ecx,_curproc			/* into next process */
 	movl	%edx,_curpcb
 
+#ifdef	USER_LDT
+	cmpl	$0, PCB_USERLDT(%edx)
+	jnz	1f
+	movl	__default_ldt,%eax
+	cmpl	_currentldt,%eax
+	je	2f
+	lldt	__default_ldt
+	movl	%eax,_currentldt
+	jmp	2f
+1:	pushl	%edx
+	call	_set_user_ldt
+	popl	%edx
+2:
+#endif
+
 	pushl	%edx				/* save p to return */
 /*
  * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
index 2b63cee6fb13..92758ad8481a 100644
--- a/sys/i386/i386/sys_machdep.c
+++ b/sys/i386/i386/sys_machdep.c
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)sys_machdep.c	5.5 (Berkeley) 1/19/91
- *	$Id$
+ *	$Id: sys_machdep.c,v 1.3 1993/10/16 14:15:10 rgrimes Exp $
  */
 
 #include "param.h"
@@ -49,6 +49,13 @@
 #include "buf.h"
 #include "trace.h"
 
+#ifdef USER_LDT
+#include "user.h"
+#include "machine/cpu.h"
+#include "machine/sysarch.h"
+#include "vm/vm_kern.h"		/* for kernel_map */
+#endif
+
 #ifdef TRACE
 int	nvualarm;
 
@@ -105,3 +112,217 @@ vdoualarm(arg)
 	nvualarm--;
 }
 #endif
+
+#ifdef USER_LDT
+void
+set_user_ldt(struct pcb *pcb)
+{
+	gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt;
+	gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1;
+	ssdtosd(gdt_segs+GUSERLDT_SEL, gdt+GUSERLDT_SEL);
+	lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
+	currentldt = GSEL(GUSERLDT_SEL, SEL_KPL);
+}
+
+struct i386_get_ldt_args {
+	int start;
+	union descriptor *desc;
+	int num;
+};
+
+int
+i386_get_ldt(p, args, retval)
+	struct proc *p;
+	char *args;
+	int *retval;
+{
+	int error = 0;
+	struct pcb *pcb = &p->p_addr->u_pcb;
+	int nldt, num;
+	union descriptor *lp;
+	int s;
+	struct i386_get_ldt_args ua, *uap;
+
+	if ((error = copyin(args, &ua, sizeof(struct i386_get_ldt_args))) < 0)
+		return(error);
+
+	uap = &ua;
+#ifdef	DEBUG
+	printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+	if (uap->start < 0 || uap->num < 0)
+		return(EINVAL);
+
+	s = splhigh();
+
+	if (pcb->pcb_ldt) {
+		nldt = pcb->pcb_ldt_len;
+		num = min(uap->num, nldt);
+		lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start];
+	} else {
+		nldt = sizeof(ldt)/sizeof(ldt[0]);
+		num = min(uap->num, nldt);
+		lp = &ldt[uap->start];
+	}
+	if (uap->start > nldt) {
+		splx(s);
+		return(EINVAL);
+	}
+
+	error = copyout(lp, uap->desc, num * sizeof(union descriptor));
+	if (!error)
+		*retval = num;
+
+	splx(s);
+	return(error);
+}
+
+struct i386_set_ldt_args {
+	int start;
+	union descriptor *desc;
+	int num;
+};
+
+int
+i386_set_ldt(p, args, retval)
+	struct proc *p;
+	char *args;
+	int *retval;
+{
+	int error = 0, i, n;
+	struct pcb *pcb = &p->p_addr->u_pcb;
+	union descriptor *lp;
+	int s;
+	struct i386_set_ldt_args ua, *uap;
+
+	if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0)
+		return(error);
+
+	uap = &ua;
+
+#ifdef	DEBUG
+	printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+	if (uap->start < 0 || uap->num < 0)
+		return(EINVAL);
+
+	/* XXX Should be 8192 ! */
+	if (uap->start > 512 ||
+	    (uap->start + uap->num) > 512)
+		return(EINVAL);
+
+	/* allocate user ldt */
+	if (!pcb->pcb_ldt) {
+		union descriptor *new_ldt =
+			(union descriptor *)kmem_alloc(kernel_map, 512*sizeof(union descriptor));
+		bzero(new_ldt, 512*sizeof(union descriptor));
+		bcopy(ldt, new_ldt, sizeof(ldt));
+		pcb->pcb_ldt = (caddr_t)new_ldt;
+		pcb->pcb_ldt_len = 512;		/* XXX need to grow */
+#ifdef DEBUG
+		printf("i386_set_ldt(%d): new_ldt=%x\n", p->p_pid, new_ldt);
+#endif
+	}
+
+	/* Check descriptors for access violations */
+	for (i = 0, n = uap->start; i < uap->num; i++, n++) {
+		union descriptor desc, *dp;
+		dp = &uap->desc[i];
+		error = copyin(dp, &desc, sizeof(union descriptor));
+		if (error)
+			return(error);
+
+		/* Only user (ring-3) descriptors */
+		if (desc.sd.sd_dpl != SEL_UPL)
+			return(EACCES);
+
+		/* Must be "present" */
+		if (desc.sd.sd_p == 0)
+			return(EACCES);
+
+		switch (desc.sd.sd_type) {
+		case SDT_SYSNULL:
+		case SDT_SYS286CGT:
+		case SDT_SYS386CGT:
+			break;
+		case SDT_MEMRO:
+		case SDT_MEMROA:
+		case SDT_MEMRW:
+		case SDT_MEMRWA:
+		case SDT_MEMROD:
+		case SDT_MEMRODA:
+		case SDT_MEME:
+		case SDT_MEMEA:
+		case SDT_MEMER:
+		case SDT_MEMERA:
+		case SDT_MEMEC:
+		case SDT_MEMEAC:
+		case SDT_MEMERC:
+		case SDT_MEMERAC: {
+#if 0
+			unsigned long base = (desc.sd.sd_hibase << 24)&0xFF000000;
+			base |= (desc.sd.sd_lobase&0x00FFFFFF);
+			if (base >= KERNBASE)
+				return(EACCES);
+#endif
+			break;
+		}
+		default:
+			return(EACCES);
+			/*NOTREACHED*/
+		}
+	}
+
+	s = splhigh();
+
+	/* Fill in range */
+	for (i = 0, n = uap->start; i < uap->num && !error; i++, n++) {
+		union descriptor desc, *dp;
+		dp = &uap->desc[i];
+		lp = &((union descriptor *)(pcb->pcb_ldt))[n];
+#ifdef DEBUG
+		printf("i386_set_ldt(%d): ldtp=%x\n", p->p_pid, lp);
+#endif
+		error = copyin(dp, lp, sizeof(union descriptor));
+	}
+	if (!error) {
+		*retval = uap->start;
+/*		need_resched(); */
+	}
+
+	splx(s);
+	return(error);
+}
+#endif	/* USER_LDT */
+
+struct sysarch_args {
+	int op;
+	char *parms;
+};
+
+int
+sysarch(p, uap, retval)
+	struct proc *p;
+	register struct sysarch_args *uap;
+	int *retval;
+{
+	int error = 0;
+
+	switch(uap->op) {
+#ifdef	USER_LDT
+	case I386_GET_LDT: 
+		error = i386_get_ldt(p, uap->parms, retval);
+		break;
+
+	case I386_SET_LDT: 
+		error = i386_set_ldt(p, uap->parms, retval);
+		break;
+#endif
+	default:
+		error = EINVAL;
+		break;
+	}
+	return(error);
+}
diff --git a/sys/i386/include/frame.h b/sys/i386/include/frame.h
index b36c141e7f83..05bf26504620 100644
--- a/sys/i386/include/frame.h
+++ b/sys/i386/include/frame.h
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)frame.h	5.2 (Berkeley) 1/18/91
- *	$Id: frame.h,v 1.6 1993/12/19 00:50:15 wollman Exp $
+ *	$Id: frame.h,v 1.7 1994/01/03 07:55:32 davidg Exp $
  */
 
 #ifndef _MACHINE_FRAME_H_
@@ -109,9 +109,6 @@ struct sigframe {
 	struct	sigcontext *sf_scp;
 	char	*sf_addr;
 	sig_t	sf_handler;
-	int	sf_eax;	
-	int	sf_edx;	
-	int	sf_ecx;	
 	struct	sigcontext sf_sc;
 };
 #endif /* _MACHINE_FRAME_H_ */
diff --git a/sys/i386/include/reg.h b/sys/i386/include/reg.h
index 4cefae0e1305..d20f8d0c85e1 100644
--- a/sys/i386/include/reg.h
+++ b/sys/i386/include/reg.h
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)reg.h	5.5 (Berkeley) 1/18/91
- *	$Id: reg.h,v 1.5 1993/12/03 05:10:08 alm Exp $
+ *	$Id: reg.h,v 1.6 1994/01/03 07:55:34 davidg Exp $
  */
 
 #ifndef _MACHINE_REG_H_
@@ -54,7 +54,7 @@
 #define	tEDI	(2)
 #define	tESI	(3)
 #define	tEBP	(4)
-
+#define	tISP	(5)
 #define	tEBX	(6)
 #define	tEDX	(7)
 #define	tECX	(8)
diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h
index a7ed23442fc5..023a0cfd3216 100644
--- a/sys/i386/include/segments.h
+++ b/sys/i386/include/segments.h
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)segments.h	7.1 (Berkeley) 5/9/91
- *	$Id: segments.h,v 1.2 1993/10/16 14:39:30 rgrimes Exp $
+ *	$Id: segments.h,v 1.3 1993/11/07 17:43:08 wollman Exp $
  */
 
 #ifndef _MACHINE_SEGMENTS_H_
@@ -64,7 +64,8 @@
  */
 struct	segment_descriptor	{
 	unsigned sd_lolimit:16 ;	/* segment extent (lsb) */
-	unsigned sd_lobase:24 ;		/* segment base address (lsb) */
+	unsigned sd_lobase:24 __attribute__ ((packed));
+					/* segment base address (lsb) */
 	unsigned sd_type:5 ;		/* segment type */
 	unsigned sd_dpl:2 ;		/* segment descriptor priority level */
 	unsigned sd_p:1 ;		/* segment descriptor present */
@@ -178,8 +179,8 @@ extern sdtossd() ;	/* to encode a sd */
  * region descriptors, used to load gdt/idt tables before segments yet exist.
  */
 struct region_descriptor {
-	unsigned rd_limit:16;		/* segment extent */
-	unsigned rd_base:32;		/* base address  */
+	unsigned rd_limit:16;				/* segment extent */
+	unsigned rd_base:32 __attribute__ ((packed));	/* base address  */
 };
 
 /*
@@ -198,4 +199,37 @@ struct region_descriptor {
 
 #define	NIDT	256
 #define	NRSVIDT	32		/* reserved entries for cpu exceptions */
+
+/*
+ * Entries in the Global Descriptor Table (GDT)
+ */
+#define	GNULL_SEL	0	/* Null Descriptor */
+#define	GCODE_SEL	1	/* Kernel Code Descriptor */
+#define	GDATA_SEL	2	/* Kernel Data Descriptor */
+#define	GLDT_SEL	3	/* LDT - eventually one per process */
+#define	GTGATE_SEL	4	/* Process task switch gate */
+#define	GPANIC_SEL	5	/* Task state to consider panic from */
+#define	GPROC0_SEL	6	/* Task state process slot zero and up */
+#define	GUSERLDT_SEL	7	/* User LDT */
+#define NGDT 	GUSERLDT_SEL+1
+
+/*
+ * Entries in the Local Descriptor Table (LDT)
+ */
+#define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
+#define	LSYS5SIGR_SEL	1
+#define	L43BSDCALLS_SEL	2	/* notyet */
+#define	LUCODE_SEL	3
+#define	LUDATA_SEL	4
+/* seperate stack, es,fs,gs sels ? */
+/* #define	LPOSIXCALLS_SEL	5*/	/* notyet */
+#define NLDT		LUDATA_SEL+1
+
+#ifdef KERNEL
+extern int currentldt;
+extern union descriptor gdt[NGDT];
+extern union descriptor ldt[NLDT];
+extern struct soft_segment_descriptor gdt_segs[];
+#endif
+
 #endif /* _MACHINE_SEGMENTS_H_ */