diff options
author | Thomas Bushnell <thomas@gnu.org> | 1999-09-16 02:17:48 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1999-09-16 02:17:48 +0000 |
commit | 6c83d0237eb855aa6e74691070efe357e2bb3d56 (patch) | |
tree | 3c3c2ce82e84988ba781fc2027b76c7b95ffda87 /i386 | |
parent | f54d036fde537292b5f9c488a754e5476eb8a8fd (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.c | 82 |
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; } |