- Use sched_lock and critical regions to ensure that LDT updates are thread
safe from preemption and concurrent access to the LDT. - Move the prototype for i386_extend_pcb() to <machine/pcb_ext.h>. Reviewed by: silence on -hackers
This commit is contained in:
parent
0a441629f1
commit
df4d012b9a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76434
@ -68,7 +68,6 @@ static int i386_get_ldt __P((struct proc *, char *));
|
||||
static int i386_set_ldt __P((struct proc *, char *));
|
||||
static int i386_get_ioperm __P((struct proc *, char *));
|
||||
static int i386_set_ioperm __P((struct proc *, char *));
|
||||
int i386_extend_pcb __P((struct proc *));
|
||||
|
||||
#ifndef _SYS_SYSPROTO_H_
|
||||
struct sysarch_args {
|
||||
@ -128,7 +127,6 @@ i386_extend_pcb(struct proc *p)
|
||||
ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1));
|
||||
if (ext == 0)
|
||||
return (ENOMEM);
|
||||
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);
|
||||
@ -151,14 +149,12 @@ i386_extend_pcb(struct proc *p)
|
||||
ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext);
|
||||
ssdtosd(&ssd, &ext->ext_tssd);
|
||||
|
||||
/* switch to the new TSS after syscall completes */
|
||||
/*
|
||||
* XXX: The sched_lock here needs to be over a slightly larger area.
|
||||
* I have patches to more properly lock accesses to process ldt's
|
||||
* and tss's that still need to be reviewed, but this keeps us from
|
||||
* panic'ing on the mtx_assert() in need_resched() for the time being.
|
||||
*/
|
||||
KASSERT(p == curproc, ("giving a TSS to non-curproc"));
|
||||
KASSERT(p->p_addr->u_pcb.pcb_ext == 0, ("already have a TSS!"));
|
||||
mtx_lock_spin(&sched_lock);
|
||||
p->p_addr->u_pcb.pcb_ext = ext;
|
||||
|
||||
/* switch to the new TSS after syscall completes */
|
||||
need_resched(p);
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
|
||||
@ -254,6 +250,7 @@ set_user_ldt(struct pcb *pcb)
|
||||
if (pcb != PCPU_GET(curpcb))
|
||||
return;
|
||||
|
||||
mtx_lock_spin(&sched_lock);
|
||||
pcb_ldt = pcb->pcb_ldt;
|
||||
#ifdef SMP
|
||||
gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
|
||||
@ -262,17 +259,23 @@ set_user_ldt(struct pcb *pcb)
|
||||
#endif
|
||||
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with either sched_lock free or held but not recursed.
|
||||
* If it does not return NULL, it will return with it owned.
|
||||
*/
|
||||
struct pcb_ldt *
|
||||
user_ldt_alloc(struct pcb *pcb, int len)
|
||||
{
|
||||
struct pcb_ldt *pcb_ldt, *new_ldt;
|
||||
|
||||
if (mtx_owned(&sched_lock))
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
mtx_assert(&sched_lock, MA_NOTOWNED);
|
||||
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,
|
||||
@ -284,6 +287,7 @@ user_ldt_alloc(struct pcb *pcb, int len)
|
||||
new_ldt->ldt_refcnt = 1;
|
||||
new_ldt->ldt_active = 0;
|
||||
|
||||
mtx_lock_spin(&sched_lock);
|
||||
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);
|
||||
@ -299,6 +303,10 @@ user_ldt_alloc(struct pcb *pcb, int len)
|
||||
return new_ldt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called either with sched_lock free or held but not recursed.
|
||||
* If pcb->pcb_ldt is not NULL, it will return with sched_lock released.
|
||||
*/
|
||||
void
|
||||
user_ldt_free(struct pcb *pcb)
|
||||
{
|
||||
@ -307,17 +315,22 @@ user_ldt_free(struct pcb *pcb)
|
||||
if (pcb_ldt == NULL)
|
||||
return;
|
||||
|
||||
if (!mtx_owned(&sched_lock))
|
||||
mtx_lock_spin(&sched_lock);
|
||||
mtx_assert(&sched_lock, MA_OWNED | MA_NOTRECURSED);
|
||||
if (pcb == PCPU_GET(curpcb)) {
|
||||
lldt(_default_ldt);
|
||||
PCPU_SET(currentldt, _default_ldt);
|
||||
}
|
||||
|
||||
pcb->pcb_ldt = NULL;
|
||||
if (--pcb_ldt->ldt_refcnt == 0) {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
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;
|
||||
} else
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -330,7 +343,6 @@ i386_get_ldt(p, args)
|
||||
struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
|
||||
int nldt, num;
|
||||
union descriptor *lp;
|
||||
int s;
|
||||
struct i386_ldt_args ua, *uap = &ua;
|
||||
|
||||
if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
|
||||
@ -345,8 +357,6 @@ i386_get_ldt(p, args)
|
||||
if ((uap->start < 0) || (uap->num <= 0))
|
||||
return(EINVAL);
|
||||
|
||||
s = splhigh();
|
||||
|
||||
if (pcb_ldt) {
|
||||
nldt = pcb_ldt->ldt_len;
|
||||
num = min(uap->num, nldt);
|
||||
@ -356,16 +366,13 @@ i386_get_ldt(p, args)
|
||||
num = min(uap->num, nldt);
|
||||
lp = &ldt[uap->start];
|
||||
}
|
||||
if (uap->start > nldt) {
|
||||
splx(s);
|
||||
if (uap->start > nldt)
|
||||
return(EINVAL);
|
||||
}
|
||||
|
||||
error = copyout(lp, uap->descs, num * sizeof(union descriptor));
|
||||
if (!error)
|
||||
p->p_retval[0] = num;
|
||||
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -378,8 +385,10 @@ i386_set_ldt(p, args)
|
||||
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;
|
||||
caddr_t old_ldt_base;
|
||||
int old_ldt_len;
|
||||
critical_t savecrit;
|
||||
|
||||
if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
|
||||
return(error);
|
||||
@ -405,14 +414,19 @@ i386_set_ldt(p, args)
|
||||
if (new_ldt == NULL)
|
||||
return ENOMEM;
|
||||
if (pcb_ldt) {
|
||||
old_ldt_base = pcb_ldt->ldt_base;
|
||||
old_ldt_len = pcb_ldt->ldt_len;
|
||||
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;
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
kmem_free(kernel_map, (vm_offset_t)old_ldt_base,
|
||||
old_ldt_len * sizeof(union descriptor));
|
||||
FREE(new_ldt, M_SUBPROC);
|
||||
} else
|
||||
} else {
|
||||
pcb->pcb_ldt = pcb_ldt = new_ldt;
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
#ifdef SMP
|
||||
/* signal other cpus to reload ldt */
|
||||
smp_rendezvous(NULL, (void (*)(void *))set_user_ldt, NULL, pcb);
|
||||
@ -453,6 +467,7 @@ i386_set_ldt(p, args)
|
||||
* for OS use only.
|
||||
*/
|
||||
return EACCES;
|
||||
/*NOTREACHED*/
|
||||
|
||||
/* memory segment types */
|
||||
case SDT_MEMEC: /* memory execute only conforming */
|
||||
@ -486,15 +501,14 @@ i386_set_ldt(p, args)
|
||||
return (EACCES);
|
||||
}
|
||||
|
||||
s = splhigh();
|
||||
|
||||
/* Fill in range */
|
||||
savecrit = critical_enter();
|
||||
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;
|
||||
critical_exit(savecrit);
|
||||
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
@ -184,14 +184,18 @@ cpu_fork(p1, p2, flags)
|
||||
pcb2->pcb_ext = 0;
|
||||
|
||||
/* Copy the LDT, if necessary. */
|
||||
mtx_lock_spin(&sched_lock);
|
||||
if (pcb2->pcb_ldt != 0) {
|
||||
if (flags & RFMEM) {
|
||||
pcb2->pcb_ldt->ldt_refcnt++;
|
||||
} else {
|
||||
pcb2->pcb_ldt = user_ldt_alloc(pcb2,
|
||||
pcb2->pcb_ldt->ldt_len);
|
||||
if (pcb2->pcb_ldt == NULL)
|
||||
panic("could not copy LDT");
|
||||
}
|
||||
}
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
|
||||
/*
|
||||
* Now, cpu_switch() can schedule the new process.
|
||||
|
@ -53,6 +53,7 @@ struct pcb_ldt {
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
int i386_extend_pcb __P((struct proc *));
|
||||
void set_user_ldt __P((struct pcb *));
|
||||
struct pcb_ldt *user_ldt_alloc __P((struct pcb *, int));
|
||||
void user_ldt_free __P((struct pcb *));
|
||||
|
@ -68,7 +68,6 @@ static int i386_get_ldt __P((struct proc *, char *));
|
||||
static int i386_set_ldt __P((struct proc *, char *));
|
||||
static int i386_get_ioperm __P((struct proc *, char *));
|
||||
static int i386_set_ioperm __P((struct proc *, char *));
|
||||
int i386_extend_pcb __P((struct proc *));
|
||||
|
||||
#ifndef _SYS_SYSPROTO_H_
|
||||
struct sysarch_args {
|
||||
@ -128,7 +127,6 @@ i386_extend_pcb(struct proc *p)
|
||||
ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1));
|
||||
if (ext == 0)
|
||||
return (ENOMEM);
|
||||
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);
|
||||
@ -151,14 +149,12 @@ i386_extend_pcb(struct proc *p)
|
||||
ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext);
|
||||
ssdtosd(&ssd, &ext->ext_tssd);
|
||||
|
||||
/* switch to the new TSS after syscall completes */
|
||||
/*
|
||||
* XXX: The sched_lock here needs to be over a slightly larger area.
|
||||
* I have patches to more properly lock accesses to process ldt's
|
||||
* and tss's that still need to be reviewed, but this keeps us from
|
||||
* panic'ing on the mtx_assert() in need_resched() for the time being.
|
||||
*/
|
||||
KASSERT(p == curproc, ("giving a TSS to non-curproc"));
|
||||
KASSERT(p->p_addr->u_pcb.pcb_ext == 0, ("already have a TSS!"));
|
||||
mtx_lock_spin(&sched_lock);
|
||||
p->p_addr->u_pcb.pcb_ext = ext;
|
||||
|
||||
/* switch to the new TSS after syscall completes */
|
||||
need_resched(p);
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
|
||||
@ -254,6 +250,7 @@ set_user_ldt(struct pcb *pcb)
|
||||
if (pcb != PCPU_GET(curpcb))
|
||||
return;
|
||||
|
||||
mtx_lock_spin(&sched_lock);
|
||||
pcb_ldt = pcb->pcb_ldt;
|
||||
#ifdef SMP
|
||||
gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
|
||||
@ -262,17 +259,23 @@ set_user_ldt(struct pcb *pcb)
|
||||
#endif
|
||||
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with either sched_lock free or held but not recursed.
|
||||
* If it does not return NULL, it will return with it owned.
|
||||
*/
|
||||
struct pcb_ldt *
|
||||
user_ldt_alloc(struct pcb *pcb, int len)
|
||||
{
|
||||
struct pcb_ldt *pcb_ldt, *new_ldt;
|
||||
|
||||
if (mtx_owned(&sched_lock))
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
mtx_assert(&sched_lock, MA_NOTOWNED);
|
||||
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,
|
||||
@ -284,6 +287,7 @@ user_ldt_alloc(struct pcb *pcb, int len)
|
||||
new_ldt->ldt_refcnt = 1;
|
||||
new_ldt->ldt_active = 0;
|
||||
|
||||
mtx_lock_spin(&sched_lock);
|
||||
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);
|
||||
@ -299,6 +303,10 @@ user_ldt_alloc(struct pcb *pcb, int len)
|
||||
return new_ldt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called either with sched_lock free or held but not recursed.
|
||||
* If pcb->pcb_ldt is not NULL, it will return with sched_lock released.
|
||||
*/
|
||||
void
|
||||
user_ldt_free(struct pcb *pcb)
|
||||
{
|
||||
@ -307,17 +315,22 @@ user_ldt_free(struct pcb *pcb)
|
||||
if (pcb_ldt == NULL)
|
||||
return;
|
||||
|
||||
if (!mtx_owned(&sched_lock))
|
||||
mtx_lock_spin(&sched_lock);
|
||||
mtx_assert(&sched_lock, MA_OWNED | MA_NOTRECURSED);
|
||||
if (pcb == PCPU_GET(curpcb)) {
|
||||
lldt(_default_ldt);
|
||||
PCPU_SET(currentldt, _default_ldt);
|
||||
}
|
||||
|
||||
pcb->pcb_ldt = NULL;
|
||||
if (--pcb_ldt->ldt_refcnt == 0) {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
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;
|
||||
} else
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -330,7 +343,6 @@ i386_get_ldt(p, args)
|
||||
struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
|
||||
int nldt, num;
|
||||
union descriptor *lp;
|
||||
int s;
|
||||
struct i386_ldt_args ua, *uap = &ua;
|
||||
|
||||
if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
|
||||
@ -345,8 +357,6 @@ i386_get_ldt(p, args)
|
||||
if ((uap->start < 0) || (uap->num <= 0))
|
||||
return(EINVAL);
|
||||
|
||||
s = splhigh();
|
||||
|
||||
if (pcb_ldt) {
|
||||
nldt = pcb_ldt->ldt_len;
|
||||
num = min(uap->num, nldt);
|
||||
@ -356,16 +366,13 @@ i386_get_ldt(p, args)
|
||||
num = min(uap->num, nldt);
|
||||
lp = &ldt[uap->start];
|
||||
}
|
||||
if (uap->start > nldt) {
|
||||
splx(s);
|
||||
if (uap->start > nldt)
|
||||
return(EINVAL);
|
||||
}
|
||||
|
||||
error = copyout(lp, uap->descs, num * sizeof(union descriptor));
|
||||
if (!error)
|
||||
p->p_retval[0] = num;
|
||||
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -378,8 +385,10 @@ i386_set_ldt(p, args)
|
||||
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;
|
||||
caddr_t old_ldt_base;
|
||||
int old_ldt_len;
|
||||
critical_t savecrit;
|
||||
|
||||
if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
|
||||
return(error);
|
||||
@ -405,14 +414,19 @@ i386_set_ldt(p, args)
|
||||
if (new_ldt == NULL)
|
||||
return ENOMEM;
|
||||
if (pcb_ldt) {
|
||||
old_ldt_base = pcb_ldt->ldt_base;
|
||||
old_ldt_len = pcb_ldt->ldt_len;
|
||||
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;
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
kmem_free(kernel_map, (vm_offset_t)old_ldt_base,
|
||||
old_ldt_len * sizeof(union descriptor));
|
||||
FREE(new_ldt, M_SUBPROC);
|
||||
} else
|
||||
} else {
|
||||
pcb->pcb_ldt = pcb_ldt = new_ldt;
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
#ifdef SMP
|
||||
/* signal other cpus to reload ldt */
|
||||
smp_rendezvous(NULL, (void (*)(void *))set_user_ldt, NULL, pcb);
|
||||
@ -453,6 +467,7 @@ i386_set_ldt(p, args)
|
||||
* for OS use only.
|
||||
*/
|
||||
return EACCES;
|
||||
/*NOTREACHED*/
|
||||
|
||||
/* memory segment types */
|
||||
case SDT_MEMEC: /* memory execute only conforming */
|
||||
@ -486,15 +501,14 @@ i386_set_ldt(p, args)
|
||||
return (EACCES);
|
||||
}
|
||||
|
||||
s = splhigh();
|
||||
|
||||
/* Fill in range */
|
||||
savecrit = critical_enter();
|
||||
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;
|
||||
critical_exit(savecrit);
|
||||
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include <machine/specialreg.h>
|
||||
#include <machine/sysarch.h>
|
||||
|
||||
extern int i386_extend_pcb __P((struct proc *));
|
||||
extern int vm86pa;
|
||||
extern struct pcb *vm86pcb;
|
||||
|
||||
|
@ -184,14 +184,18 @@ cpu_fork(p1, p2, flags)
|
||||
pcb2->pcb_ext = 0;
|
||||
|
||||
/* Copy the LDT, if necessary. */
|
||||
mtx_lock_spin(&sched_lock);
|
||||
if (pcb2->pcb_ldt != 0) {
|
||||
if (flags & RFMEM) {
|
||||
pcb2->pcb_ldt->ldt_refcnt++;
|
||||
} else {
|
||||
pcb2->pcb_ldt = user_ldt_alloc(pcb2,
|
||||
pcb2->pcb_ldt->ldt_len);
|
||||
if (pcb2->pcb_ldt == NULL)
|
||||
panic("could not copy LDT");
|
||||
}
|
||||
}
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
|
||||
/*
|
||||
* Now, cpu_switch() can schedule the new process.
|
||||
|
@ -53,6 +53,7 @@ struct pcb_ldt {
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
int i386_extend_pcb __P((struct proc *));
|
||||
void set_user_ldt __P((struct pcb *));
|
||||
struct pcb_ldt *user_ldt_alloc __P((struct pcb *, int));
|
||||
void user_ldt_free __P((struct pcb *));
|
||||
|
Loading…
Reference in New Issue
Block a user