summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>1999-09-02 21:50:42 +0000
committermarcel <marcel@FreeBSD.org>1999-09-02 21:50:42 +0000
commitff51285d108763e4c51418dc9a601851ceb4b3ff (patch)
treee0e193cc5b4201fa7d9f94bd32c7446efd23e636 /sys/i386
parent4c5411b9843c8495b8a598f58e68862e99661150 (diff)
downloadFreeBSD-src-ff51285d108763e4c51418dc9a601851ceb4b3ff.zip
FreeBSD-src-ff51285d108763e4c51418dc9a601851ceb4b3ff.tar.gz
Implementation of the modify_ldt syscall. Use the sysarch() interface to do
the actual work. When USER_LDT is not defined for a kernel, sysarch returns EOPNOTSUPP. Display a message in that case and return ENOSYS to userland. Reviewed by: luoqi
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/linux/linux_dummy.c1
-rw-r--r--sys/i386/linux/linux_misc.c84
2 files changed, 84 insertions, 1 deletions
diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c
index c76402c..67e3a1a 100644
--- a/sys/i386/linux/linux_dummy.c
+++ b/sys/i386/linux/linux_dummy.c
@@ -77,7 +77,6 @@ DUMMY(idle);
DUMMY(vm86old);
DUMMY(swapoff);
DUMMY(sysinfo);
-DUMMY(modify_ldt);
DUMMY(adjtimex);
DUMMY(create_module);
DUMMY(init_module);
diff --git a/sys/i386/linux/linux_misc.c b/sys/i386/linux/linux_misc.c
index 323ecdb..2dd6a80 100644
--- a/sys/i386/linux/linux_misc.c
+++ b/sys/i386/linux/linux_misc.c
@@ -57,6 +57,8 @@
#include <machine/frame.h>
#include <machine/psl.h>
+#include <machine/sysarch.h>
+#include <machine/segments.h>
#include <i386/linux/linux.h>
#include <i386/linux/linux_proto.h>
@@ -1343,3 +1345,85 @@ linux_sched_getscheduler(p, uap)
return error;
}
+
+struct linux_descriptor {
+ unsigned int entry_number;
+ unsigned long base_addr;
+ unsigned int limit;
+ unsigned int seg_32bit:1;
+ unsigned int contents:2;
+ unsigned int read_exec_only:1;
+ unsigned int limit_in_pages:1;
+ unsigned int seg_not_present:1;
+ unsigned int useable:1;
+};
+
+int
+linux_modify_ldt(p, uap)
+ struct proc *p;
+ struct linux_modify_ldt_args *uap;
+{
+ int error;
+ caddr_t sg;
+ struct sysarch_args args;
+ struct i386_ldt_args *ldt;
+ struct linux_descriptor ld;
+ union descriptor *desc;
+
+ sg = stackgap_init();
+
+ if (uap->ptr == NULL)
+ return (EINVAL);
+
+ switch (uap->func) {
+ case 0x00: /* read_ldt */
+ ldt = stackgap_alloc(&sg, sizeof(*ldt));
+ ldt->start = 0;
+ ldt->desc = uap->ptr;
+ ldt->num = uap->bytecount / sizeof(union descriptor);
+ args.op = I386_GET_LDT;
+ args.parms = (char*)ldt;
+ error = sysarch(p, &args);
+ p->p_retval[0] *= sizeof(union descriptor);
+ break;
+ case 0x01: /* write_ldt */
+ case 0x11: /* write_ldt */
+ if (uap->bytecount != sizeof(ld))
+ return (EINVAL);
+
+ error = copyin(uap->ptr, &ld, sizeof(ld));
+ if (error)
+ return (error);
+
+ ldt = stackgap_alloc(&sg, sizeof(*ldt));
+ desc = stackgap_alloc(&sg, sizeof(*desc));
+ ldt->start = ld.entry_number;
+ ldt->desc = 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(p, &args);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ if (error == EOPNOTSUPP) {
+ printf("linux: modify_ldt needs kernel option USER_LDT\n");
+ error = ENOSYS;
+ }
+
+ return (error);
+}
OpenPOWER on IntegriCloud