From owner-freebsd-bugs Fri Apr 30 14:40:19 1999 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id E04A315922 for ; Fri, 30 Apr 1999 14:40:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id OAA88114; Fri, 30 Apr 1999 14:40:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Date: Fri, 30 Apr 1999 14:40:01 -0700 (PDT) Message-Id: <199904302140.OAA88114@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: Juergen Lock Subject: Re: kern/11287: rfork(RFMEM...) doesn't share LDTs set by i386_set_ldt, breaking wine Reply-To: Juergen Lock Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org The following reply was made to PR kern/11287; it has been noted by GNATS. From: Juergen Lock To: Luoqi Chen Cc: freebsd-gnats-submit@freebsd.org Subject: Re: kern/11287: rfork(RFMEM...) doesn't share LDTs set by i386_set_ldt, breaking wine Date: Fri, 30 Apr 1999 23:25:27 +0200 On Fri, Apr 30, 1999 at 12:05:13PM -0400, Luoqi Chen wrote: > User LDT sharing should really be done in the machine dependent layer. Well, was my patch not in the machine dependent layer? > I have an implementation based on -current (I don't have any machine > running -stable), you may want to take a look at, the patch is at > http://www.freebsd.org/~luoqi > > There are still two problems with this implementation: > - It is incomplete for SMP. We need something similar to TLB shootdown > when modifying the ldt table. > - It doesn't work correctly in the following case: > 1. process A initially doesn't have a user ldt table > 2. process A forks process B (RFMEM) > 3. process B calls i386_set_ldt() > now process B has a user ldt table, but inaccessible to A. I can > see 3 solutions to this problem: > 1. Allocate a user ldt table for all processes. > This is not really an acceptable solution, it penalize everyone > else for the benefit of a few. > 2. Define another rfork flag RFLDT. > The problem with solution is the flag is too machine-specific. > 3. Any process wants to share user ldt with its descendants should > call i386_set_ldt() prior to any fork. > This is a workaround in the user application, but should work > well. > > -lq Anyway I have back-ported your patch to 3.1-stable and it seems to work, so whichever one gets committed is ok with me... I added a diff for pc98/i386/machdep.c, and the cpu_switch_load_{f,g}s trap 12 handler. (Sorry no http location, maybe you can add this to your page? thanx.) cvs diff: Diffing sys/alpha/alpha Index: sys/alpha/alpha/vm_machdep.c =================================================================== RCS file: /home/cvs/cvs/src/sys/alpha/alpha/vm_machdep.c,v retrieving revision 1.7.2.1 diff -u -r1.7.2.1 vm_machdep.c --- vm_machdep.c 1999/01/27 20:51:39 1.7.2.1 +++ vm_machdep.c 1999/04/30 18:37:45 @@ -114,11 +114,15 @@ * ready to run and return to user mode. */ void -cpu_fork(p1, p2) +cpu_fork(p1, p2, flags) register struct proc *p1, *p2; + int flags; { struct user *up = p2->p_addr; int i; + + if ((flags & RFPROC) == 0) + return; p2->p_md.md_tf = p1->p_md.md_tf; p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED; cvs diff: Diffing sys/i386/i386 Index: sys/i386/i386/genassym.c =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/i386/genassym.c,v retrieving revision 1.62.2.1 diff -u -r1.62.2.1 genassym.c --- genassym.c 1999/02/22 15:59:39 1.62.2.1 +++ genassym.c 1999/04/30 18:38:27 @@ -125,7 +125,9 @@ printf("#define\tPCB_EBX %#x\n", OS(pcb, pcb_ebx)); printf("#define\tPCB_EIP %#x\n", OS(pcb, pcb_eip)); printf("#define\tTSS_ESP0 %#x\n", OS(i386tss, tss_esp0)); +#ifdef USER_LDT printf("#define\tPCB_USERLDT %#x\n", OS(pcb, pcb_ldt)); +#endif printf("#define\tPCB_FS %#x\n", OS(pcb, pcb_fs)); printf("#define\tPCB_GS %#x\n", OS(pcb, pcb_gs)); #ifdef VM86 Index: sys/i386/i386/machdep.c =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/i386/machdep.c,v retrieving revision 1.322.2.4 diff -u -r1.322.2.4 machdep.c --- machdep.c 1999/02/17 13:08:41 1.322.2.4 +++ machdep.c 1999/04/30 18:39:41 @@ -814,15 +814,7 @@ #ifdef USER_LDT /* was i386_user_cleanup() in NetBSD */ - if (pcb->pcb_ldt) { - if (pcb == curpcb) { - lldt(_default_ldt); - currentldt = _default_ldt; - } - kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt, - pcb->pcb_ldt_len * sizeof(union descriptor)); - pcb->pcb_ldt_len = (int)pcb->pcb_ldt = 0; - } + user_ldt_free(pcb); #endif bzero((char *)regs, sizeof(struct trapframe)); Index: sys/i386/i386/sys_machdep.c =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/i386/sys_machdep.c,v retrieving revision 1.38 diff -u -r1.38 sys_machdep.c --- sys_machdep.c 1998/12/07 21:58:19 1.38 +++ sys_machdep.c 1999/04/30 19:03:34 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,6 @@ #ifdef USER_LDT -void set_user_ldt __P((struct pcb *pcb)); static int i386_get_ldt __P((struct proc *, char *)); static int i386_set_ldt __P((struct proc *, char *)); #endif @@ -259,13 +259,72 @@ 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].sd); + struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; +#ifdef SMP + gdt[cpuid * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd; +#else + gdt[GUSERLDT_SEL].sd = pcb_ldt->ldt_sd; +#endif lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); currentldt = GSEL(GUSERLDT_SEL, SEL_KPL); } +struct pcb_ldt * +user_ldt_alloc(struct pcb *pcb, int len) +{ + struct pcb_ldt *pcb_ldt, *new_ldt; + + MALLOC(new_ldt, struct pcb_ldt *, sizeof(struct pcb_ldt), + M_SUBPROC, M_WAITOK); + if (new_ldt == NULL) + return NULL; + + new_ldt->ldt_len = len = NEW_MAX_LD(len); + new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map, + len * sizeof(union descriptor)); + if (new_ldt->ldt_base == NULL) { + FREE(new_ldt, M_SUBPROC); + return NULL; + } + new_ldt->ldt_refcnt = 1; + new_ldt->ldt_active = 0; + + gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt->ldt_base; + gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1; + ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd); + + if ((pcb_ldt = pcb->pcb_ldt)) { + if (len > pcb_ldt->ldt_len) + len = pcb_ldt->ldt_len; + bcopy(pcb_ldt->ldt_base, new_ldt->ldt_base, + len * sizeof(union descriptor)); + } else { + bcopy(ldt, new_ldt->ldt_base, sizeof(ldt)); + } + return new_ldt; +} + +void +user_ldt_free(struct pcb *pcb) +{ + struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; + + if (pcb_ldt == NULL) + return; + + if (pcb == curpcb) { + lldt(_default_ldt); + currentldt = _default_ldt; + } + + if (--pcb_ldt->ldt_refcnt == 0) { + kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base, + pcb_ldt->ldt_len * sizeof(union descriptor)); + FREE(pcb_ldt, M_SUBPROC); + } + pcb->pcb_ldt = NULL; +} + struct i386_get_ldt_args { int start; union descriptor *desc; @@ -279,6 +338,7 @@ { int error = 0; struct pcb *pcb = &p->p_addr->u_pcb; + struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; int nldt, num; union descriptor *lp; int s; @@ -299,10 +359,10 @@ s = splhigh(); - if (pcb->pcb_ldt) { - nldt = pcb->pcb_ldt_len; + if (pcb_ldt) { + nldt = pcb_ldt->ldt_len; num = min(uap->num, nldt); - lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start]; + lp = &((union descriptor *)(pcb_ldt->ldt_base))[uap->start]; } else { nldt = sizeof(ldt)/sizeof(ldt[0]); num = min(uap->num, nldt); @@ -335,6 +395,7 @@ int error = 0, i, n; int largest_ld; struct pcb *pcb = &p->p_addr->u_pcb; + struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; int s; struct i386_set_ldt_args ua, *uap; @@ -348,36 +409,37 @@ uap->start, uap->num, (void *)uap->desc); #endif - /* verify range of descriptors to modify */ - if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) || - (uap->num > MAX_LD)) - { + /* verify range of descriptors to modify */ + if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) || + (uap->num > MAX_LD)) + { + return(EINVAL); + } + largest_ld = uap->start + uap->num - 1; + if (largest_ld >= MAX_LD) return(EINVAL); - } - largest_ld = uap->start + uap->num - 1; - if (largest_ld >= MAX_LD) - return(EINVAL); - - /* allocate user ldt */ - if (!pcb->pcb_ldt || (largest_ld >= pcb->pcb_ldt_len)) { - union descriptor *new_ldt = (union descriptor *)kmem_alloc( - kernel_map, SIZE_FROM_LARGEST_LD(largest_ld)); - if (new_ldt == NULL) { - return ENOMEM; - } - if (pcb->pcb_ldt) { - bcopy(pcb->pcb_ldt, new_ldt, pcb->pcb_ldt_len - * sizeof(union descriptor)); - kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt, - pcb->pcb_ldt_len * sizeof(union descriptor)); - } else { - bcopy(ldt, new_ldt, sizeof(ldt)); - } - pcb->pcb_ldt = (caddr_t)new_ldt; - pcb->pcb_ldt_len = NEW_MAX_LD(largest_ld); - if (pcb == curpcb) - set_user_ldt(pcb); - } + + /* allocate user ldt */ + if (!pcb_ldt || (largest_ld >= pcb_ldt->ldt_len)) { + struct pcb_ldt *new_ldt = user_ldt_alloc(pcb, largest_ld); + if (new_ldt == NULL) { + return ENOMEM; + } + if (pcb_ldt) { + pcb_ldt->ldt_sd = new_ldt->ldt_sd; +#ifdef SMP + /* signal other cpus to reload ldt */ +#endif + kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base, + pcb_ldt->ldt_len * sizeof(union descriptor)); + pcb_ldt->ldt_base = new_ldt->ldt_base; + pcb_ldt->ldt_len = new_ldt->ldt_len; + FREE(new_ldt, M_SUBPROC); + } else + pcb->pcb_ldt = pcb_ldt = new_ldt; + if (pcb == curpcb) + set_user_ldt(pcb); + } /* Check descriptors for access violations */ for (i = 0, n = uap->start; i < uap->num; i++, n++) { @@ -388,70 +450,70 @@ return(error); switch (desc.sd.sd_type) { - case SDT_SYSNULL: /* system null */ - desc.sd.sd_p = 0; - break; - case SDT_SYS286TSS: /* system 286 TSS available */ - case SDT_SYSLDT: /* system local descriptor table */ - case SDT_SYS286BSY: /* system 286 TSS busy */ - case SDT_SYSTASKGT: /* system task gate */ - case SDT_SYS286IGT: /* system 286 interrupt gate */ - case SDT_SYS286TGT: /* system 286 trap gate */ - case SDT_SYSNULL2: /* undefined by Intel */ - case SDT_SYS386TSS: /* system 386 TSS available */ - case SDT_SYSNULL3: /* undefined by Intel */ - case SDT_SYS386BSY: /* system 386 TSS busy */ - case SDT_SYSNULL4: /* undefined by Intel */ - case SDT_SYS386IGT: /* system 386 interrupt gate */ - case SDT_SYS386TGT: /* system 386 trap gate */ - case SDT_SYS286CGT: /* system 286 call gate */ - case SDT_SYS386CGT: /* system 386 call gate */ - /* I can't think of any reason to allow a user proc - * to create a segment of these types. They are - * for OS use only. - */ - return EACCES; - - /* memory segment types */ - case SDT_MEMEC: /* memory execute only conforming */ - case SDT_MEMEAC: /* memory execute only accessed conforming */ - case SDT_MEMERC: /* memory execute read conforming */ - case SDT_MEMERAC: /* memory execute read accessed conforming */ - /* Must be "present" if executable and conforming. */ - if (desc.sd.sd_p == 0) - return (EACCES); + case SDT_SYSNULL: /* system null */ + desc.sd.sd_p = 0; break; - case SDT_MEMRO: /* memory read only */ - case SDT_MEMROA: /* memory read only accessed */ - case SDT_MEMRW: /* memory read write */ - case SDT_MEMRWA: /* memory read write accessed */ - case SDT_MEMROD: /* memory read only expand dwn limit */ - case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ - case SDT_MEMRWD: /* memory read write expand dwn limit */ - case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ - case SDT_MEME: /* memory execute only */ - case SDT_MEMEA: /* memory execute only accessed */ - case SDT_MEMER: /* memory execute read */ - case SDT_MEMERA: /* memory execute read accessed */ + case SDT_SYS286TSS: /* system 286 TSS available */ + case SDT_SYSLDT: /* system local descriptor table */ + case SDT_SYS286BSY: /* system 286 TSS busy */ + case SDT_SYSTASKGT: /* system task gate */ + case SDT_SYS286IGT: /* system 286 interrupt gate */ + case SDT_SYS286TGT: /* system 286 trap gate */ + case SDT_SYSNULL2: /* undefined by Intel */ + case SDT_SYS386TSS: /* system 386 TSS available */ + case SDT_SYSNULL3: /* undefined by Intel */ + case SDT_SYS386BSY: /* system 386 TSS busy */ + case SDT_SYSNULL4: /* undefined by Intel */ + case SDT_SYS386IGT: /* system 386 interrupt gate */ + case SDT_SYS386TGT: /* system 386 trap gate */ + case SDT_SYS286CGT: /* system 286 call gate */ + case SDT_SYS386CGT: /* system 386 call gate */ + /* I can't think of any reason to allow a user proc + * to create a segment of these types. They are + * for OS use only. + */ + return EACCES; + + /* memory segment types */ + case SDT_MEMEC: /* memory execute only conforming */ + case SDT_MEMEAC: /* memory execute only accessed conforming */ + case SDT_MEMERC: /* memory execute read conforming */ + case SDT_MEMERAC: /* memory execute read accessed conforming */ + /* Must be "present" if executable and conforming. */ + if (desc.sd.sd_p == 0) + return (EACCES); + break; + case SDT_MEMRO: /* memory read only */ + case SDT_MEMROA: /* memory read only accessed */ + case SDT_MEMRW: /* memory read write */ + case SDT_MEMRWA: /* memory read write accessed */ + case SDT_MEMROD: /* memory read only expand dwn limit */ + case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ + case SDT_MEMRWD: /* memory read write expand dwn limit */ + case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ + case SDT_MEME: /* memory execute only */ + case SDT_MEMEA: /* memory execute only accessed */ + case SDT_MEMER: /* memory execute read */ + case SDT_MEMERA: /* memory execute read accessed */ break; default: return(EINVAL); /*NOTREACHED*/ } - /* Only user (ring-3) descriptors may be present. */ - if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL)) - return (EACCES); + /* Only user (ring-3) descriptors may be present. */ + if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL)) + return (EACCES); } s = splhigh(); /* Fill in range */ - error = copyin(uap->desc, - &((union descriptor *)(pcb->pcb_ldt))[uap->start], - uap->num * sizeof(union descriptor)); - if (!error) - p->p_retval[0] = uap->start; + error = copyin(uap->desc, + &((union descriptor *)(pcb_ldt->ldt_base))[uap->start], + uap->num * sizeof(union descriptor)); + if (!error) + p->p_retval[0] = uap->start; splx(s); return(error); Index: sys/i386/i386/vm_machdep.c =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/i386/vm_machdep.c,v retrieving revision 1.115 diff -u -r1.115 vm_machdep.c --- vm_machdep.c 1999/01/06 23:05:37 1.115 +++ vm_machdep.c 1999/04/30 19:11:14 @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -113,10 +114,29 @@ * ready to run and return to user mode. */ void -cpu_fork(p1, p2) +cpu_fork(p1, p2, flags) register struct proc *p1, *p2; + int flags; { - struct pcb *pcb2 = &p2->p_addr->u_pcb; + struct pcb *pcb2; + + if ((flags & RFPROC) == 0) { +#ifdef USER_LDT + if ((flags & RFMEM) == 0) { + /* unshare user LDT */ + struct pcb *pcb1 = &p1->p_addr->u_pcb; + struct pcb_ldt *pcb_ldt = pcb1->pcb_ldt; + if (pcb_ldt && pcb_ldt->ldt_refcnt > 1) { + pcb_ldt = user_ldt_alloc(pcb1,pcb_ldt->ldt_len); + user_ldt_free(pcb1); + pcb1->pcb_ldt = pcb_ldt; + if (pcb1 == curpcb) + set_user_ldt(pcb1); + } + } +#endif + return; + } #if NNPX > 0 /* Ensure that p1's pcb is up to date. */ @@ -126,6 +146,7 @@ /* Copy p1's pcb. */ p2->p_addr->u_pcb = p1->p_addr->u_pcb; + pcb2 = &p2->p_addr->u_pcb; /* * Create a new fresh stack for the new process. @@ -153,7 +174,6 @@ pcb2->pcb_eip = (int)fork_trampoline; /* * pcb2->pcb_ldt: duplicated below, if necessary. - * pcb2->pcb_ldt_len: cloned above. * pcb2->pcb_savefpu: cloned above. * pcb2->pcb_flags: cloned above (always 0 here?). * pcb2->pcb_onfault: cloned above (always NULL here?). @@ -172,12 +192,12 @@ #ifdef USER_LDT /* Copy the LDT, if necessary. */ if (pcb2->pcb_ldt != 0) { - union descriptor *new_ldt; - size_t len = pcb2->pcb_ldt_len * sizeof(union descriptor); - - new_ldt = (union descriptor *)kmem_alloc(kernel_map, len); - bcopy(pcb2->pcb_ldt, new_ldt, len); - pcb2->pcb_ldt = (caddr_t)new_ldt; + if (flags & RFMEM) { + pcb2->pcb_ldt->ldt_refcnt++; + } else { + pcb2->pcb_ldt = user_ldt_alloc(pcb2, + pcb2->pcb_ldt->ldt_len); + } } #endif @@ -235,15 +255,7 @@ } #endif #ifdef USER_LDT - if (pcb->pcb_ldt != 0) { - if (pcb == curpcb) { - lldt(_default_ldt); - currentldt = _default_ldt; - } - kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt, - pcb->pcb_ldt_len * sizeof(union descriptor)); - pcb->pcb_ldt_len = (int)pcb->pcb_ldt = 0; - } + user_ldt_free(pcb); #endif cnt.v_swtch++; cpu_switch(p); cvs diff: Diffing sys/i386/include Index: sys/i386/include/pcb.h =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/include/pcb.h,v retrieving revision 1.26 diff -u -r1.26 pcb.h --- pcb.h 1998/02/03 21:27:50 1.26 +++ pcb.h 1999/04/30 19:12:53 @@ -53,8 +53,11 @@ int pcb_esp; int pcb_ebx; int pcb_eip; - caddr_t pcb_ldt; /* per process (user) LDT */ - int pcb_ldt_len; /* number of LDT entries */ +#ifdef USER_LDT + struct pcb_ldt *pcb_ldt; /* per process (user) LDT */ +#else + struct pcb_ldt *pcb_ldt_dontuse; +#endif struct save87 pcb_savefpu; /* floating point state for 287/387 */ u_char pcb_flags; #define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */ @@ -71,7 +74,7 @@ #else struct pcb_ext *pcb_ext_dontuse; #endif - u_long __pcb_spare[1]; /* adjust to avoid core dump size changes */ + u_long __pcb_spare[2]; /* adjust to avoid core dump size changes */ }; /* Index: sys/i386/include/pcb_ext.h =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/include/pcb_ext.h,v retrieving revision 1.1 diff -u -r1.1 pcb_ext.h --- pcb_ext.h 1997/08/09 04:55:05 1.1 +++ pcb_ext.h 1999/04/30 19:13:58 @@ -43,4 +43,22 @@ struct vm86_kernel ext_vm86; /* vm86 area */ }; +struct pcb_ldt { + caddr_t ldt_base; + int ldt_len; + int ldt_refcnt; + u_long ldt_active; + struct segment_descriptor ldt_sd; +}; + +#ifdef KERNEL + +#ifdef USER_LDT +void set_user_ldt __P((struct pcb *)); +struct pcb_ldt *user_ldt_alloc __P((struct pcb *, int)); +void user_ldt_free __P((struct pcb *)); +#endif + +#endif + #endif /* _I386_PCB_EXT_H_ */ cvs diff: Diffing sys/i386/include/pc cvs diff: Diffing sys/kern Index: sys/kern/kern_fork.c =================================================================== RCS file: /home/cvs/cvs/src/sys/kern/kern_fork.c,v retrieving revision 1.54.2.2 diff -u -r1.54.2.2 kern_fork.c --- kern_fork.c 1999/03/02 00:42:08 1.54.2.2 +++ kern_fork.c 1999/04/30 19:14:56 @@ -162,16 +162,7 @@ */ if ((flags & RFPROC) == 0) { - /* - * Divorce the memory, if it is shared, essentially - * this changes shared memory amongst threads, into - * COW locally. - */ - if ((flags & RFMEM) == 0) { - if (p1->p_vmspace->vm_refcnt > 1) { - vmspace_unshare(p1); - } - } + vm_fork(p1, 0, flags); /* * Close all file descriptors. cvs diff: Diffing sys/sys Index: sys/sys/proc.h =================================================================== RCS file: /home/cvs/cvs/src/sys/sys/proc.h,v retrieving revision 1.66.2.2 diff -u -r1.66.2.2 proc.h --- proc.h 1999/02/23 13:44:36 1.66.2.2 +++ proc.h 1999/04/30 19:15:32 @@ -375,7 +375,7 @@ void cpu_exit __P((struct proc *)) __dead2; void exit1 __P((struct proc *, int)) __dead2; -void cpu_fork __P((struct proc *, struct proc *)); +void cpu_fork __P((struct proc *, struct proc *, int)); int fork1 __P((struct proc *, int)); int trace_req __P((struct proc *)); void cpu_wait __P((struct proc *)); cvs diff: Diffing sys/vm Index: sys/vm/vm_glue.c =================================================================== RCS file: /home/cvs/cvs/src/sys/vm/vm_glue.c,v retrieving revision 1.80.2.1 diff -u -r1.80.2.1 vm_glue.c --- vm_glue.c 1999/01/27 20:51:43 1.80.2.1 +++ vm_glue.c 1999/04/30 19:17:19 @@ -208,6 +208,21 @@ { register struct user *up; + if ((flags & RFPROC) == 0) { + /* + * Divorce the memory, if it is shared, essentially + * this changes shared memory amongst threads, into + * COW locally. + */ + if ((flags & RFMEM) == 0) { + if (p1->p_vmspace->vm_refcnt > 1) { + vmspace_unshare(p1); + } + } + cpu_fork(p1, p2, flags); + return; + } + if (flags & RFMEM) { p2->p_vmspace = p1->p_vmspace; p1->p_vmspace->vm_refcnt++; @@ -257,7 +272,7 @@ * cpu_fork will copy and update the pcb, set up the kernel stack, * and make the child ready to run. */ - cpu_fork(p1, p2); + cpu_fork(p1, p2, flags); } /* Index: sys/pc98/i386/machdep.c =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/i386/machdep.c,v retrieving revision 1.322.2.4 diff -u -r1.322.2.4 machdep.c --- machdep.c 1999/02/17 13:08:41 1.322.2.4 +++ machdep.c 1999/04/30 18:39:41 @@ -814,15 +814,7 @@ #ifdef USER_LDT /* was i386_user_cleanup() in NetBSD */ - if (pcb->pcb_ldt) { - if (pcb == curpcb) { - lldt(_default_ldt); - currentldt = _default_ldt; - } - kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt, - pcb->pcb_ldt_len * sizeof(union descriptor)); - pcb->pcb_ldt_len = (int)pcb->pcb_ldt = 0; - } + user_ldt_free(pcb); #endif bzero((char *)regs, sizeof(struct trapframe)); Index: sys/i386/i386/trap.c =================================================================== RCS file: /home/cvs/cvs/src/sys/i386/i386/trap.c,v retrieving revision 1.133 diff -u -r1.133 trap.c --- trap.c 1999/01/06 23:05:36 1.133 +++ trap.c 1999/04/26 13:44:35 @@ -434,6 +434,29 @@ switch (type) { case T_PAGEFLT: /* page fault */ + if (intr_nesting_level == 0) { + /* + * Invalid %fs's and %gs's can be created using + * procfs or PT_SETREGS or by invalidating the + * underlying LDT entry. This causes a fault + * in kernel mode when the kernel attempts to + * switch contexts. Lose the bad context + * (XXX) so that we can continue, and generate + * a signal. + */ + if (frame.tf_eip == (int)cpu_switch_load_fs + && curpcb->pcb_fs) { + curpcb->pcb_fs = 0; + psignal(p, SIGBUS); + return; + } + if (frame.tf_eip == (int)cpu_switch_load_gs + && curpcb->pcb_gs) { + curpcb->pcb_gs = 0; + psignal(p, SIGBUS); + return; + } + } (void) trap_pfault(&frame, FALSE, eva); return; Regards, -- Juergen Lock (remove dot foo from address to reply) To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message