| File: | obj-scan-build/../i386/i386/user_ldt.c |
| Location: | line 83, column 13 |
| Description: | Dereference of null pointer |
| 1 | /* | |||
| 2 | * Mach Operating System | |||
| 3 | * Copyright (c) 1994,1993,1992,1991 Carnegie Mellon University | |||
| 4 | * All Rights Reserved. | |||
| 5 | * | |||
| 6 | * Permission to use, copy, modify and distribute this software and its | |||
| 7 | * documentation is hereby granted, provided that both the copyright | |||
| 8 | * notice and this permission notice appear in all copies of the | |||
| 9 | * software, derivative works or modified versions, and any portions | |||
| 10 | * thereof, and that both notices appear in supporting documentation. | |||
| 11 | * | |||
| 12 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |||
| 13 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |||
| 14 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |||
| 15 | * | |||
| 16 | * Carnegie Mellon requests users of this software to return to | |||
| 17 | * | |||
| 18 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |||
| 19 | * School of Computer Science | |||
| 20 | * Carnegie Mellon University | |||
| 21 | * Pittsburgh PA 15213-3890 | |||
| 22 | * | |||
| 23 | * any improvements or extensions that they make and grant Carnegie Mellon | |||
| 24 | * the rights to redistribute these changes. | |||
| 25 | */ | |||
| 26 | /* | |||
| 27 | * User LDT management. | |||
| 28 | * Each thread in a task may have its own LDT. | |||
| 29 | */ | |||
| 30 | ||||
| 31 | #include <string.h> | |||
| 32 | ||||
| 33 | #include <kern/kalloc.h> | |||
| 34 | #include <kern/thread.h> | |||
| 35 | ||||
| 36 | #include <vm/vm_kern.h> | |||
| 37 | ||||
| 38 | #include <i3861/pcb.h> | |||
| 39 | #include <i3861/seg.h> | |||
| 40 | #include <i3861/thread.h> | |||
| 41 | #include <i3861/user_ldt.h> | |||
| 42 | #include <stddef.h> | |||
| 43 | #include "ldt.h" | |||
| 44 | #include "vm_param.h" | |||
| 45 | ||||
| 46 | char acc_type[8][3] = { | |||
| 47 | /* code stack data */ | |||
| 48 | { 0, 0, 1 }, /* data */ | |||
| 49 | { 0, 1, 1 }, /* data, writable */ | |||
| 50 | { 0, 0, 1 }, /* data, expand-down */ | |||
| 51 | { 0, 1, 1 }, /* data, writable, expand-down */ | |||
| 52 | { 1, 0, 0 }, /* code */ | |||
| 53 | { 1, 0, 1 }, /* code, readable */ | |||
| 54 | { 1, 0, 0 }, /* code, conforming */ | |||
| 55 | { 1, 0, 1 }, /* code, readable, conforming */ | |||
| 56 | }; | |||
| 57 | ||||
| 58 | boolean_t selector_check(thread, sel, type) | |||
| 59 | thread_t thread; | |||
| 60 | int sel; | |||
| 61 | int type; /* code, stack, data */ | |||
| 62 | { | |||
| 63 | struct user_ldt *ldt; | |||
| 64 | int access; | |||
| 65 | ||||
| 66 | ldt = thread->pcb->ims.ldt; | |||
| 67 | if (ldt == 0) { | |||
| ||||
| 68 | switch (type) { | |||
| 69 | case S_CODE0: | |||
| 70 | return sel == USER_CS0x17; | |||
| 71 | case S_STACK1: | |||
| 72 | return sel == USER_DS0x1f; | |||
| 73 | case S_DATA2: | |||
| 74 | return sel == 0 || | |||
| 75 | sel == USER_CS0x17 || | |||
| 76 | sel == USER_DS0x1f; | |||
| 77 | } | |||
| 78 | } | |||
| 79 | ||||
| 80 | if (type != S_DATA2 && sel == 0) | |||
| 81 | return FALSE((boolean_t) 0); | |||
| 82 | if ((sel & (SEL_LDT0x04|SEL_PL0x03)) != (SEL_LDT0x04|SEL_PL_U0x03) | |||
| 83 | || sel > ldt->desc.limit_low) | |||
| ||||
| 84 | return FALSE((boolean_t) 0); | |||
| 85 | ||||
| 86 | access = ldt->ldt[sel_idx(sel)((sel)>>3)].access; | |||
| 87 | ||||
| 88 | if ((access & (ACC_P0x80|ACC_PL0x60|ACC_TYPE_USER0x10|SZ_640x2)) | |||
| 89 | != (ACC_P0x80|ACC_PL_U0x60|ACC_TYPE_USER0x10)) | |||
| 90 | return FALSE((boolean_t) 0); | |||
| 91 | /* present, pl == pl.user, not system, not 64bits */ | |||
| 92 | ||||
| 93 | return acc_type[(access & 0xe)>>1][type]; | |||
| 94 | } | |||
| 95 | ||||
| 96 | /* | |||
| 97 | * Add the descriptors to the LDT, starting with | |||
| 98 | * the descriptor for 'first_selector'. | |||
| 99 | */ | |||
| 100 | kern_return_t | |||
| 101 | i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline) | |||
| 102 | thread_t thread; | |||
| 103 | int first_selector; | |||
| 104 | struct real_descriptor *desc_list; | |||
| 105 | unsigned int count; | |||
| 106 | boolean_t desc_list_inline; | |||
| 107 | { | |||
| 108 | user_ldt_t new_ldt, old_ldt, temp; | |||
| 109 | struct real_descriptor *dp; | |||
| 110 | int i; | |||
| 111 | int min_selector = 0; | |||
| 112 | pcb_t pcb; | |||
| 113 | vm_size_t ldt_size_needed; | |||
| 114 | int first_desc = sel_idx(first_selector)((first_selector)>>3); | |||
| 115 | vm_map_copy_t old_copy_object = NULL((void *) 0); /* Suppress gcc warning */ | |||
| 116 | ||||
| 117 | if (thread == THREAD_NULL((thread_t) 0)) | |||
| 118 | return KERN_INVALID_ARGUMENT4; | |||
| 119 | if (thread == current_thread()(active_threads[(0)])) | |||
| 120 | min_selector = LDTSZ4; | |||
| 121 | if (first_desc < min_selector || first_desc > 8191) | |||
| 122 | return KERN_INVALID_ARGUMENT4; | |||
| 123 | if (first_desc + count >= 8192) | |||
| 124 | return KERN_INVALID_ARGUMENT4; | |||
| 125 | ||||
| 126 | /* | |||
| 127 | * If desc_list is not inline, it is in copyin form. | |||
| 128 | * We must copy it out to the kernel map, and wire | |||
| 129 | * it down (we touch it while the PCB is locked). | |||
| 130 | * | |||
| 131 | * We make a copy of the copyin object, and clear | |||
| 132 | * out the old one, so that returning KERN_INVALID_ARGUMENT | |||
| 133 | * will not try to deallocate the data twice. | |||
| 134 | */ | |||
| 135 | if (!desc_list_inline) { | |||
| 136 | kern_return_t kr; | |||
| 137 | vm_offset_t dst_addr; | |||
| 138 | ||||
| 139 | old_copy_object = (vm_map_copy_t) desc_list; | |||
| 140 | ||||
| 141 | kr = vm_map_copyout(ipc_kernel_map, &dst_addr, | |||
| 142 | vm_map_copy_copy(old_copy_object)); | |||
| 143 | if (kr != KERN_SUCCESS0) | |||
| 144 | return kr; | |||
| 145 | ||||
| 146 | (void) vm_map_pageable(ipc_kernel_map,vm_map_pageable_common(ipc_kernel_map, dst_addr, dst_addr + count * sizeof(struct real_descriptor), ((vm_prot_t) 0x01)|((vm_prot_t ) 0x02), ((boolean_t) 0)) | |||
| 147 | dst_addr,vm_map_pageable_common(ipc_kernel_map, dst_addr, dst_addr + count * sizeof(struct real_descriptor), ((vm_prot_t) 0x01)|((vm_prot_t ) 0x02), ((boolean_t) 0)) | |||
| 148 | dst_addr + count * sizeof(struct real_descriptor),vm_map_pageable_common(ipc_kernel_map, dst_addr, dst_addr + count * sizeof(struct real_descriptor), ((vm_prot_t) 0x01)|((vm_prot_t ) 0x02), ((boolean_t) 0)) | |||
| 149 | VM_PROT_READ|VM_PROT_WRITE)vm_map_pageable_common(ipc_kernel_map, dst_addr, dst_addr + count * sizeof(struct real_descriptor), ((vm_prot_t) 0x01)|((vm_prot_t ) 0x02), ((boolean_t) 0)); | |||
| 150 | desc_list = (struct real_descriptor *)dst_addr; | |||
| 151 | } | |||
| 152 | ||||
| 153 | for (i = 0, dp = desc_list; | |||
| 154 | i < count; | |||
| 155 | i++, dp++) | |||
| 156 | { | |||
| 157 | switch (dp->access & ~ACC_A0x01) { | |||
| 158 | case 0: | |||
| 159 | case ACC_P0x80: | |||
| 160 | /* valid empty descriptor */ | |||
| 161 | break; | |||
| 162 | case ACC_P0x80 | ACC_CALL_GATE0x0c: | |||
| 163 | /* Mach kernel call */ | |||
| 164 | *dp = *(struct real_descriptor *) | |||
| 165 | &ldt[sel_idx(USER_SCALL)((0x07)>>3)]; | |||
| 166 | break; | |||
| 167 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_DATA0x10: | |||
| 168 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_DATA_W0x12: | |||
| 169 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_DATA_E0x14: | |||
| 170 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_DATA_EW0x16: | |||
| 171 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_CODE0x18: | |||
| 172 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_CODE_R0x1a: | |||
| 173 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_CODE_C0x1c: | |||
| 174 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_CODE_CR0x1e: | |||
| 175 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_CALL_GATE_160x04: | |||
| 176 | case ACC_P0x80 | ACC_PL_U0x60 | ACC_CALL_GATE0x0c: | |||
| 177 | break; | |||
| 178 | default: | |||
| 179 | return KERN_INVALID_ARGUMENT4; | |||
| 180 | } | |||
| 181 | } | |||
| 182 | ldt_size_needed = sizeof(struct real_descriptor) | |||
| 183 | * (first_desc + count); | |||
| 184 | ||||
| 185 | pcb = thread->pcb; | |||
| 186 | new_ldt = 0; | |||
| 187 | Retry: | |||
| 188 | simple_lock(&pcb->lock); | |||
| 189 | old_ldt = pcb->ims.ldt; | |||
| 190 | if (old_ldt == 0 || | |||
| 191 | old_ldt->desc.limit_low + 1 < ldt_size_needed) | |||
| 192 | { | |||
| 193 | /* | |||
| 194 | * No old LDT, or not big enough | |||
| 195 | */ | |||
| 196 | if (new_ldt == 0) { | |||
| 197 | simple_unlock(&pcb->lock); | |||
| 198 | ||||
| 199 | #ifdef MACH_PV_DESCRIPTORS | |||
| 200 | /* LDT needs to be aligned on a page */ | |||
| 201 | vm_offset_t alloc = kalloc(ldt_size_needed + PAGE_SIZE(1 << 12) + offsetof(struct user_ldt, ldt)__builtin_offsetof (struct user_ldt, ldt)); | |||
| 202 | new_ldt = (user_ldt_t) (round_page((alloc + offsetof(struct user_ldt, ldt)))((vm_offset_t)((((vm_offset_t)((alloc + __builtin_offsetof (struct user_ldt, ldt)))) + ((1 << 12)-1)) & ~((1 << 12)-1))) - offsetof(struct user_ldt, ldt)__builtin_offsetof (struct user_ldt, ldt)); | |||
| 203 | new_ldt->alloc = alloc; | |||
| 204 | ||||
| 205 | #else /* MACH_PV_DESCRIPTORS */ | |||
| 206 | new_ldt = (user_ldt_t) | |||
| 207 | kalloc(ldt_size_needed | |||
| 208 | + sizeof(struct real_descriptor)); | |||
| 209 | #endif /* MACH_PV_DESCRIPTORS */ | |||
| 210 | /* | |||
| 211 | * Build a descriptor that describes the | |||
| 212 | * LDT itself | |||
| 213 | */ | |||
| 214 | { | |||
| 215 | vm_offset_t ldt_base; | |||
| 216 | ||||
| 217 | ldt_base = kvtolin(&new_ldt->ldt[0])((vm_offset_t)(&new_ldt->ldt[0]) - 0xC0000000UL + ((0xc0000000UL ))); | |||
| 218 | ||||
| 219 | new_ldt->desc.limit_low = ldt_size_needed - 1; | |||
| 220 | new_ldt->desc.limit_high = 0; | |||
| 221 | new_ldt->desc.base_low = ldt_base & 0xffff; | |||
| 222 | new_ldt->desc.base_med = (ldt_base >> 16) & 0xff; | |||
| 223 | new_ldt->desc.base_high = ldt_base >> 24; | |||
| 224 | new_ldt->desc.access = ACC_P0x80 | ACC_LDT0x02; | |||
| 225 | new_ldt->desc.granularity = 0; | |||
| 226 | } | |||
| 227 | ||||
| 228 | goto Retry; | |||
| 229 | } | |||
| 230 | ||||
| 231 | /* | |||
| 232 | * Have new LDT. If there was a an old ldt, copy descriptors | |||
| 233 | * from old to new. Otherwise copy the default ldt. | |||
| 234 | */ | |||
| 235 | if (old_ldt) { | |||
| 236 | memcpy(&new_ldt->ldt[0], | |||
| 237 | &old_ldt->ldt[0], | |||
| 238 | old_ldt->desc.limit_low + 1); | |||
| 239 | } | |||
| 240 | else { | |||
| 241 | struct real_descriptor template = {0, 0, 0, ACC_P0x80, 0, 0 ,0}; | |||
| 242 | ||||
| 243 | for (dp = &new_ldt->ldt[0], i = 0; i < first_desc; i++, dp++) { | |||
| 244 | if (i < LDTSZ4) | |||
| 245 | *dp = *(struct real_descriptor *) &ldt[i]; | |||
| 246 | else | |||
| 247 | *dp = template; | |||
| 248 | } | |||
| 249 | } | |||
| 250 | ||||
| 251 | temp = old_ldt; | |||
| 252 | old_ldt = new_ldt; /* use new LDT from now on */ | |||
| 253 | new_ldt = temp; /* discard old LDT */ | |||
| 254 | ||||
| 255 | pcb->ims.ldt = old_ldt; /* set LDT for thread */ | |||
| 256 | ||||
| 257 | /* | |||
| 258 | * If we are modifying the LDT for the current thread, | |||
| 259 | * make sure it is properly set. | |||
| 260 | */ | |||
| 261 | if (thread == current_thread()(active_threads[(0)])) | |||
| 262 | switch_ktss(pcb); | |||
| 263 | } | |||
| 264 | ||||
| 265 | /* | |||
| 266 | * Install new descriptors. | |||
| 267 | */ | |||
| 268 | memcpy(&old_ldt->ldt[first_desc], | |||
| 269 | desc_list, | |||
| 270 | count * sizeof(struct real_descriptor)); | |||
| 271 | ||||
| 272 | simple_unlock(&pcb->lock); | |||
| 273 | ||||
| 274 | if (new_ldt) | |||
| 275 | #ifdef MACH_PV_DESCRIPTORS | |||
| 276 | { | |||
| 277 | int i; | |||
| 278 | #ifdef MACH_PV_PAGETABLES | |||
| 279 | for (i=0; i<(new_ldt->desc.limit_low + 1)/sizeof(struct real_descriptor); i+=PAGE_SIZE(1 << 12)/sizeof(struct real_descriptor)) | |||
| 280 | pmap_set_page_readwrite(&new_ldt->ldt[i]); | |||
| 281 | #endif /* MACH_PV_PAGETABLES*/ | |||
| 282 | kfree(new_ldt->alloc, new_ldt->desc.limit_low + 1 | |||
| 283 | + PAGE_SIZE(1 << 12) + offsetof(struct user_ldt, ldt)__builtin_offsetof (struct user_ldt, ldt)); | |||
| 284 | } | |||
| 285 | #else /* MACH_PV_DESCRIPTORS */ | |||
| 286 | kfree((vm_offset_t)new_ldt, | |||
| 287 | new_ldt->desc.limit_low + 1 | |||
| 288 | + sizeof(struct real_descriptor)); | |||
| 289 | #endif /* MACH_PV_DESCRIPTORS */ | |||
| 290 | ||||
| 291 | /* | |||
| 292 | * Free the descriptor list, if it was | |||
| 293 | * out-of-line. Also discard the original | |||
| 294 | * copy object for it. | |||
| 295 | */ | |||
| 296 | if (!desc_list_inline) { | |||
| 297 | (void) kmem_free(ipc_kernel_map, | |||
| 298 | (vm_offset_t) desc_list, | |||
| 299 | count * sizeof(struct real_descriptor)); | |||
| 300 | vm_map_copy_discard(old_copy_object); | |||
| 301 | } | |||
| 302 | ||||
| 303 | return KERN_SUCCESS0; | |||
| 304 | } | |||
| 305 | ||||
| 306 | kern_return_t | |||
| 307 | i386_get_ldt(thread, first_selector, selector_count, desc_list, count) | |||
| 308 | thread_t thread; | |||
| 309 | int first_selector; | |||
| 310 | int selector_count; /* number wanted */ | |||
| 311 | struct real_descriptor **desc_list; /* in/out */ | |||
| 312 | unsigned int *count; /* in/out */ | |||
| 313 | { | |||
| 314 | struct user_ldt *user_ldt; | |||
| 315 | pcb_t pcb = thread->pcb; | |||
| 316 | int first_desc = sel_idx(first_selector)((first_selector)>>3); | |||
| 317 | unsigned int ldt_count; | |||
| 318 | vm_size_t ldt_size; | |||
| 319 | vm_size_t size, size_needed; | |||
| 320 | vm_offset_t addr; | |||
| 321 | ||||
| 322 | if (thread == THREAD_NULL((thread_t) 0)) | |||
| 323 | return KERN_INVALID_ARGUMENT4; | |||
| 324 | if (first_desc < 0 || first_desc > 8191) | |||
| 325 | return KERN_INVALID_ARGUMENT4; | |||
| 326 | if (first_desc + selector_count >= 8192) | |||
| 327 | return KERN_INVALID_ARGUMENT4; | |||
| 328 | ||||
| 329 | addr = 0; | |||
| 330 | size = 0; | |||
| 331 | ||||
| 332 | for (;;) { | |||
| 333 | simple_lock(&pcb->lock); | |||
| 334 | user_ldt = pcb->ims.ldt; | |||
| 335 | if (user_ldt == 0) { | |||
| 336 | simple_unlock(&pcb->lock); | |||
| 337 | if (addr) | |||
| 338 | kmem_free(ipc_kernel_map, addr, size); | |||
| 339 | *count = 0; | |||
| 340 | return KERN_SUCCESS0; | |||
| 341 | } | |||
| 342 | ||||
| 343 | /* | |||
| 344 | * Find how many descriptors we should return. | |||
| 345 | */ | |||
| 346 | ldt_count = (user_ldt->desc.limit_low + 1) / | |||
| 347 | sizeof (struct real_descriptor); | |||
| 348 | ldt_count -= first_desc; | |||
| 349 | if (ldt_count > selector_count) | |||
| 350 | ldt_count = selector_count; | |||
| 351 | ||||
| 352 | ldt_size = ldt_count * sizeof(struct real_descriptor); | |||
| 353 | ||||
| 354 | /* | |||
| 355 | * Do we have the memory we need? | |||
| 356 | */ | |||
| 357 | if (ldt_count <= *count) | |||
| 358 | break; /* fits in-line */ | |||
| 359 | ||||
| 360 | size_needed = round_page(ldt_size)((vm_offset_t)((((vm_offset_t)(ldt_size)) + ((1 << 12)- 1)) & ~((1 << 12)-1))); | |||
| 361 | if (size_needed <= size) | |||
| 362 | break; | |||
| 363 | ||||
| 364 | /* | |||
| 365 | * Unlock the pcb and allocate more memory | |||
| 366 | */ | |||
| 367 | simple_unlock(&pcb->lock); | |||
| 368 | ||||
| 369 | if (size != 0) | |||
| 370 | kmem_free(ipc_kernel_map, addr, size); | |||
| 371 | ||||
| 372 | size = size_needed; | |||
| 373 | ||||
| 374 | if (kmem_alloc(ipc_kernel_map, &addr, size) | |||
| 375 | != KERN_SUCCESS0) | |||
| 376 | return KERN_RESOURCE_SHORTAGE6; | |||
| 377 | } | |||
| 378 | ||||
| 379 | /* | |||
| 380 | * copy out the descriptors | |||
| 381 | */ | |||
| 382 | memcpy(*desc_list, | |||
| 383 | &user_ldt->ldt[first_desc], | |||
| 384 | ldt_size); | |||
| 385 | *count = ldt_count; | |||
| 386 | simple_unlock(&pcb->lock); | |||
| 387 | ||||
| 388 | if (addr) { | |||
| 389 | vm_size_t size_used, size_left; | |||
| 390 | vm_map_copy_t memory; | |||
| 391 | ||||
| 392 | /* | |||
| 393 | * Free any unused memory beyond the end of the last page used | |||
| 394 | */ | |||
| 395 | size_used = round_page(ldt_size)((vm_offset_t)((((vm_offset_t)(ldt_size)) + ((1 << 12)- 1)) & ~((1 << 12)-1))); | |||
| 396 | if (size_used != size) | |||
| 397 | kmem_free(ipc_kernel_map, | |||
| 398 | addr + size_used, size - size_used); | |||
| 399 | ||||
| 400 | /* | |||
| 401 | * Zero the remainder of the page being returned. | |||
| 402 | */ | |||
| 403 | size_left = size_used - ldt_size; | |||
| 404 | if (size_left > 0) | |||
| 405 | memset((char *)addr + ldt_size, 0, size_left); | |||
| 406 | ||||
| 407 | /* | |||
| 408 | * Make memory into copyin form - this unwires it. | |||
| 409 | */ | |||
| 410 | (void) vm_map_copyin(ipc_kernel_map, addr, size_used, | |||
| 411 | TRUE((boolean_t) 1), &memory); | |||
| 412 | *desc_list = (struct real_descriptor *)memory; | |||
| 413 | } | |||
| 414 | ||||
| 415 | return KERN_SUCCESS0; | |||
| 416 | } | |||
| 417 | ||||
| 418 | void | |||
| 419 | user_ldt_free(user_ldt) | |||
| 420 | user_ldt_t user_ldt; | |||
| 421 | { | |||
| 422 | #ifdef MACH_PV_DESCRIPTORS | |||
| 423 | int i; | |||
| 424 | #ifdef MACH_PV_PAGETABLES | |||
| 425 | for (i=0; i<(user_ldt->desc.limit_low + 1)/sizeof(struct real_descriptor); i+=PAGE_SIZE(1 << 12)/sizeof(struct real_descriptor)) | |||
| 426 | pmap_set_page_readwrite(&user_ldt->ldt[i]); | |||
| 427 | #endif /* MACH_PV_PAGETABLES */ | |||
| 428 | kfree(user_ldt->alloc, user_ldt->desc.limit_low + 1 | |||
| 429 | + PAGE_SIZE(1 << 12) + offsetof(struct user_ldt, ldt)__builtin_offsetof (struct user_ldt, ldt)); | |||
| 430 | #else /* MACH_PV_DESCRIPTORS */ | |||
| 431 | kfree((vm_offset_t)user_ldt, | |||
| 432 | user_ldt->desc.limit_low + 1 | |||
| 433 | + sizeof(struct real_descriptor)); | |||
| 434 | #endif /* MACH_PV_DESCRIPTORS */ | |||
| 435 | } | |||
| 436 | ||||
| 437 | ||||
| 438 | kern_return_t | |||
| 439 | i386_set_gdt (thread_t thread, int *selector, struct real_descriptor desc) | |||
| 440 | { | |||
| 441 | int idx; | |||
| 442 | ||||
| 443 | if (thread == THREAD_NULL((thread_t) 0)) | |||
| 444 | return KERN_INVALID_ARGUMENT4; | |||
| 445 | ||||
| 446 | if (*selector == -1) | |||
| 447 | { | |||
| 448 | for (idx = 0; idx < USER_GDT_SLOTS2; ++idx) | |||
| 449 | if ((thread->pcb->ims.user_gdt[idx].access & ACC_P0x80) == 0) | |||
| 450 | { | |||
| 451 | *selector = ((idx + sel_idx(USER_GDT)((0x48)>>3)) << 3) | SEL_PL_U0x03; | |||
| 452 | break; | |||
| 453 | } | |||
| 454 | if (idx == USER_GDT_SLOTS2) | |||
| 455 | return KERN_NO_SPACE3; /* ? */ | |||
| 456 | } | |||
| 457 | else if ((*selector & (SEL_LDT0x04|SEL_PL0x03)) != SEL_PL_U0x03 | |||
| 458 | || sel_idx (*selector)((*selector)>>3) < sel_idx(USER_GDT)((0x48)>>3) | |||
| 459 | || sel_idx (*selector)((*selector)>>3) >= sel_idx(USER_GDT)((0x48)>>3) + USER_GDT_SLOTS2) | |||
| 460 | return KERN_INVALID_ARGUMENT4; | |||
| 461 | else | |||
| 462 | idx = sel_idx (*selector)((*selector)>>3) - sel_idx(USER_GDT)((0x48)>>3); | |||
| 463 | ||||
| 464 | if ((desc.access & ACC_P0x80) == 0) | |||
| 465 | memset (&thread->pcb->ims.user_gdt[idx], 0, | |||
| 466 | sizeof thread->pcb->ims.user_gdt[idx]); | |||
| 467 | else if ((desc.access & (ACC_TYPE_USER0x10|ACC_PL0x60)) != (ACC_TYPE_USER0x10|ACC_PL_U0x60) || (desc.granularity & SZ_640x2)) | |||
| 468 | ||||
| 469 | return KERN_INVALID_ARGUMENT4; | |||
| 470 | else | |||
| 471 | thread->pcb->ims.user_gdt[idx] = desc; | |||
| 472 | ||||
| 473 | /* | |||
| 474 | * If we are modifying the GDT for the current thread, | |||
| 475 | * make sure it is properly set. | |||
| 476 | */ | |||
| 477 | if (thread == current_thread()(active_threads[(0)])) | |||
| 478 | switch_ktss(thread->pcb); | |||
| 479 | ||||
| 480 | return KERN_SUCCESS0; | |||
| 481 | } | |||
| 482 | ||||
| 483 | kern_return_t | |||
| 484 | i386_get_gdt (thread_t thread, int selector, struct real_descriptor *desc) | |||
| 485 | { | |||
| 486 | if (thread == THREAD_NULL((thread_t) 0)) | |||
| 487 | return KERN_INVALID_ARGUMENT4; | |||
| 488 | ||||
| 489 | if ((selector & (SEL_LDT0x04|SEL_PL0x03)) != SEL_PL_U0x03 | |||
| 490 | || sel_idx (selector)((selector)>>3) < sel_idx(USER_GDT)((0x48)>>3) | |||
| 491 | || sel_idx (selector)((selector)>>3) >= sel_idx(USER_GDT)((0x48)>>3) + USER_GDT_SLOTS2) | |||
| 492 | return KERN_INVALID_ARGUMENT4; | |||
| 493 | ||||
| 494 | *desc = thread->pcb->ims.user_gdt[sel_idx (selector)((selector)>>3) - sel_idx(USER_GDT)((0x48)>>3)]; | |||
| 495 | ||||
| 496 | return KERN_SUCCESS0; | |||
| 497 | } |