summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authordg <dg@FreeBSD.org>1994-01-31 10:27:13 +0000
committerdg <dg@FreeBSD.org>1994-01-31 10:27:13 +0000
commit8df5d2c1f8c514a14d5728e5a9f9e30e48ae90eb (patch)
tree3f282f48fea85301258a9cb32507359b11f365f7 /sys/amd64
parent805b2d4d90c77f94e31f786f0afbd08f5fd8e1cb (diff)
downloadFreeBSD-src-8df5d2c1f8c514a14d5728e5a9f9e30e48ae90eb.zip
FreeBSD-src-8df5d2c1f8c514a14d5728e5a9f9e30e48ae90eb.tar.gz
WINE/user LDT support from John Brezak, ported to FreeBSD by Jeffrey Hsu
<hsu@soda.berkeley.edu>.
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/amd64/cpu_switch.S17
-rw-r--r--sys/amd64/amd64/machdep.c90
-rw-r--r--sys/amd64/amd64/swtch.s17
-rw-r--r--sys/amd64/amd64/sys_machdep.c223
-rw-r--r--sys/amd64/include/frame.h5
-rw-r--r--sys/amd64/include/reg.h4
-rw-r--r--sys/amd64/include/segments.h42
7 files changed, 343 insertions, 55 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index 731359e..ab5cb7a 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 2ed6217..ea31916 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 731359e..ab5cb7a 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 2b63cee..92758ad 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 b36c141..05bf265 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 4cefae0..d20f8d0 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 a7ed234..023a0cf 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_ */
OpenPOWER on IntegriCloud