diff options
-rw-r--r-- | sys/alpha/alpha/vm_machdep.c | 6 | ||||
-rw-r--r-- | sys/amd64/amd64/genassym.c | 2 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 12 | ||||
-rw-r--r-- | sys/amd64/amd64/sys_machdep.c | 255 | ||||
-rw-r--r-- | sys/amd64/amd64/vm_machdep.c | 52 | ||||
-rw-r--r-- | sys/amd64/include/pcb.h | 9 | ||||
-rw-r--r-- | sys/amd64/include/pcb_ext.h | 18 | ||||
-rw-r--r-- | sys/i386/i386/genassym.c | 2 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 12 | ||||
-rw-r--r-- | sys/i386/i386/sys_machdep.c | 255 | ||||
-rw-r--r-- | sys/i386/i386/vm_machdep.c | 52 | ||||
-rw-r--r-- | sys/i386/include/pcb.h | 9 | ||||
-rw-r--r-- | sys/i386/include/pcb_ext.h | 18 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 11 | ||||
-rw-r--r-- | sys/pc98/i386/machdep.c | 12 | ||||
-rw-r--r-- | sys/pc98/pc98/machdep.c | 12 | ||||
-rw-r--r-- | sys/powerpc/aim/vm_machdep.c | 6 | ||||
-rw-r--r-- | sys/powerpc/powerpc/vm_machdep.c | 6 | ||||
-rw-r--r-- | sys/sys/proc.h | 2 | ||||
-rw-r--r-- | sys/vm/vm_glue.c | 17 |
20 files changed, 477 insertions, 291 deletions
diff --git a/sys/alpha/alpha/vm_machdep.c b/sys/alpha/alpha/vm_machdep.c index 989be9a..75bfef5 100644 --- a/sys/alpha/alpha/vm_machdep.c +++ b/sys/alpha/alpha/vm_machdep.c @@ -115,11 +115,15 @@ vm_fault_quick(v, prot) * 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; + 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; diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index d137b12..75f278d 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -120,7 +120,9 @@ main() 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_GS %#x\n", OS(pcb, pcb_gs)); printf("#define\tPCB_DR0 %#x\n", OS(pcb, pcb_dr0)); printf("#define\tPCB_DR1 %#x\n", OS(pcb, pcb_dr1)); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 645b702..dfe6a87 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -61,11 +61,11 @@ #include <sys/signalvar.h> #include <sys/kernel.h> #include <sys/linker.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/buf.h> #include <sys/reboot.h> #include <sys/callout.h> -#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/msgbuf.h> #include <sys/sysent.h> @@ -1006,15 +1006,7 @@ setregs(p, entry, stack, ps_strings) #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)); diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c index f9227dc..e9c7ddf 100644 --- a/sys/amd64/amd64/sys_machdep.c +++ b/sys/amd64/amd64/sys_machdep.c @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <vm/vm.h> @@ -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 @@ -136,7 +136,7 @@ i386_extend_pcb(struct proc *p) p->p_addr->u_pcb.pcb_ext = ext; bzero(ext, sizeof(struct pcb_ext)); ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16; - ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); + ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); /* * The last byte of the i/o map must be followed by an 0xff byte. * We arbitrarily allocate 16 bytes here, to keep the starting @@ -174,8 +174,8 @@ i386_set_ioperm(p, args) if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0) return (error); - if ((error = suser(p)) != 0) - return (error); + if ((error = suser(p)) != 0) + return (error); if (securelevel > 0) return (EPERM); /* @@ -247,17 +247,77 @@ done: 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; + struct pcb_ldt *pcb_ldt; + + if (pcb != curpcb) + return; + + pcb_ldt = pcb->pcb_ldt; #ifdef SMP - ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[cpuid * NGDT + GUSERLDT_SEL].sd); + gdt[cpuid * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd; #else - ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[GUSERLDT_SEL].sd); + 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; +} + static int i386_get_ldt(p, args) struct proc *p; @@ -265,6 +325,7 @@ i386_get_ldt(p, args) { 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; @@ -284,10 +345,10 @@ i386_get_ldt(p, args) 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); @@ -312,8 +373,9 @@ i386_set_ldt(p, args) char *args; { int error = 0, i, n; - int largest_ld; + int largest_ld; struct pcb *pcb = &p->p_addr->u_pcb; + struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; int s; struct i386_ldt_args ua, *uap = &ua; @@ -325,36 +387,37 @@ i386_set_ldt(p, args) uap->start, uap->num, (void *)uap->descs); #endif - /* 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); - - /* 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); - } + /* 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); + + /* 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; + 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; +#ifdef SMP + /* signal other cpus to reload ldt */ + smp_rendezvous(NULL, (void (*)(void *))set_user_ldt, NULL, pcb); +#else + set_user_ldt(pcb); +#endif + } /* Check descriptors for access violations */ for (i = 0, n = uap->start; i < uap->num; i++, n++) { @@ -365,70 +428,70 @@ i386_set_ldt(p, args) 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); - 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_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); + 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->descs, - &((union descriptor *)(pcb->pcb_ldt))[uap->start], - uap->num * sizeof(union descriptor)); - if (!error) - p->p_retval[0] = uap->start; + error = copyin(uap->descs, + &((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); diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index 9ca7d3a..d7fa73b1 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -49,13 +49,14 @@ #include <sys/param.h> #include <sys/systm.h> -#include <sys/proc.h> #include <sys/malloc.h> +#include <sys/proc.h> #include <sys/buf.h> #include <sys/vnode.h> #include <sys/vmmeter.h> #include <sys/kernel.h> #include <sys/sysctl.h> +#include <sys/unistd.h> #include <machine/clock.h> #include <machine/cpu.h> @@ -63,6 +64,9 @@ #ifdef SMP #include <machine/smp.h> #endif +#include <machine/pcb.h> +#include <machine/pcb_ext.h> +#include <machine/vm86.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -110,10 +114,28 @@ vm_fault_quick(v, prot) * 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; + set_user_ldt(pcb1); + } + } +#endif + return; + } #if NNPX > 0 /* Ensure that p1's pcb is up to date. */ @@ -123,6 +145,7 @@ cpu_fork(p1, p2) /* 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. @@ -146,7 +169,6 @@ cpu_fork(p1, p2) 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?). @@ -163,12 +185,12 @@ cpu_fork(p1, p2) #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 @@ -222,15 +244,7 @@ cpu_exit(p) pcb->pcb_ext = 0; } #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); diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h index ed3044c..dde7281 100644 --- a/sys/amd64/include/pcb.h +++ b/sys/amd64/include/pcb.h @@ -62,8 +62,11 @@ struct pcb { int pcb_dr6; int pcb_dr7; - 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 */ @@ -76,7 +79,7 @@ struct pcb { #endif int pcb_gs; struct pcb_ext *pcb_ext; /* optional pcb extension */ - u_long __pcb_spare[2]; /* adjust to avoid core dump size changes */ + u_long __pcb_spare[3]; /* adjust to avoid core dump size changes */ }; /* diff --git a/sys/amd64/include/pcb_ext.h b/sys/amd64/include/pcb_ext.h index 154cf94..42e8abf 100644 --- a/sys/amd64/include/pcb_ext.h +++ b/sys/amd64/include/pcb_ext.h @@ -43,4 +43,22 @@ struct pcb_ext { 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_ */ diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index d137b12..75f278d 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -120,7 +120,9 @@ main() 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_GS %#x\n", OS(pcb, pcb_gs)); printf("#define\tPCB_DR0 %#x\n", OS(pcb, pcb_dr0)); printf("#define\tPCB_DR1 %#x\n", OS(pcb, pcb_dr1)); diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 645b702..dfe6a87 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -61,11 +61,11 @@ #include <sys/signalvar.h> #include <sys/kernel.h> #include <sys/linker.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/buf.h> #include <sys/reboot.h> #include <sys/callout.h> -#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/msgbuf.h> #include <sys/sysent.h> @@ -1006,15 +1006,7 @@ setregs(p, entry, stack, ps_strings) #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)); diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c index f9227dc..e9c7ddf 100644 --- a/sys/i386/i386/sys_machdep.c +++ b/sys/i386/i386/sys_machdep.c @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <vm/vm.h> @@ -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 @@ -136,7 +136,7 @@ i386_extend_pcb(struct proc *p) p->p_addr->u_pcb.pcb_ext = ext; bzero(ext, sizeof(struct pcb_ext)); ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16; - ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); + ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); /* * The last byte of the i/o map must be followed by an 0xff byte. * We arbitrarily allocate 16 bytes here, to keep the starting @@ -174,8 +174,8 @@ i386_set_ioperm(p, args) if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0) return (error); - if ((error = suser(p)) != 0) - return (error); + if ((error = suser(p)) != 0) + return (error); if (securelevel > 0) return (EPERM); /* @@ -247,17 +247,77 @@ done: 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; + struct pcb_ldt *pcb_ldt; + + if (pcb != curpcb) + return; + + pcb_ldt = pcb->pcb_ldt; #ifdef SMP - ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[cpuid * NGDT + GUSERLDT_SEL].sd); + gdt[cpuid * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd; #else - ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[GUSERLDT_SEL].sd); + 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; +} + static int i386_get_ldt(p, args) struct proc *p; @@ -265,6 +325,7 @@ i386_get_ldt(p, args) { 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; @@ -284,10 +345,10 @@ i386_get_ldt(p, args) 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); @@ -312,8 +373,9 @@ i386_set_ldt(p, args) char *args; { int error = 0, i, n; - int largest_ld; + int largest_ld; struct pcb *pcb = &p->p_addr->u_pcb; + struct pcb_ldt *pcb_ldt = pcb->pcb_ldt; int s; struct i386_ldt_args ua, *uap = &ua; @@ -325,36 +387,37 @@ i386_set_ldt(p, args) uap->start, uap->num, (void *)uap->descs); #endif - /* 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); - - /* 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); - } + /* 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); + + /* 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; + 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; +#ifdef SMP + /* signal other cpus to reload ldt */ + smp_rendezvous(NULL, (void (*)(void *))set_user_ldt, NULL, pcb); +#else + set_user_ldt(pcb); +#endif + } /* Check descriptors for access violations */ for (i = 0, n = uap->start; i < uap->num; i++, n++) { @@ -365,70 +428,70 @@ i386_set_ldt(p, args) 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); - 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_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); + 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->descs, - &((union descriptor *)(pcb->pcb_ldt))[uap->start], - uap->num * sizeof(union descriptor)); - if (!error) - p->p_retval[0] = uap->start; + error = copyin(uap->descs, + &((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); diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index 9ca7d3a..d7fa73b1 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -49,13 +49,14 @@ #include <sys/param.h> #include <sys/systm.h> -#include <sys/proc.h> #include <sys/malloc.h> +#include <sys/proc.h> #include <sys/buf.h> #include <sys/vnode.h> #include <sys/vmmeter.h> #include <sys/kernel.h> #include <sys/sysctl.h> +#include <sys/unistd.h> #include <machine/clock.h> #include <machine/cpu.h> @@ -63,6 +64,9 @@ #ifdef SMP #include <machine/smp.h> #endif +#include <machine/pcb.h> +#include <machine/pcb_ext.h> +#include <machine/vm86.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -110,10 +114,28 @@ vm_fault_quick(v, prot) * 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; + set_user_ldt(pcb1); + } + } +#endif + return; + } #if NNPX > 0 /* Ensure that p1's pcb is up to date. */ @@ -123,6 +145,7 @@ cpu_fork(p1, p2) /* 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. @@ -146,7 +169,6 @@ cpu_fork(p1, p2) 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?). @@ -163,12 +185,12 @@ cpu_fork(p1, p2) #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 @@ -222,15 +244,7 @@ cpu_exit(p) pcb->pcb_ext = 0; } #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); diff --git a/sys/i386/include/pcb.h b/sys/i386/include/pcb.h index ed3044c..dde7281 100644 --- a/sys/i386/include/pcb.h +++ b/sys/i386/include/pcb.h @@ -62,8 +62,11 @@ struct pcb { int pcb_dr6; int pcb_dr7; - 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 */ @@ -76,7 +79,7 @@ struct pcb { #endif int pcb_gs; struct pcb_ext *pcb_ext; /* optional pcb extension */ - u_long __pcb_spare[2]; /* adjust to avoid core dump size changes */ + u_long __pcb_spare[3]; /* adjust to avoid core dump size changes */ }; /* diff --git a/sys/i386/include/pcb_ext.h b/sys/i386/include/pcb_ext.h index 154cf94..42e8abf 100644 --- a/sys/i386/include/pcb_ext.h +++ b/sys/i386/include/pcb_ext.h @@ -43,4 +43,22 @@ struct pcb_ext { 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_ */ diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 9f3feb2..2468ad7 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -167,16 +167,7 @@ fork1(p1, flags, procp) */ 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. diff --git a/sys/pc98/i386/machdep.c b/sys/pc98/i386/machdep.c index f17e905..89cf0de 100644 --- a/sys/pc98/i386/machdep.c +++ b/sys/pc98/i386/machdep.c @@ -61,11 +61,11 @@ #include <sys/signalvar.h> #include <sys/kernel.h> #include <sys/linker.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/buf.h> #include <sys/reboot.h> #include <sys/callout.h> -#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/msgbuf.h> #include <sys/sysent.h> @@ -1019,15 +1019,7 @@ setregs(p, entry, stack, ps_strings) #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)); diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c index f17e905..89cf0de 100644 --- a/sys/pc98/pc98/machdep.c +++ b/sys/pc98/pc98/machdep.c @@ -61,11 +61,11 @@ #include <sys/signalvar.h> #include <sys/kernel.h> #include <sys/linker.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/buf.h> #include <sys/reboot.h> #include <sys/callout.h> -#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/msgbuf.h> #include <sys/sysent.h> @@ -1019,15 +1019,7 @@ setregs(p, entry, stack, ps_strings) #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)); diff --git a/sys/powerpc/aim/vm_machdep.c b/sys/powerpc/aim/vm_machdep.c index 989be9a..75bfef5 100644 --- a/sys/powerpc/aim/vm_machdep.c +++ b/sys/powerpc/aim/vm_machdep.c @@ -115,11 +115,15 @@ vm_fault_quick(v, prot) * 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; + 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; diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c index 989be9a..75bfef5 100644 --- a/sys/powerpc/powerpc/vm_machdep.c +++ b/sys/powerpc/powerpc/vm_machdep.c @@ -115,11 +115,15 @@ vm_fault_quick(v, prot) * 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; + 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; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index d126fd6..3f06cee 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -429,7 +429,7 @@ void wakeup_one __P((void *chan)); 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)); void cpu_set_fork_handler __P((struct proc *, void (*)(void *), void *)); int fork1 __P((struct proc *, int, struct proc **)); int trace_req __P((struct proc *)); diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 5ec101f..7aa092d 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -209,6 +209,21 @@ vm_fork(p1, p2, flags) { 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++; @@ -259,7 +274,7 @@ vm_fork(p1, p2, flags) * 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); } /* |