summaryrefslogtreecommitdiff
path: root/i386
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1999-09-16 02:17:48 +0000
committerThomas Bushnell <thomas@gnu.org>1999-09-16 02:17:48 +0000
commit6c83d0237eb855aa6e74691070efe357e2bb3d56 (patch)
tree3c3c2ce82e84988ba781fc2027b76c7b95ffda87 /i386
parentf54d036fde537292b5f9c488a754e5476eb8a8fd (diff)
1999-09-15 Mark Kettenis <kettenis@gnu.org>
* i386/i386/user_ldt.c: Fix user LDT management. (i386_set_ldt): Prevent thrashing the LDT for the current thread. Correctly calculate size of new LDT. Set base adress of the LDT descriptor to the linear address of the LDT instead of the kernel virtual address. Copy descriptors from the default LDT if there is no old LDT for the current thread. Call switch_ktss if we are setting a new LDT for the current thread. (i386_get_ldt): Fix bug in copying out the descriptors.
Diffstat (limited to 'i386')
-rw-r--r--i386/i386/user_ldt.c82
1 files changed, 47 insertions, 35 deletions
diff --git a/i386/i386/user_ldt.c b/i386/i386/user_ldt.c
index 71ca08d..5c5df64 100644
--- a/i386/i386/user_ldt.c
+++ b/i386/i386/user_ldt.c
@@ -37,6 +37,7 @@
#include <i386/thread.h>
#include <i386/user_ldt.h>
#include "ldt.h"
+#include "vm_param.h"
char acc_type[8][3] = {
/* code stack data */
@@ -100,9 +101,10 @@ i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline)
unsigned int count;
boolean_t desc_list_inline;
{
- user_ldt_t new_ldt, old_ldt, cur_ldt;
+ user_ldt_t new_ldt, old_ldt, temp;
struct real_descriptor *dp;
int i;
+ int min_selector = 0;
pcb_t pcb;
vm_size_t ldt_size_needed;
int first_desc = sel_idx(first_selector);
@@ -110,7 +112,9 @@ i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline)
if (thread == THREAD_NULL)
return KERN_INVALID_ARGUMENT;
- if (first_desc < 0 || first_desc > 8191)
+ if (thread == current_thread())
+ min_selector = LDTSZ;
+ if (first_desc < min_selector || first_desc > 8191)
return KERN_INVALID_ARGUMENT;
if (first_desc + count >= 8192)
return KERN_INVALID_ARGUMENT;
@@ -172,19 +176,18 @@ i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline)
}
}
ldt_size_needed = sizeof(struct real_descriptor)
- * (first_desc + count - 1);
+ * (first_desc + count);
pcb = thread->pcb;
- old_ldt = 0; /* the one to throw away */
- new_ldt = 0; /* the one to allocate */
+ new_ldt = 0;
Retry:
simple_lock(&pcb->lock);
- cur_ldt = pcb->ims.ldt;
- if (cur_ldt == 0 ||
- cur_ldt->desc.limit_low + 1 < ldt_size_needed)
+ old_ldt = pcb->ims.ldt;
+ if (old_ldt == 0 ||
+ old_ldt->desc.limit_low + 1 < ldt_size_needed)
{
/*
- * No current LDT, or not big enough
+ * No old LDT, or not big enough
*/
if (new_ldt == 0) {
simple_unlock(&pcb->lock);
@@ -199,7 +202,7 @@ i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline)
{
vm_offset_t ldt_base;
- ldt_base = (vm_offset_t) &new_ldt->ldt[0];
+ ldt_base = kvtolin(&new_ldt->ldt[0]);
new_ldt->desc.limit_low = ldt_size_needed - 1;
new_ldt->desc.limit_high = 0;
@@ -214,40 +217,48 @@ i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline)
}
/*
- * Have new LDT. Copy descriptors from current to new.
+ * Have new LDT. If there was a an old ldt, copy descriptors
+ * from old to new. Otherwise copy the default ldt.
*/
- if (cur_ldt)
- bcopy((char *) &cur_ldt->ldt[0],
- (char *) &new_ldt->ldt[0],
- cur_ldt->desc.limit_low + 1);
-
- old_ldt = cur_ldt; /* discard old LDT */
- cur_ldt = new_ldt; /* use new LDT from now on */
- new_ldt = 0; /* keep new LDT */
+ if (old_ldt) {
+ bcopy((char *)&old_ldt->ldt[0],
+ (char *)&new_ldt->ldt[0],
+ old_ldt->desc.limit_low + 1);
+ }
+ else if (thread == current_thread()) {
+ struct real_descriptor template = {0, 0, 0, ACC_P, 0, 0 ,0};
+
+ for (dp = &new_ldt->ldt[0], i = 0; i < first_desc; i++, dp++) {
+ if (i < LDTSZ)
+ *dp = *(struct real_descriptor *) &ldt[i];
+ else
+ *dp = template;
+ }
+ }
+
+ temp = old_ldt;
+ old_ldt = new_ldt; /* use new LDT from now on */
+ new_ldt = temp; /* discard old LDT */
- pcb->ims.ldt = cur_ldt; /* set LDT for thread */
+ pcb->ims.ldt = old_ldt; /* set LDT for thread */
+
+ /*
+ * If we are modifying the LDT for the current thread,
+ * make sure it is properly set.
+ */
+ if (thread == current_thread())
+ switch_ktss(pcb);
}
/*
* Install new descriptors.
*/
- bcopy((char *) desc_list,
- (char *) &cur_ldt->ldt[first_desc],
+ bcopy((char *)desc_list,
+ (char *)&old_ldt->ldt[first_desc],
count * sizeof(struct real_descriptor));
simple_unlock(&pcb->lock);
- /*
- * Discard old LDT if it was replaced
- */
- if (old_ldt)
- kfree((vm_offset_t)old_ldt,
- old_ldt->desc.limit_low + 1
- + sizeof(struct real_descriptor));
-
- /*
- * Discard new LDT if it was not used
- */
if (new_ldt)
kfree((vm_offset_t)new_ldt,
new_ldt->desc.limit_low + 1
@@ -344,7 +355,7 @@ i386_get_ldt(thread, first_selector, selector_count, desc_list, count)
/*
* copy out the descriptors
*/
- bcopy((char *)&user_ldt[first_desc],
+ bcopy((char *)&user_ldt->ldt[first_desc],
(char *)*desc_list,
ldt_size);
*count = ldt_count;
@@ -372,7 +383,8 @@ i386_get_ldt(thread, first_selector, selector_count, desc_list, count)
/*
* Make memory into copyin form - this unwires it.
*/
- (void) vm_map_copyin(ipc_kernel_map, addr, size_used, TRUE, &memory);
+ (void) vm_map_copyin(ipc_kernel_map, addr, size_used,
+ TRUE, &memory);
*desc_list = (struct real_descriptor *)memory;
}