diff options
author | dg <dg@FreeBSD.org> | 1994-01-31 10:27:13 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1994-01-31 10:27:13 +0000 |
commit | 8df5d2c1f8c514a14d5728e5a9f9e30e48ae90eb (patch) | |
tree | 3f282f48fea85301258a9cb32507359b11f365f7 /sys/i386 | |
parent | 805b2d4d90c77f94e31f786f0afbd08f5fd8e1cb (diff) | |
download | FreeBSD-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/i386')
-rw-r--r-- | sys/i386/conf/LINT | 4 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 4 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 90 | ||||
-rw-r--r-- | sys/i386/i386/swtch.s | 17 | ||||
-rw-r--r-- | sys/i386/i386/sys_machdep.c | 223 | ||||
-rw-r--r-- | sys/i386/include/frame.h | 5 | ||||
-rw-r--r-- | sys/i386/include/reg.h | 4 | ||||
-rw-r--r-- | sys/i386/include/segments.h | 42 |
8 files changed, 333 insertions, 56 deletions
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 67f620e..9635d0e 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 67f620e..9635d0e 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 2ed6217..ea31916 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 731359e..ab5cb7a 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 2b63cee..92758ad 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 b36c141..05bf265 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 4cefae0..d20f8d0 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 a7ed234..023a0cf 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_ */ |