o Move copyin()/copyout() out of i386_{get,set}_ldt() and
i386_{get,set}_ioperm() and make those APIs visible in the kernel namespace; o use i386_{get,set}_ldt() and i386_{get,set}_ioperm() instead of sysarch() in the linuxlator, which allows to kill another two stackgaps. MFC after: 2 weeks
This commit is contained in:
parent
3f0d8e467c
commit
ef41053770
@ -65,13 +65,9 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
|
||||
|
||||
static int i386_get_ldt(struct thread *, char *);
|
||||
static int i386_set_ldt(struct thread *, char *);
|
||||
static int i386_set_ldt_data(struct thread *, int start, int num,
|
||||
union descriptor *descs);
|
||||
static int i386_ldt_grow(struct thread *td, int len);
|
||||
static int i386_get_ioperm(struct thread *, char *);
|
||||
static int i386_set_ioperm(struct thread *, char *);
|
||||
#ifdef SMP
|
||||
static void set_user_ldt_rv(struct thread *);
|
||||
#endif
|
||||
@ -89,21 +85,60 @@ sysarch(td, uap)
|
||||
register struct sysarch_args *uap;
|
||||
{
|
||||
int error;
|
||||
union descriptor *lp;
|
||||
union {
|
||||
struct i386_ldt_args largs;
|
||||
struct i386_ioperm_args iargs;
|
||||
} kargs;
|
||||
|
||||
switch (uap->op) {
|
||||
case I386_GET_IOPERM:
|
||||
case I386_SET_IOPERM:
|
||||
if ((error = copyin(uap->parms, &kargs.iargs,
|
||||
sizeof(struct i386_ioperm_args))) != 0)
|
||||
return (error);
|
||||
break;
|
||||
case I386_GET_LDT:
|
||||
case I386_SET_LDT:
|
||||
if ((error = copyin(uap->parms, &kargs.largs,
|
||||
sizeof(struct i386_ldt_args))) != 0)
|
||||
return (error);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mtx_lock(&Giant);
|
||||
switch(uap->op) {
|
||||
case I386_GET_LDT:
|
||||
error = i386_get_ldt(td, uap->parms);
|
||||
error = i386_get_ldt(td, &kargs.largs);
|
||||
break;
|
||||
|
||||
case I386_SET_LDT:
|
||||
error = i386_set_ldt(td, uap->parms);
|
||||
if (kargs.largs.descs != NULL) {
|
||||
lp = (union descriptor *)kmem_alloc(kernel_map,
|
||||
kargs.largs.num * sizeof(union descriptor));
|
||||
if (lp == NULL) {
|
||||
error = ENOMEM;
|
||||
break;
|
||||
}
|
||||
error = copyin(kargs.largs.descs, lp,
|
||||
kargs.largs.num * sizeof(union descriptor));
|
||||
if (error == 0)
|
||||
error = i386_set_ldt(td, &kargs.largs, lp);
|
||||
kmem_free(kernel_map, (vm_offset_t)lp,
|
||||
kargs.largs.num * sizeof(union descriptor));
|
||||
} else {
|
||||
error = i386_set_ldt(td, &kargs.largs, NULL);
|
||||
}
|
||||
break;
|
||||
case I386_GET_IOPERM:
|
||||
error = i386_get_ioperm(td, uap->parms);
|
||||
error = i386_get_ioperm(td, &kargs.iargs);
|
||||
if (error == 0)
|
||||
error = copyout(&kargs.iargs, uap->parms,
|
||||
sizeof(struct i386_ioperm_args));
|
||||
break;
|
||||
case I386_SET_IOPERM:
|
||||
error = i386_set_ioperm(td, uap->parms);
|
||||
error = i386_set_ioperm(td, &kargs.iargs);
|
||||
break;
|
||||
case I386_VM86:
|
||||
error = vm86_sysarch(td, uap->parms);
|
||||
@ -175,18 +210,14 @@ i386_extend_pcb(struct thread *td)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i386_set_ioperm(td, args)
|
||||
int
|
||||
i386_set_ioperm(td, uap)
|
||||
struct thread *td;
|
||||
char *args;
|
||||
struct i386_ioperm_args *uap;
|
||||
{
|
||||
int i, error;
|
||||
struct i386_ioperm_args ua;
|
||||
char *iomap;
|
||||
|
||||
if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0)
|
||||
return (error);
|
||||
|
||||
#ifdef MAC
|
||||
if ((error = mac_check_sysarch_ioperm(td->td_ucred)) != 0)
|
||||
return (error);
|
||||
@ -207,11 +238,11 @@ i386_set_ioperm(td, args)
|
||||
return (error);
|
||||
iomap = (char *)td->td_pcb->pcb_ext->ext_iomap;
|
||||
|
||||
if (ua.start + ua.length > IOPAGES * PAGE_SIZE * NBBY)
|
||||
if (uap->start + uap->length > IOPAGES * PAGE_SIZE * NBBY)
|
||||
return (EINVAL);
|
||||
|
||||
for (i = ua.start; i < ua.start + ua.length; i++) {
|
||||
if (ua.enable)
|
||||
for (i = uap->start; i < uap->start + uap->length; i++) {
|
||||
if (uap->enable)
|
||||
iomap[i >> 3] &= ~(1 << (i & 7));
|
||||
else
|
||||
iomap[i >> 3] |= (1 << (i & 7));
|
||||
@ -219,41 +250,37 @@ i386_set_ioperm(td, args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
i386_get_ioperm(td, args)
|
||||
int
|
||||
i386_get_ioperm(td, uap)
|
||||
struct thread *td;
|
||||
char *args;
|
||||
struct i386_ioperm_args *uap;
|
||||
{
|
||||
int i, state, error;
|
||||
struct i386_ioperm_args ua;
|
||||
int i, state;
|
||||
char *iomap;
|
||||
|
||||
if ((error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) != 0)
|
||||
return (error);
|
||||
if (ua.start >= IOPAGES * PAGE_SIZE * NBBY)
|
||||
if (uap->start >= IOPAGES * PAGE_SIZE * NBBY)
|
||||
return (EINVAL);
|
||||
|
||||
if (td->td_pcb->pcb_ext == 0) {
|
||||
ua.length = 0;
|
||||
uap->length = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
iomap = (char *)td->td_pcb->pcb_ext->ext_iomap;
|
||||
|
||||
i = ua.start;
|
||||
i = uap->start;
|
||||
state = (iomap[i >> 3] >> (i & 7)) & 1;
|
||||
ua.enable = !state;
|
||||
ua.length = 1;
|
||||
uap->enable = !state;
|
||||
uap->length = 1;
|
||||
|
||||
for (i = ua.start + 1; i < IOPAGES * PAGE_SIZE * NBBY; i++) {
|
||||
for (i = uap->start + 1; i < IOPAGES * PAGE_SIZE * NBBY; i++) {
|
||||
if (state != ((iomap[i >> 3] >> (i & 7)) & 1))
|
||||
break;
|
||||
ua.length++;
|
||||
uap->length++;
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
error = copyout(&ua, args, sizeof(struct i386_ioperm_args));
|
||||
return (error);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -363,19 +390,21 @@ user_ldt_free(struct thread *td)
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
i386_get_ldt(td, args)
|
||||
/*
|
||||
* Note for the authors of compat layers (linux, etc): copyout() in
|
||||
* the function below is not a problem since it presents data in
|
||||
* arch-specific format (i.e. i386-specific in this case), not in
|
||||
* the OS-specific one.
|
||||
*/
|
||||
int
|
||||
i386_get_ldt(td, uap)
|
||||
struct thread *td;
|
||||
char *args;
|
||||
struct i386_ldt_args *uap;
|
||||
{
|
||||
int error = 0;
|
||||
struct proc_ldt *pldt = td->td_proc->p_md.md_ldt;
|
||||
int nldt, num;
|
||||
union descriptor *lp;
|
||||
struct i386_ldt_args ua, *uap = &ua;
|
||||
|
||||
if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
|
||||
return(error);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("i386_get_ldt: start=%d num=%d descs=%p\n",
|
||||
@ -408,28 +437,24 @@ i386_get_ldt(td, args)
|
||||
static int ldt_warnings;
|
||||
#define NUM_LDT_WARNINGS 10
|
||||
|
||||
static int
|
||||
i386_set_ldt(td, args)
|
||||
int
|
||||
i386_set_ldt(td, uap, descs)
|
||||
struct thread *td;
|
||||
char *args;
|
||||
struct i386_ldt_args *uap;
|
||||
union descriptor *descs;
|
||||
{
|
||||
int error = 0, i;
|
||||
int largest_ld;
|
||||
struct mdproc *mdp = &td->td_proc->p_md;
|
||||
struct proc_ldt *pldt = NULL;
|
||||
struct i386_ldt_args ua, *uap = &ua;
|
||||
union descriptor *descs, *dp;
|
||||
int descs_size;
|
||||
|
||||
if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0)
|
||||
return(error);
|
||||
union descriptor *dp;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("i386_set_ldt: start=%d num=%d descs=%p\n",
|
||||
uap->start, uap->num, (void *)uap->descs);
|
||||
#endif
|
||||
|
||||
if (uap->descs == NULL) {
|
||||
if (descs == NULL) {
|
||||
/* Free descriptors */
|
||||
if (uap->start == 0 && uap->num == 0) {
|
||||
/*
|
||||
@ -472,16 +497,6 @@ i386_set_ldt(td, args)
|
||||
}
|
||||
}
|
||||
|
||||
descs_size = uap->num * sizeof(union descriptor);
|
||||
descs = (union descriptor *)kmem_alloc(kernel_map, descs_size);
|
||||
if (descs == NULL)
|
||||
return (ENOMEM);
|
||||
error = copyin(uap->descs, descs, descs_size);
|
||||
if (error) {
|
||||
kmem_free(kernel_map, (vm_offset_t)descs, descs_size);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Check descriptors for access violations */
|
||||
for (i = 0; i < uap->num; i++) {
|
||||
dp = &descs[i];
|
||||
@ -509,7 +524,6 @@ i386_set_ldt(td, args)
|
||||
* to create a segment of these types. They are
|
||||
* for OS use only.
|
||||
*/
|
||||
kmem_free(kernel_map, (vm_offset_t)descs, descs_size);
|
||||
return (EACCES);
|
||||
/*NOTREACHED*/
|
||||
|
||||
@ -519,11 +533,8 @@ i386_set_ldt(td, args)
|
||||
case SDT_MEMERC: /* memory execute read conforming */
|
||||
case SDT_MEMERAC: /* memory execute read accessed conforming */
|
||||
/* Must be "present" if executable and conforming. */
|
||||
if (dp->sd.sd_p == 0) {
|
||||
kmem_free(kernel_map, (vm_offset_t)descs,
|
||||
descs_size);
|
||||
if (dp->sd.sd_p == 0)
|
||||
return (EACCES);
|
||||
}
|
||||
break;
|
||||
case SDT_MEMRO: /* memory read only */
|
||||
case SDT_MEMROA: /* memory read only accessed */
|
||||
@ -539,16 +550,13 @@ i386_set_ldt(td, args)
|
||||
case SDT_MEMERA: /* memory execute read accessed */
|
||||
break;
|
||||
default:
|
||||
kmem_free(kernel_map, (vm_offset_t)descs, descs_size);
|
||||
return(EINVAL);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* Only user (ring-3) descriptors may be present. */
|
||||
if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL)) {
|
||||
kmem_free(kernel_map, (vm_offset_t)descs, descs_size);
|
||||
if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL))
|
||||
return (EACCES);
|
||||
}
|
||||
}
|
||||
|
||||
if (uap->start == LDT_AUTO_ALLOC && uap->num == 1) {
|
||||
@ -556,11 +564,8 @@ i386_set_ldt(td, args)
|
||||
pldt = mdp->md_ldt;
|
||||
if (pldt == NULL) {
|
||||
error = i386_ldt_grow(td, NLDT + 1);
|
||||
if (error) {
|
||||
kmem_free(kernel_map, (vm_offset_t)descs,
|
||||
descs_size);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
pldt = mdp->md_ldt;
|
||||
}
|
||||
again:
|
||||
@ -578,11 +583,8 @@ again:
|
||||
if (i >= pldt->ldt_len) {
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
error = i386_ldt_grow(td, pldt->ldt_len+1);
|
||||
if (error) {
|
||||
kmem_free(kernel_map, (vm_offset_t)descs,
|
||||
descs_size);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
uap->start = i;
|
||||
@ -598,7 +600,6 @@ again:
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
}
|
||||
kmem_free(kernel_map, (vm_offset_t)descs, descs_size);
|
||||
if (error == 0)
|
||||
td->td_retval[0] = uap->start;
|
||||
return (error);
|
||||
|
@ -88,6 +88,14 @@ int i386_set_watch(int, unsigned int, int, int, struct dbreg *);
|
||||
int i386_clr_watch(int, struct dbreg *);
|
||||
int sysarch(int, void *);
|
||||
__END_DECLS
|
||||
#else
|
||||
struct thread;
|
||||
union descriptor;
|
||||
|
||||
int i386_get_ldt(struct thread *, struct i386_ldt_args *);
|
||||
int i386_set_ldt(struct thread *, struct i386_ldt_args *, union descriptor *);
|
||||
int i386_get_ioperm(struct thread *, struct i386_ioperm_args *);
|
||||
int i386_set_ioperm(struct thread *, struct i386_ioperm_args *);
|
||||
#endif
|
||||
|
||||
#endif /* !_MACHINE_SYSARCH_H_ */
|
||||
|
@ -581,18 +581,16 @@ linux_pipe(struct thread *td, struct linux_pipe_args *args)
|
||||
int
|
||||
linux_ioperm(struct thread *td, struct linux_ioperm_args *args)
|
||||
{
|
||||
struct sysarch_args sa;
|
||||
struct i386_ioperm_args *iia;
|
||||
caddr_t sg;
|
||||
int error;
|
||||
struct i386_ioperm_args iia;
|
||||
|
||||
sg = stackgap_init();
|
||||
iia = stackgap_alloc(&sg, sizeof(struct i386_ioperm_args));
|
||||
iia->start = args->start;
|
||||
iia->length = args->length;
|
||||
iia->enable = args->enable;
|
||||
sa.op = I386_SET_IOPERM;
|
||||
sa.parms = (char *)iia;
|
||||
return (sysarch(td, &sa));
|
||||
iia.start = args->start;
|
||||
iia.length = args->length;
|
||||
iia.enable = args->enable;
|
||||
mtx_lock(&Giant);
|
||||
error = i386_set_ioperm(td, &iia);
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
@ -615,27 +613,22 @@ int
|
||||
linux_modify_ldt(struct thread *td, struct linux_modify_ldt_args *uap)
|
||||
{
|
||||
int error;
|
||||
caddr_t sg;
|
||||
struct sysarch_args args;
|
||||
struct i386_ldt_args *ldt;
|
||||
struct i386_ldt_args ldt;
|
||||
struct l_descriptor ld;
|
||||
union descriptor *desc;
|
||||
|
||||
sg = stackgap_init();
|
||||
union descriptor desc;
|
||||
|
||||
if (uap->ptr == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
switch (uap->func) {
|
||||
case 0x00: /* read_ldt */
|
||||
ldt = stackgap_alloc(&sg, sizeof(*ldt));
|
||||
ldt->start = 0;
|
||||
ldt->descs = uap->ptr;
|
||||
ldt->num = uap->bytecount / sizeof(union descriptor);
|
||||
args.op = I386_GET_LDT;
|
||||
args.parms = (char*)ldt;
|
||||
error = sysarch(td, &args);
|
||||
ldt.start = 0;
|
||||
ldt.descs = uap->ptr;
|
||||
ldt.num = uap->bytecount / sizeof(union descriptor);
|
||||
mtx_lock(&Giant);
|
||||
error = i386_get_ldt(td, &ldt);
|
||||
td->td_retval[0] *= sizeof(union descriptor);
|
||||
mtx_unlock(&Giant);
|
||||
break;
|
||||
case 0x01: /* write_ldt */
|
||||
case 0x11: /* write_ldt */
|
||||
@ -646,25 +639,23 @@ linux_modify_ldt(struct thread *td, struct linux_modify_ldt_args *uap)
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
ldt = stackgap_alloc(&sg, sizeof(*ldt));
|
||||
desc = stackgap_alloc(&sg, sizeof(*desc));
|
||||
ldt->start = ld.entry_number;
|
||||
ldt->descs = desc;
|
||||
ldt->num = 1;
|
||||
desc->sd.sd_lolimit = (ld.limit & 0x0000ffff);
|
||||
desc->sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
|
||||
desc->sd.sd_lobase = (ld.base_addr & 0x00ffffff);
|
||||
desc->sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
|
||||
desc->sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
|
||||
ldt.start = ld.entry_number;
|
||||
ldt.descs = &desc;
|
||||
ldt.num = 1;
|
||||
desc.sd.sd_lolimit = (ld.limit & 0x0000ffff);
|
||||
desc.sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
|
||||
desc.sd.sd_lobase = (ld.base_addr & 0x00ffffff);
|
||||
desc.sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
|
||||
desc.sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
|
||||
(ld.contents << 2);
|
||||
desc->sd.sd_dpl = 3;
|
||||
desc->sd.sd_p = (ld.seg_not_present ^ 1);
|
||||
desc->sd.sd_xx = 0;
|
||||
desc->sd.sd_def32 = ld.seg_32bit;
|
||||
desc->sd.sd_gran = ld.limit_in_pages;
|
||||
args.op = I386_SET_LDT;
|
||||
args.parms = (char*)ldt;
|
||||
error = sysarch(td, &args);
|
||||
desc.sd.sd_dpl = 3;
|
||||
desc.sd.sd_p = (ld.seg_not_present ^ 1);
|
||||
desc.sd.sd_xx = 0;
|
||||
desc.sd.sd_def32 = ld.seg_32bit;
|
||||
desc.sd.sd_gran = ld.limit_in_pages;
|
||||
mtx_lock(&Giant);
|
||||
error = i386_set_ldt(td, &ldt, &desc);
|
||||
mtx_unlock(&Giant);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user