summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--i386/i386/gdt.h4
-rw-r--r--i386/i386/pcb.c7
-rw-r--r--i386/i386/thread.h2
-rw-r--r--i386/i386/user_ldt.c54
-rw-r--r--i386/include/mach/i386/mach_i386.defs16
-rw-r--r--linux/dev/include/linux/head.h20
7 files changed, 118 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 29e2e39..23db3fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2006-11-05 Barry deFreese <bddebian@comcast.net>
+
+ [task #5878 --- ``Backport code from GNU Mach's trunk to
+ gnumach-1-branch: i386_set_gdt, i386_get_gdt'']
+
+ * i386/include/mach/i386/mach_i386.defs (i386_set_gdt, i386_get_gdt):
+ New routines.
+ * i386/i386/user_ldt.c (i386_set_gdt, i386_get_gdt): New functions.
+ * i386/i386/gdt.h (USER_GDT, USER_GDT_SLOTS): New macros.
+ (GDTSZ): Compute it from USER_GDT and USER_GDT_SLOTS.
+ * i386/i386/thread.h: Include `gdt.h'.
+ (struct i386_machine_state): New member `user_gdt'.
+ * i386/i386/pcb.c (switch_ktss): Copy those slots into the GDT.
+ * linux/dev/include/linux/head.h: New file.
+
2006-11-05 Samuel Thibault <samuel.thibault@ens-lyon.org>
FPU, CPU and IO stubs cleanup.
@@ -36,7 +51,7 @@
* device/ds_routines.c (device_write_get, ds_read_done): Likewise.
* device/kmsg.c: Likewise.
* device/net_io.c (net_filter, net_set_filter, net_getstat): Likewise.
- * i386/i386/fpu.c (fpu_set_state, fpu_get_state) fp_load)
+ * i386/i386/fpu.c (fpu_set_state, fpu_get_state, fp_load)
(fp_state_alloc): Likewise.
* i386/i386/iopb.c (io_tss_init, i386_io_port_list): Likewise.
* i386/i386/mp_desc.c (mp_desc_init): Likewise.
diff --git a/i386/i386/gdt.h b/i386/i386/gdt.h
index 49cb0d3..4715759 100644
--- a/i386/i386/gdt.h
+++ b/i386/i386/gdt.h
@@ -49,8 +49,10 @@
#define USER_FPREGS 0x40 /* user-mode access to saved
floating-point registers */
-#define GDTSZ 11
+#define USER_GDT 0x48 /* user-defined GDT entries */
+#define USER_GDT_SLOTS 2
+#define GDTSZ (USER_GDT/8 + USER_GDT_SLOTS)
extern struct real_descriptor gdt[GDTSZ];
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c
index 9665caa..a18a5e6 100644
--- a/i386/i386/pcb.c
+++ b/i386/i386/pcb.c
@@ -191,6 +191,13 @@ void switch_ktss(pcb)
set_ldt(USER_LDT);
}
}
+
+ /* Copy in the per-thread GDT slots. No reloading is necessary
+ because just restoring the segment registers on the way back to
+ user mode reloads the shadow registers from the in-memory GDT. */
+ memcpy (gdt_desc_p (mycpu, USER_GDT),
+ pcb->ims.user_gdt, sizeof pcb->ims.user_gdt);
+
/*
* Load the floating-point context, if necessary.
*/
diff --git a/i386/i386/thread.h b/i386/i386/thread.h
index 027193a..337190e 100644
--- a/i386/i386/thread.h
+++ b/i386/i386/thread.h
@@ -41,6 +41,7 @@
#include <i386/iopb.h>
#include <i386/tss.h>
+#include "gdt.h"
/*
* i386_saved_state:
@@ -161,6 +162,7 @@ struct i386_machine_state {
struct user_ldt * ldt;
struct i386_fpsave_state *ifps;
struct v86_assist_state v86s;
+ struct real_descriptor user_gdt[USER_GDT_SLOTS];
};
typedef struct pcb {
diff --git a/i386/i386/user_ldt.c b/i386/i386/user_ldt.c
index 33724ec..3f37599 100644
--- a/i386/i386/user_ldt.c
+++ b/i386/i386/user_ldt.c
@@ -401,3 +401,57 @@ user_ldt_free(user_ldt)
user_ldt->desc.limit_low + 1
+ sizeof(struct real_descriptor));
}
+
+
+kern_return_t
+i386_set_gdt (thread_t thread, int *selector, struct real_descriptor desc)
+{
+ int idx;
+
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ if (*selector == -1)
+ {
+ for (idx = 0; idx < USER_GDT_SLOTS; ++idx)
+ if ((thread->pcb->ims.user_gdt[idx].access & ACC_P) == 0)
+ {
+ *selector = ((idx + sel_idx(USER_GDT)) << 3) | SEL_PL_U;
+ break;
+ }
+ if (idx == USER_GDT_SLOTS)
+ return KERN_NO_SPACE; /* ? */
+ }
+ else if ((*selector & (SEL_LDT|SEL_PL)) != SEL_PL_U
+ || sel_idx (*selector) < sel_idx(USER_GDT)
+ || sel_idx (*selector) >= sel_idx(USER_GDT) + USER_GDT_SLOTS)
+ return KERN_INVALID_ARGUMENT;
+ else
+ idx = sel_idx (*selector) - sel_idx(USER_GDT);
+
+ if ((desc.access & ACC_P) == 0)
+ memset (&thread->pcb->ims.user_gdt[idx], 0,
+ sizeof thread->pcb->ims.user_gdt[idx]);
+ else if ((desc.access & (ACC_TYPE_USER|ACC_PL)) != (ACC_TYPE_USER|ACC_PL_U))
+ return KERN_INVALID_ARGUMENT;
+ else
+ thread->pcb->ims.user_gdt[idx] = desc;
+
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+i386_get_gdt (thread_t thread, int selector, struct real_descriptor *desc)
+{
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ if ((selector & (SEL_LDT|SEL_PL)) != SEL_PL_U
+ || sel_idx (selector) < sel_idx(USER_GDT)
+ || sel_idx (selector) >= sel_idx(USER_GDT) + USER_GDT_SLOTS)
+ return KERN_INVALID_ARGUMENT;
+
+ *desc = thread->pcb->ims.user_gdt[sel_idx (selector) - sel_idx(USER_GDT)];
+
+ return KERN_SUCCESS;
+}
diff --git a/i386/include/mach/i386/mach_i386.defs b/i386/include/mach/i386/mach_i386.defs
index 55121b6..1f98dc3 100644
--- a/i386/include/mach/i386/mach_i386.defs
+++ b/i386/include/mach/i386/mach_i386.defs
@@ -66,3 +66,19 @@ routine i386_get_ldt(
first_selector : int;
selector_count : int;
out desc_list : descriptor_list_t);
+
+/* Modify one of a few available thread-specific segment descriptor slots.
+ The SELECTOR must be a value from a previous call (on any thread),
+ or -1 to allocate an available slot and return the segment selector for it.
+ These slots are copied into the CPU on each thread switch.
+ Returns KERN_NO_SPACE when there are no more slots available. */
+routine i386_set_gdt(
+ target_thread : thread_t;
+ inout selector : int;
+ desc : descriptor_t);
+
+/* Fetch a segment descriptor set with a prior i386_set_gdt call. */
+routine i386_get_gdt(
+ target_thread : thread_t;
+ selector : int;
+ out desc : descriptor_t);
diff --git a/linux/dev/include/linux/head.h b/linux/dev/include/linux/head.h
new file mode 100644
index 0000000..c501f21
--- /dev/null
+++ b/linux/dev/include/linux/head.h
@@ -0,0 +1,20 @@
+#ifndef _LINUX_HEAD_H
+#define _LINUX_HEAD_H
+
+typedef struct desc_struct {
+ unsigned long a,b;
+} desc_table[256];
+
+/* XXX Linux code shouldn't use idt/gdt directly */
+/* extern desc_table idt,gdt; */
+
+#define GDT_NUL 0
+#define GDT_CODE 1
+#define GDT_DATA 2
+#define GDT_TMP 3
+
+#define LDT_NUL 0
+#define LDT_CODE 1
+#define LDT_DATA 2
+
+#endif