summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2005-01-26 13:59:46 +0000
committersobomax <sobomax@FreeBSD.org>2005-01-26 13:59:46 +0000
commitef410537709bade6c0f73294ab4c6702637c582c (patch)
tree1977517e0838d86134452dce17f9b9cf695ba1a4
parent3f0d8e467c82773cd96f4e8a6daed7e6cdf02c2c (diff)
downloadFreeBSD-src-ef410537709bade6c0f73294ab4c6702637c582c.zip
FreeBSD-src-ef410537709bade6c0f73294ab4c6702637c582c.tar.gz
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
-rw-r--r--sys/i386/i386/sys_machdep.c163
-rw-r--r--sys/i386/include/sysarch.h8
-rw-r--r--sys/i386/linux/linux_machdep.c77
3 files changed, 124 insertions, 124 deletions
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
index 9aeb050..0056843 100644
--- a/sys/i386/i386/sys_machdep.c
+++ b/sys/i386/i386/sys_machdep.c
@@ -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);
diff --git a/sys/i386/include/sysarch.h b/sys/i386/include/sysarch.h
index b117943..899ebd8 100644
--- a/sys/i386/include/sysarch.h
+++ b/sys/i386/include/sysarch.h
@@ -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_ */
diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c
index 4d334ba..2a825e8 100644
--- a/sys/i386/linux/linux_machdep.c
+++ b/sys/i386/linux/linux_machdep.c
@@ -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;
-
- 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));
+ int error;
+ struct i386_ioperm_args iia;
+
+ 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;
OpenPOWER on IntegriCloud