User ldt sharing.
This commit is contained in:
parent
a2e7fb9f68
commit
91c28bfde0
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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_ */
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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_ */
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 *));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user