|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1992 NeXT Computer, Inc. ! 27: * ! 28: * Intel386 Family: Machine dependent thread module. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 6 April 1992 ? at NeXT ! 33: * Created. ! 34: */ ! 35: ! 36: #import <mach/mach_types.h> ! 37: ! 38: #import <kern/mach_param.h> ! 39: ! 40: #import <architecture/i386/table.h> ! 41: ! 42: #import <machdep/i386/fp_exported.h> ! 43: #import <machdep/i386/configure.h> ! 44: ! 45: #import <machdep/i386/ldt.h> ! 46: #import <machdep/i386/table_inline.h> ! 47: #import <machdep/i386/desc_inline.h> ! 48: #import <machdep/i386/sel_inline.h> ! 49: #import <machdep/i386/cpu_inline.h> ! 50: ! 51: /* U**X crap!! */ ! 52: #import <sys/param.h> ! 53: #import <sys/proc.h> ! 54: ! 55: #import <fp_emul.h> ! 56: #import <pc_support.h> ! 57: ! 58: zone_t pcb_zone; ! 59: ! 60: vm_offset_t stack_pointers[NCPUS]; ! 61: boolean_t empty_stacks[NCPUS]; ! 62: ! 63: /* ! 64: * The base of the kernel stack ! 65: * is different when a thread is ! 66: * in v86 mode. ! 67: */ ! 68: #define KERNEL_STACK_BASE(state) \ ! 69: ((unsigned int) &(state)->frame.v_es) ! 70: ! 71: #define KERNEL_V86_STACK_BASE(state) \ ! 72: ((unsigned int) &(&(state)->frame)[1]) ! 73: ! 74: void ! 75: stack_attach( ! 76: thread_t thread, ! 77: vm_offset_t stack, ! 78: void (*continuation)(void) ! 79: ) ! 80: { ! 81: tss_t *tss; ! 82: extern void _stack_attach(void); ! 83: ! 84: thread->kernel_stack = stack; ! 85: ! 86: tss = thread->pcb->tss; ! 87: tss->esp = tss->ebp = stack + KERNEL_STACK_SIZE; ! 88: tss->eip = (unsigned int)_stack_attach; ! 89: tss->ebx = (unsigned int)continuation; ! 90: } ! 91: ! 92: ! 93: vm_offset_t ! 94: stack_detach( ! 95: thread_t thread ! 96: ) ! 97: { ! 98: vm_offset_t stack; ! 99: ! 100: stack = thread->kernel_stack; ! 101: thread->kernel_stack = 0; ! 102: ! 103: return (stack); ! 104: } ! 105: ! 106: void ! 107: stack_handoff( ! 108: thread_t old, ! 109: thread_t new ! 110: ) ! 111: { ! 112: struct pcb *new_pcb = new->pcb, ! 113: *old_pcb = old->pcb; ! 114: vm_offset_t stack = stack_detach(old); ! 115: ! 116: stack_attach(new, stack, 0); ! 117: ! 118: /* ! 119: * Change software state. ! 120: */ ! 121: if (new->task != old->task) { ! 122: int mycpu = cpu_number(); ! 123: ! 124: PMAP_DEACTIVATE(vm_map_pmap(old->task->map), old, mycpu); ! 125: PMAP_ACTIVATE(vm_map_pmap(new->task->map), new, mycpu); ! 126: } ! 127: ! 128: current_thread() = new; ! 129: ! 130: /* ! 131: * Change hardware state. ! 132: */ ! 133: if (new_pcb->tss->cr3 != old_pcb->tss->cr3) ! 134: set_cr3(new_pcb->tss->cr3); ! 135: ! 136: if (new_pcb->ldt != old_pcb->ldt ! 137: || new_pcb->ldt_size != old_pcb->ldt_size) { ! 138: map_ldt(sel_to_gdt_entry(LDT_SEL), ! 139: (vm_offset_t) new_pcb->ldt, ! 140: (vm_size_t) new_pcb->ldt_size); ! 141: lldt(); ! 142: } ! 143: ! 144: map_tss(sel_to_gdt_entry(TSS_SEL), ! 145: (vm_offset_t) new_pcb->tss ! 146: + KERNEL_LINEAR_BASE, ! 147: (vm_size_t) new_pcb->tss_size); ! 148: ltr(); setts(); ! 149: } ! 150: ! 151: extern ! 152: thread_t ! 153: _switch_tss( ! 154: tss_t *old_tss, ! 155: tss_t *new_tss, ! 156: thread_t old ! 157: ); ! 158: ! 159: thread_t ! 160: switch_context( ! 161: thread_t old, ! 162: void (*continuation)(void), ! 163: thread_t new ! 164: ) ! 165: { ! 166: struct pcb *new_pcb = new->pcb, ! 167: *old_pcb = old->pcb; ! 168: ! 169: /* ! 170: * Change software state. ! 171: */ ! 172: if (new->task != old->task) { ! 173: int mycpu = cpu_number(); ! 174: ! 175: PMAP_DEACTIVATE(vm_map_pmap(old->task->map), old, mycpu); ! 176: PMAP_ACTIVATE(vm_map_pmap(new->task->map), new, mycpu); ! 177: } ! 178: ! 179: current_thread() = new; ! 180: current_stack() = new->kernel_stack; ! 181: current_stack_pointer() = new->kernel_stack + KERNEL_STACK_SIZE; ! 182: ! 183: /* ! 184: * Change hardware state. ! 185: */ ! 186: if (new_pcb->tss->cr3 != old_pcb->tss->cr3) ! 187: set_cr3(new_pcb->tss->cr3); ! 188: ! 189: if (new_pcb->ldt != old_pcb->ldt ! 190: || new_pcb->ldt_size != old_pcb->ldt_size) { ! 191: map_ldt(sel_to_gdt_entry(LDT_SEL), ! 192: (vm_offset_t) new_pcb->ldt, ! 193: (vm_size_t) new_pcb->ldt_size); ! 194: lldt(); ! 195: } ! 196: ! 197: map_tss(sel_to_gdt_entry(TSS_SEL), ! 198: (vm_offset_t) new_pcb->tss ! 199: + KERNEL_LINEAR_BASE, ! 200: (vm_size_t) new_pcb->tss_size); ! 201: ltr(); setts(); ! 202: ! 203: if (old->swap_func = continuation) ! 204: return _switch_tss(0, new_pcb->tss, old); ! 205: else ! 206: return _switch_tss(old_pcb->tss, new_pcb->tss, old); ! 207: } ! 208: ! 209: void ! 210: call_continuation( ! 211: void (*continuation)(void) ! 212: ) ! 213: { ! 214: _call_with_stack(continuation, current_stack_pointer()); ! 215: /* NOTREACHED */ ! 216: } ! 217: ! 218: void ! 219: pcb_module_init(void) ! 220: { ! 221: pcb_zone = zinit( ! 222: sizeof (struct pcb), ! 223: THREAD_MAX * sizeof (struct pcb), ! 224: THREAD_CHUNK * sizeof (struct pcb), ! 225: FALSE, "pcb"); ! 226: } ! 227: ! 228: /* ! 229: * Initialize a pcb for a ! 230: * new thread. ! 231: */ ! 232: void pcb_init( ! 233: thread_t thread ! 234: ) ! 235: { ! 236: struct pcb *pcb; ! 237: tss_t *tss; ! 238: ! 239: /* ! 240: * Allocate a new pcb. ! 241: */ ! 242: thread->pcb = pcb = (void *)zalloc(pcb_zone); ! 243: *pcb = (struct pcb) { 0 }; ! 244: ! 245: /* ! 246: * Setup with internal TSS. ! 247: */ ! 248: pcb->tss = tss = &pcb->tss_store.internal; ! 249: pcb->tss_size = TSS_SIZE(0); ! 250: ! 251: /* ! 252: * Context from pmap. ! 253: */ ! 254: tss->cr3 = vm_map_pmap(thread->task->map)->cr3; ! 255: ! 256: /* ! 257: * Setup with default LDT. ! 258: */ ! 259: pcb->ldt = (vm_offset_t)ldt + KERNEL_LINEAR_BASE; ! 260: pcb->ldt_size = LDTSZ * sizeof (ldt_entry_t); ! 261: ! 262: tss->ldt = LDT_SEL; ! 263: ! 264: /* ! 265: * Kernel state. ! 266: */ ! 267: tss->ss0 = KDS_SEL; ! 268: tss->eflags = EFL_IF; ! 269: tss->ss = KDS_SEL; ! 270: tss->cs = KCS_SEL; ! 271: tss->ds = KDS_SEL; ! 272: tss->es = KDS_SEL; ! 273: tss->fs = LDATA_SEL; ! 274: tss->gs = NULL_SEL; ! 275: tss->io_bmap = TSS_SIZE(0); ! 276: } ! 277: ! 278: void ! 279: pcb_common_init( ! 280: task_t task ! 281: ) ! 282: { ! 283: pcb_common_t *common = (void *)kalloc(sizeof (*common)); ! 284: ! 285: lock_init(&common->lock, TRUE); ! 286: common->ldt = (vm_offset_t)ldt + KERNEL_LINEAR_BASE; ! 287: common->ldt_size = LDTSZ * sizeof (ldt_entry_t); ! 288: common->io_bmap.length = common->io_bmap.base = 0; ! 289: task->pcb_common = common; ! 290: } ! 291: ! 292: /* ! 293: * Set the thread's io space to the region ! 294: * defined by base and length. The TSS is ! 295: * expanded if necessary. Thread must either ! 296: * be the current thread, or suspended. ! 297: * N.B. On exit, the thread is guaranteed to ! 298: * have an external TSS. ! 299: */ ! 300: static void ! 301: thread_set_io_bmap( ! 302: thread_t thread, ! 303: vm_offset_t base, ! 304: vm_size_t length ! 305: ) ! 306: { ! 307: struct pcb *pcb = thread->pcb; ! 308: ! 309: if (pcb->tss_size < TSS_SIZE(length + 1)) { ! 310: struct tss_alloc new_tss_alloc, old_tss_alloc; ! 311: tss_t *new_tss, *old_tss; ! 312: ! 313: /* ! 314: * TSS needs to be enlarged. ! 315: */ ! 316: new_tss_alloc.length = TSS_SIZE(length + 1); ! 317: new_tss_alloc.base = (vm_offset_t)kalloc(new_tss_alloc.length); ! 318: ! 319: new_tss = (tss_t *)new_tss_alloc.base; ! 320: old_tss = pcb->tss; ! 321: ! 322: /* ! 323: * Copy old TSS to new one. ! 324: */ ! 325: *new_tss = *old_tss; ! 326: ! 327: if (pcb->extern_tss) { ! 328: /* ! 329: * Deal with old external tss. ! 330: */ ! 331: old_tss_alloc = pcb->tss_store.external; ! 332: ! 333: /* ! 334: * Switch to new TSS. ! 335: */ ! 336: pcb->tss_store.external = new_tss_alloc; ! 337: pcb->tss = new_tss; ! 338: pcb->tss_size = new_tss_alloc.length; ! 339: pcb->extern_tss = TRUE; ! 340: ! 341: /* ! 342: * Free old TSS. ! 343: */ ! 344: kfree((void *)old_tss_alloc.base, old_tss_alloc.length); ! 345: } ! 346: else { ! 347: /* ! 348: * Switch to new TSS. ! 349: */ ! 350: pcb->tss_store.external = new_tss_alloc; ! 351: pcb->tss = new_tss; ! 352: pcb->tss_size = new_tss_alloc.length; ! 353: pcb->extern_tss = TRUE; ! 354: } ! 355: ! 356: /* ! 357: * If changing the current ! 358: * thread, remap its tss now. ! 359: */ ! 360: if (thread == current_thread()) { ! 361: map_tss(sel_to_gdt_entry(TSS_SEL), ! 362: (vm_offset_t) thread->pcb->tss ! 363: + KERNEL_LINEAR_BASE, ! 364: (vm_size_t) thread->pcb->tss_size); ! 365: ltr(); ! 366: } ! 367: } ! 368: ! 369: memcpy( ! 370: (void *)pcb->tss + pcb->tss->io_bmap, ! 371: (void *)base, length); ! 372: } ! 373: ! 374: static void ! 375: task_update_io_bmap( ! 376: task_t task ! 377: ) ! 378: { ! 379: queue_head_t *list; ! 380: thread_t thread, prev_thread; ! 381: pcb_common_t *common = task->pcb_common; ! 382: ! 383: list = &task->thread_list; ! 384: prev_thread = THREAD_NULL; ! 385: task_lock(task); ! 386: thread = (thread_t)queue_first(list); ! 387: while (!queue_end(list, (queue_entry_t)thread)) { ! 388: thread_reference(thread); ! 389: task_unlock(task); ! 390: if (prev_thread != THREAD_NULL) ! 391: thread_deallocate(prev_thread); ! 392: thread_set_io_bmap(thread, ! 393: common->io_bmap.base, ! 394: common->io_bmap.length); ! 395: prev_thread = thread; ! 396: task_lock(task); ! 397: thread = (thread_t)queue_next(&thread->thread_list); ! 398: } ! 399: task_unlock(task); ! 400: if (prev_thread != THREAD_NULL) ! 401: thread_deallocate(prev_thread); ! 402: } ! 403: ! 404: kern_return_t ! 405: task_map_io_ports( ! 406: task_t task, ! 407: unsigned int port, ! 408: unsigned int length, ! 409: boolean_t unmap ! 410: ) ! 411: { ! 412: pcb_common_t *common = task->pcb_common; ! 413: vm_offset_t new_io_bmap_base; ! 414: vm_size_t new_io_bmap_length; ! 415: int i; ! 416: ! 417: /* ! 418: * Bad port range. ! 419: */ ! 420: if ((port + length) > 65536) ! 421: return (KERN_INVALID_ADDRESS); ! 422: ! 423: if (task->kernel_vm_space) ! 424: return (KERN_SUCCESS); ! 425: ! 426: /* ! 427: * If task is being terminated, ! 428: * don't bother. ! 429: */ ! 430: if (task_hold(task) != KERN_SUCCESS) ! 431: return (KERN_INVALID_ARGUMENT); ! 432: ! 433: new_io_bmap_length = roundup(port + length, NBBY) / NBBY; ! 434: ! 435: lock_write(&common->lock); ! 436: ! 437: if (common->io_bmap.length < new_io_bmap_length) { ! 438: new_io_bmap_base = (vm_offset_t)kalloc(new_io_bmap_length); ! 439: ! 440: /* ! 441: * Invalidate all of new IO bitmap. ! 442: */ ! 443: memset( ! 444: (void *)new_io_bmap_base, ! 445: 0xff, new_io_bmap_length); ! 446: ! 447: /* ! 448: * Copy old IO bitmap. ! 449: */ ! 450: memcpy( ! 451: (void *)new_io_bmap_base, ! 452: (void *)common->io_bmap.base, common->io_bmap.length); ! 453: ! 454: kfree((void *)common->io_bmap.base, common->io_bmap.length); ! 455: ! 456: common->io_bmap.base = new_io_bmap_base; ! 457: common->io_bmap.length = new_io_bmap_length; ! 458: } ! 459: ! 460: for (i = port; i < (port + length); i++) ! 461: if (unmap) ! 462: setbit(common->io_bmap.base, i); ! 463: else ! 464: clrbit(common->io_bmap.base, i); ! 465: ! 466: (void) task_dowait(task, TRUE); ! 467: ! 468: task_update_io_bmap(task); ! 469: ! 470: (void) task_release(task); ! 471: ! 472: lock_done(&common->lock); ! 473: ! 474: return (KERN_SUCCESS); ! 475: } ! 476: ! 477: static void ! 478: thread_set_ldt( ! 479: thread_t thread, ! 480: vm_offset_t address, ! 481: vm_size_t size ! 482: ) ! 483: { ! 484: thread->pcb->ldt = address; ! 485: thread->pcb->ldt_size = size; ! 486: ! 487: /* ! 488: * If changing the current ! 489: * thread, remap its LDT now. ! 490: */ ! 491: if (thread == current_thread()) { ! 492: map_ldt(sel_to_gdt_entry(LDT_SEL), ! 493: (vm_offset_t) thread->pcb->ldt, ! 494: (vm_size_t) thread->pcb->ldt_size); ! 495: lldt(); ! 496: } ! 497: } ! 498: ! 499: static void ! 500: task_update_ldt( ! 501: task_t task ! 502: ) ! 503: { ! 504: queue_head_t *list; ! 505: thread_t thread, prev_thread; ! 506: pcb_common_t *common = task->pcb_common; ! 507: ! 508: list = &task->thread_list; ! 509: prev_thread = THREAD_NULL; ! 510: task_lock(task); ! 511: thread = (thread_t)queue_first(list); ! 512: while (!queue_end(list, (queue_entry_t)thread)) { ! 513: thread_reference(thread); ! 514: task_unlock(task); ! 515: if (prev_thread != THREAD_NULL) ! 516: thread_deallocate(prev_thread); ! 517: thread_set_ldt(thread, common->ldt, common->ldt_size); ! 518: prev_thread = thread; ! 519: task_lock(task); ! 520: thread = (thread_t)queue_next(&thread->thread_list); ! 521: } ! 522: task_unlock(task); ! 523: if (prev_thread != THREAD_NULL) ! 524: thread_deallocate(prev_thread); ! 525: } ! 526: ! 527: kern_return_t ! 528: task_locate_ldt( ! 529: task_t task, ! 530: vm_offset_t address, ! 531: vm_size_t size ! 532: ) ! 533: { ! 534: pcb_common_t *common = task->pcb_common; ! 535: ! 536: if (vm_map_min(task->map) > address || ! 537: vm_map_max(task->map) <= (address + size)) ! 538: return (KERN_INVALID_ADDRESS); ! 539: ! 540: /* ! 541: * If task is being terminated, ! 542: * don't bother. ! 543: */ ! 544: if (task_hold(task) != KERN_SUCCESS) ! 545: return (KERN_INVALID_ARGUMENT); ! 546: ! 547: lock_write(&common->lock); ! 548: ! 549: common->ldt = address; ! 550: common->ldt_size = size; ! 551: ! 552: (void) task_dowait(task, TRUE); ! 553: ! 554: task_update_ldt(task); ! 555: ! 556: (void) task_release(task); ! 557: ! 558: lock_done(&common->lock); ! 559: ! 560: return (KERN_SUCCESS); ! 561: } ! 562: ! 563: kern_return_t ! 564: task_default_ldt( ! 565: task_t task ! 566: ) ! 567: { ! 568: pcb_common_t *common = task->pcb_common; ! 569: ! 570: /* ! 571: * If task is being terminated, ! 572: * don't bother. ! 573: */ ! 574: if (task_hold(task) != KERN_SUCCESS) ! 575: return (KERN_INVALID_ARGUMENT); ! 576: ! 577: lock_write(&common->lock); ! 578: ! 579: common->ldt = (vm_offset_t)ldt + KERNEL_LINEAR_BASE; ! 580: common->ldt_size = LDTSZ * sizeof (ldt_entry_t); ! 581: ! 582: (void) task_dowait(task, TRUE); ! 583: ! 584: task_update_ldt(task); ! 585: ! 586: (void) task_release(task); ! 587: ! 588: lock_done(&common->lock); ! 589: ! 590: return (KERN_SUCCESS); ! 591: } ! 592: ! 593: thread_saved_state_t * ! 594: thread_user_state( ! 595: thread_t thread ! 596: ) ! 597: { ! 598: thread_save_area_t *save_area = thread->pcb->save_area; ! 599: ! 600: if (save_area == 0) { ! 601: thread_saved_state_t *saved_state; ! 602: ! 603: thread->pcb->save_area = ! 604: save_area = (void *)kalloc(sizeof (*save_area)); ! 605: ! 606: saved_state = &save_area->sa_u; ! 607: *saved_state = (thread_saved_state_t) { 0 }; ! 608: saved_state->frame.eflags = EFL_IF; ! 609: saved_state->frame.cs = UCODE_SEL; ! 610: saved_state->frame.ss = UDATA_SEL; ! 611: saved_state->regs.ds = UDATA_SEL; ! 612: saved_state->regs.es = UDATA_SEL; ! 613: saved_state->regs.fs = NULL_SEL; ! 614: saved_state->regs.gs = NULL_SEL; ! 615: ! 616: return (saved_state); ! 617: } ! 618: else ! 619: return (&save_area->sa_u); ! 620: } ! 621: ! 622: /* ! 623: * Entry point for new user ! 624: * threads. ! 625: */ ! 626: void ! 627: thread_bootstrap_return(void) ! 628: { ! 629: thread_t thread = current_thread(); ! 630: pcb_common_t *common = thread->task->pcb_common; ! 631: struct pcb *pcb = thread->pcb; ! 632: ! 633: lock_read(&common->lock); ! 634: ! 635: if (common->io_bmap.length > 0) ! 636: thread_set_io_bmap(thread, ! 637: common->io_bmap.base, ! 638: common->io_bmap.length); ! 639: ! 640: if (common->ldt != pcb->ldt) ! 641: thread_set_ldt(thread, common->ldt, common->ldt_size); ! 642: ! 643: lock_done(&common->lock); ! 644: ! 645: thread_exception_return(); ! 646: /* NOTREACHED */ ! 647: } ! 648: ! 649: void ! 650: thread_exception_return(void) ! 651: { ! 652: thread_t thread = current_thread(); ! 653: thread_saved_state_t *saved_state = USER_REGS(thread); ! 654: ! 655: check_for_ast(saved_state); // *may* not return ! 656: ! 657: thread->pcb->tss->esp0 = ! 658: ((saved_state->frame.eflags & EFL_VM) ? ! 659: KERNEL_V86_STACK_BASE(saved_state) : ! 660: KERNEL_STACK_BASE(saved_state)); ! 661: ! 662: _return_with_state(saved_state); ! 663: /* NOTREACHED */ ! 664: } ! 665: ! 666: void __volatile__ ! 667: thread_syscall_return( ! 668: kern_return_t result ! 669: ) ! 670: { ! 671: thread_t thread = current_thread(); ! 672: thread_saved_state_t *saved_state = USER_REGS(thread); ! 673: ! 674: saved_state->regs.eax = result; ! 675: ! 676: check_for_ast(saved_state); // *may* not return ! 677: ! 678: thread->pcb->tss->esp0 = ! 679: ((saved_state->frame.eflags & EFL_VM) ? ! 680: KERNEL_V86_STACK_BASE(saved_state) : ! 681: KERNEL_STACK_BASE(saved_state)); ! 682: ! 683: _return_with_state(saved_state); ! 684: /* NOTREACHED */ ! 685: } ! 686: ! 687: void ! 688: thread_set_syscall_return( ! 689: thread_t thread, ! 690: kern_return_t result ! 691: ) ! 692: { ! 693: thread_saved_state_t *saved_state = USER_REGS(thread); ! 694: ! 695: saved_state->regs.eax = result; ! 696: } ! 697: ! 698: /* ! 699: * Called from locore to ! 700: * startup the first thread. (never returns) ! 701: */ ! 702: void ! 703: start_initial_context( ! 704: thread_t thread ! 705: ) ! 706: { ! 707: struct pcb *pcb = thread->pcb; ! 708: ! 709: /* ! 710: * Initialize the common, ! 711: * static LDT. ! 712: */ ! 713: ldt_init(); ! 714: ! 715: /* ! 716: * Change software state. ! 717: */ ! 718: PMAP_ACTIVATE(vm_map_pmap(thread->task->map), thread, 0); ! 719: ! 720: current_thread() = thread; ! 721: current_stack() = thread->kernel_stack; ! 722: current_stack_pointer() = thread->kernel_stack + KERNEL_STACK_SIZE; ! 723: ! 724: /* ! 725: * Change hardware state. ! 726: */ ! 727: set_cr3(pcb->tss->cr3); ! 728: ! 729: map_ldt(sel_to_gdt_entry(LDT_SEL), ! 730: (vm_offset_t) pcb->ldt, ! 731: (vm_size_t) pcb->ldt_size); ! 732: lldt(); ! 733: ! 734: map_tss(sel_to_gdt_entry(TSS_SEL), ! 735: (vm_offset_t) pcb->tss ! 736: + KERNEL_LINEAR_BASE, ! 737: (vm_size_t) pcb->tss_size); ! 738: ltr(); setts(); ! 739: ! 740: _switch_tss(0, pcb->tss, 0); ! 741: } ! 742: ! 743: /* ! 744: * Set externally visible thread ! 745: * state. ! 746: */ ! 747: kern_return_t ! 748: thread_setstatus( ! 749: thread_t thread, ! 750: int flavor, ! 751: thread_state_t tstate, ! 752: unsigned int count ! 753: ) ! 754: { ! 755: switch (flavor) { ! 756: ! 757: case i386_THREAD_STATE: ! 758: return (set_thread_state(thread, tstate, count)); ! 759: ! 760: case i386_THREAD_FPSTATE: ! 761: return (set_thread_fpstate(thread, tstate, count)); ! 762: ! 763: default: ! 764: return (KERN_INVALID_ARGUMENT); ! 765: } ! 766: } ! 767: ! 768: static void set_thread_v86_state( ! 769: thread_t thread, ! 770: i386_thread_state_t *state); ! 771: ! 772: kern_return_t ! 773: set_thread_state( ! 774: thread_t thread, ! 775: thread_state_t tstate, ! 776: unsigned int count ! 777: ) ! 778: { ! 779: thread_saved_state_t *saved_state; ! 780: i386_thread_state_t *state; ! 781: ! 782: if (count < i386_THREAD_STATE_COUNT) ! 783: return (KERN_INVALID_ARGUMENT); ! 784: ! 785: state = (i386_thread_state_t *)tstate; ! 786: ! 787: if ((state->eflags & EFL_VM) != 0) ! 788: set_thread_v86_state(thread, state); ! 789: else { ! 790: if (!thread->task->kernel_privilege) { ! 791: /* ! 792: * Validate segment selector values. ! 793: */ ! 794: if ( ! 795: !valid_user_code_selector(state->cs) || ! 796: !valid_user_data_selector(state->ds) || ! 797: !valid_user_data_selector(state->es) || ! 798: !valid_user_data_selector(state->fs) || ! 799: !valid_user_data_selector(state->gs) || ! 800: !valid_user_stack_selector(state->ss) ! 801: ) ! 802: return (KERN_INVALID_ARGUMENT); ! 803: } ! 804: else { ! 805: tss_t *tss = thread->pcb->tss; ! 806: /* ! 807: * State for kernel threads ! 808: * can only be set before thread ! 809: * is first started. ! 810: * ! 811: * XXX This hack is due to the ! 812: * fact that the &^%$#@! kernel loader ! 813: * uses the thread_set_state() call to ! 814: * start a thread in kernel mode. ! 815: */ ! 816: if (thread->swap_func != thread_bootstrap_return) ! 817: return (KERN_INVALID_ARGUMENT); ! 818: ! 819: tss->eax = state->eax; ! 820: tss->ebx = state->ebx; ! 821: tss->ecx = state->ecx; ! 822: tss->edx = state->edx; ! 823: tss->edi = state->edi; ! 824: tss->esi = state->esi; ! 825: ! 826: thread_start(thread, state->eip); ! 827: ! 828: return (KERN_SUCCESS); ! 829: } ! 830: ! 831: saved_state = USER_REGS(thread); ! 832: ! 833: saved_state->regs.eax = state->eax; ! 834: saved_state->regs.ebx = state->ebx; ! 835: saved_state->regs.ecx = state->ecx; ! 836: saved_state->regs.edx = state->edx; ! 837: saved_state->regs.edi = state->edi; ! 838: saved_state->regs.esi = state->esi; ! 839: saved_state->regs.ebp = state->ebp; ! 840: saved_state->frame.esp = state->esp; ! 841: saved_state->frame.ss = selector_to_sel(state->ss); ! 842: saved_state->frame.eflags = state->eflags; ! 843: saved_state->frame.eflags &= ~( EFL_VM | EFL_NT | EFL_IOPL | EFL_CLR ); ! 844: saved_state->frame.eflags |= ( EFL_IF | EFL_SET ); ! 845: saved_state->frame.eip = state->eip; ! 846: saved_state->frame.cs = selector_to_sel(state->cs); ! 847: saved_state->regs.ds = selector_to_sel(state->ds); ! 848: saved_state->regs.es = selector_to_sel(state->es); ! 849: saved_state->regs.fs = selector_to_sel(state->fs); ! 850: saved_state->regs.gs = selector_to_sel(state->gs); ! 851: } ! 852: ! 853: return (KERN_SUCCESS); ! 854: } ! 855: ! 856: static ! 857: void ! 858: set_thread_v86_state( ! 859: thread_t thread, ! 860: i386_thread_state_t *state ! 861: ) ! 862: { ! 863: thread_saved_state_t *saved_state = USER_REGS(thread); ! 864: ! 865: saved_state->regs.eax = state->eax; ! 866: saved_state->regs.ebx = state->ebx; ! 867: saved_state->regs.ecx = state->ecx; ! 868: saved_state->regs.edx = state->edx; ! 869: saved_state->regs.edi = state->edi; ! 870: saved_state->regs.esi = state->esi; ! 871: saved_state->regs.ebp = state->ebp; ! 872: saved_state->frame.esp = state->esp; ! 873: saved_state->frame.ss = selector_to_sel(state->ss); ! 874: saved_state->frame.eflags = state->eflags; ! 875: saved_state->frame.eflags &= ~( EFL_NT | EFL_IOPL | EFL_CLR ); ! 876: saved_state->frame.eflags |= ( EFL_VM | EFL_IF | EFL_SET ); ! 877: saved_state->frame.eip = state->eip; ! 878: saved_state->frame.cs = selector_to_sel(state->cs); ! 879: saved_state->regs.ds = NULL_SEL; ! 880: saved_state->regs.es = NULL_SEL; ! 881: saved_state->regs.fs = NULL_SEL; ! 882: saved_state->regs.gs = NULL_SEL; ! 883: saved_state->frame.v_ds = state->ds; ! 884: saved_state->frame.v_es = state->es; ! 885: saved_state->frame.v_fs = state->fs; ! 886: saved_state->frame.v_gs = state->gs; ! 887: } ! 888: ! 889: kern_return_t ! 890: set_thread_fpstate( ! 891: thread_t thread, ! 892: thread_state_t tstate, ! 893: unsigned int count ! 894: ) ! 895: { ! 896: fp_state_t *saved_state; ! 897: i386_thread_fpstate_t *state; ! 898: ! 899: if (count < i386_THREAD_FPSTATE_COUNT) ! 900: return (KERN_INVALID_ARGUMENT); ! 901: ! 902: state = (i386_thread_fpstate_t *)tstate; ! 903: saved_state = &thread->pcb->fpstate; ! 904: ! 905: fp_terminate(thread); ! 906: ! 907: saved_state->environ = state->environ; ! 908: saved_state->stack = state->stack; ! 909: ! 910: thread->pcb->fpvalid = TRUE; ! 911: ! 912: return (KERN_SUCCESS); ! 913: } ! 914: ! 915: kern_return_t ! 916: thread_set_cthread_self( ! 917: int self ! 918: ) ! 919: { ! 920: current_thread()->pcb->cthread_self = (unsigned int)self; ! 921: ! 922: return (KERN_SUCCESS); ! 923: } ! 924: ! 925: /* ! 926: * Return externally visible ! 927: * thread status. ! 928: */ ! 929: kern_return_t ! 930: thread_getstatus( ! 931: thread_t thread, ! 932: int flavor, ! 933: thread_state_t tstate, ! 934: unsigned int *count ! 935: ) ! 936: { ! 937: switch (flavor) { ! 938: ! 939: case i386_THREAD_STATE: ! 940: return (get_thread_state(thread, tstate, count)); ! 941: ! 942: case i386_THREAD_FPSTATE: ! 943: return (get_thread_fpstate(thread, tstate, count)); ! 944: ! 945: case i386_THREAD_EXCEPTSTATE: ! 946: return (get_thread_exceptstate(thread, tstate, count)); ! 947: ! 948: case i386_THREAD_CTHREADSTATE: ! 949: return (get_thread_cthreadstate(thread, tstate, count)); ! 950: ! 951: case THREAD_STATE_FLAVOR_LIST: ! 952: return (get_thread_state_flavor_list(tstate, count)); ! 953: ! 954: default: ! 955: return (KERN_INVALID_ARGUMENT); ! 956: } ! 957: } ! 958: ! 959: kern_return_t ! 960: get_thread_state( ! 961: thread_t thread, ! 962: thread_state_t tstate, ! 963: unsigned int *count ! 964: ) ! 965: { ! 966: thread_saved_state_t *saved_state; ! 967: i386_thread_state_t *state; ! 968: ! 969: if (*count < i386_THREAD_STATE_COUNT) ! 970: return (KERN_INVALID_ARGUMENT); ! 971: ! 972: state = (i386_thread_state_t *)tstate; ! 973: saved_state = USER_REGS(thread); ! 974: ! 975: state->eax = saved_state->regs.eax; ! 976: state->ebx = saved_state->regs.ebx; ! 977: state->ecx = saved_state->regs.ecx; ! 978: state->edx = saved_state->regs.edx; ! 979: state->edi = saved_state->regs.edi; ! 980: state->esi = saved_state->regs.esi; ! 981: state->ebp = saved_state->regs.ebp; ! 982: state->esp = saved_state->frame.esp; ! 983: state->ss = sel_to_selector(saved_state->frame.ss); ! 984: state->eflags = saved_state->frame.eflags; ! 985: state->eip = saved_state->frame.eip; ! 986: state->cs = sel_to_selector(saved_state->frame.cs); ! 987: if ((saved_state->frame.eflags & EFL_VM) == 0) { ! 988: state->ds = sel_to_selector(saved_state->regs.ds); ! 989: state->es = sel_to_selector(saved_state->regs.es); ! 990: state->fs = sel_to_selector(saved_state->regs.fs); ! 991: state->gs = sel_to_selector(saved_state->regs.gs); ! 992: } ! 993: else { ! 994: state->ds = saved_state->frame.v_ds; ! 995: state->es = saved_state->frame.v_es; ! 996: state->fs = saved_state->frame.v_fs; ! 997: state->gs = saved_state->frame.v_gs; ! 998: } ! 999: ! 1000: *count = i386_THREAD_STATE_COUNT; ! 1001: ! 1002: return (KERN_SUCCESS); ! 1003: } ! 1004: ! 1005: kern_return_t ! 1006: get_thread_fpstate( ! 1007: thread_t thread, ! 1008: thread_state_t tstate, ! 1009: unsigned int *count ! 1010: ) ! 1011: { ! 1012: fp_state_t *saved_state; ! 1013: i386_thread_fpstate_t *state; ! 1014: ! 1015: if (*count < i386_THREAD_FPSTATE_COUNT) ! 1016: return (KERN_INVALID_ARGUMENT); ! 1017: ! 1018: state = (i386_thread_fpstate_t *)tstate; ! 1019: saved_state = &thread->pcb->fpstate; ! 1020: ! 1021: fp_synch(thread); ! 1022: ! 1023: state->environ = saved_state->environ; ! 1024: state->stack = saved_state->stack; ! 1025: ! 1026: *count = i386_THREAD_FPSTATE_COUNT; ! 1027: ! 1028: return (KERN_SUCCESS); ! 1029: } ! 1030: ! 1031: kern_return_t ! 1032: get_thread_exceptstate( ! 1033: thread_t thread, ! 1034: thread_state_t tstate, ! 1035: unsigned int *count ! 1036: ) ! 1037: { ! 1038: thread_saved_state_t *saved_state; ! 1039: i386_thread_exceptstate_t *state; ! 1040: ! 1041: if (*count < i386_THREAD_EXCEPTSTATE_COUNT) ! 1042: return (KERN_INVALID_ARGUMENT); ! 1043: ! 1044: state = (i386_thread_exceptstate_t *)tstate; ! 1045: saved_state = USER_REGS(thread); ! 1046: ! 1047: state->trapno = saved_state->trapno; ! 1048: state->err = saved_state->frame.err; ! 1049: ! 1050: *count = i386_THREAD_EXCEPTSTATE_COUNT; ! 1051: ! 1052: return (KERN_SUCCESS); ! 1053: } ! 1054: ! 1055: kern_return_t ! 1056: get_thread_cthreadstate( ! 1057: thread_t thread, ! 1058: thread_state_t tstate, ! 1059: unsigned int *count ! 1060: ) ! 1061: { ! 1062: i386_thread_cthreadstate_t *state; ! 1063: ! 1064: if (*count < i386_THREAD_CTHREADSTATE_COUNT) ! 1065: return (KERN_INVALID_ARGUMENT); ! 1066: ! 1067: state = (i386_thread_cthreadstate_t *)tstate; ! 1068: state->self = thread->pcb->cthread_self; ! 1069: ! 1070: *count = i386_THREAD_CTHREADSTATE_COUNT; ! 1071: ! 1072: return (KERN_SUCCESS); ! 1073: } ! 1074: ! 1075: kern_return_t ! 1076: thread_get_cthread_self( ! 1077: void ! 1078: ) ! 1079: { ! 1080: return ((kern_return_t)current_thread()->pcb->cthread_self); ! 1081: } ! 1082: ! 1083: kern_return_t ! 1084: get_thread_state_flavor_list( ! 1085: thread_state_t tstate, ! 1086: unsigned int *count ! 1087: ) ! 1088: { ! 1089: struct thread_state_flavor *state; ! 1090: #define i386_THREAD_STATE_FLAVOR_COUNT 4 ! 1091: ! 1092: #define i386_THREAD_STATE_FLAVOR_LIST_COUNT \ ! 1093: ( i386_THREAD_STATE_FLAVOR_COUNT * \ ! 1094: ( sizeof (struct thread_state_flavor) / sizeof (int) ) ) ! 1095: ! 1096: if (*count < i386_THREAD_STATE_FLAVOR_COUNT) ! 1097: return (KERN_INVALID_ARGUMENT); ! 1098: ! 1099: state = (struct thread_state_flavor *)tstate; ! 1100: ! 1101: state->flavor = i386_THREAD_STATE; ! 1102: state->count = i386_THREAD_STATE_COUNT; ! 1103: ! 1104: (++state)->flavor = i386_THREAD_FPSTATE; ! 1105: state->count = i386_THREAD_FPSTATE_COUNT; ! 1106: ! 1107: (++state)->flavor = i386_THREAD_EXCEPTSTATE; ! 1108: state->count = i386_THREAD_EXCEPTSTATE_COUNT; ! 1109: ! 1110: (++state)->flavor = i386_THREAD_CTHREADSTATE; ! 1111: state->count = i386_THREAD_CTHREADSTATE_COUNT; ! 1112: ! 1113: *count = i386_THREAD_STATE_FLAVOR_LIST_COUNT; ! 1114: ! 1115: return (KERN_SUCCESS); ! 1116: } ! 1117: ! 1118: /* ! 1119: * thread_userstack: ! 1120: * ! 1121: * Return the user stack pointer from the machine dependent thread state info. ! 1122: */ ! 1123: kern_return_t ! 1124: thread_userstack( ! 1125: thread_t thread, ! 1126: int flavor, ! 1127: thread_state_t tstate, ! 1128: unsigned int count, ! 1129: vm_offset_t *user_stack ! 1130: ) ! 1131: { ! 1132: i386_thread_state_t *state; ! 1133: ! 1134: /* ! 1135: * Set a default. ! 1136: */ ! 1137: if (*user_stack == 0) ! 1138: *user_stack = VM_MAX_ADDRESS; ! 1139: ! 1140: switch (flavor) { ! 1141: ! 1142: case i386_THREAD_STATE: ! 1143: if (count < i386_THREAD_STATE_COUNT) ! 1144: return (KERN_INVALID_ARGUMENT); ! 1145: ! 1146: state = (i386_thread_state_t *) tstate; ! 1147: ! 1148: /* ! 1149: * If a valid user stack is specified, use it. ! 1150: */ ! 1151: *user_stack = state->esp ? state->esp: VM_MAX_ADDRESS; ! 1152: break; ! 1153: } ! 1154: ! 1155: return (KERN_SUCCESS); ! 1156: } ! 1157: kern_return_t ! 1158: thread_entrypoint( ! 1159: thread_t thread, ! 1160: int flavor, ! 1161: thread_state_t tstate, ! 1162: unsigned int count, ! 1163: vm_offset_t *entry_point ! 1164: ) ! 1165: { ! 1166: i386_thread_state_t *state; ! 1167: ! 1168: /* ! 1169: * Set a default. ! 1170: */ ! 1171: if (*entry_point == 0) ! 1172: *entry_point = VM_MIN_ADDRESS; ! 1173: ! 1174: switch (flavor) { ! 1175: ! 1176: case i386_THREAD_STATE: ! 1177: if (count < i386_THREAD_STATE_COUNT) ! 1178: return (KERN_INVALID_ARGUMENT); ! 1179: ! 1180: state = (i386_thread_state_t *) tstate; ! 1181: ! 1182: /* ! 1183: * If a valid entry point is specified, use it. ! 1184: */ ! 1185: *entry_point = state->eip ? state->eip: VM_MIN_ADDRESS; ! 1186: break; ! 1187: } ! 1188: ! 1189: return (KERN_SUCCESS); ! 1190: } ! 1191: ! 1192: /* ! 1193: * Duplicate parent state in child ! 1194: * for U**X fork. ! 1195: */ ! 1196: thread_dup( ! 1197: thread_t parent, ! 1198: thread_t child ! 1199: ) ! 1200: { ! 1201: struct thread_saved_state *parent_state, *child_state; ! 1202: ! 1203: parent_state = USER_REGS(parent); ! 1204: child_state = thread_user_state(child); ! 1205: ! 1206: *child_state = *parent_state; ! 1207: ! 1208: child_state->regs.eax = child->task->proc->p_pid; ! 1209: ! 1210: child_state->regs.edx = 1; ! 1211: child_state->frame.eflags &= ~EFL_CF; ! 1212: } ! 1213: ! 1214: /* ! 1215: * Release resources on ! 1216: * thread termination. ! 1217: */ ! 1218: pcb_terminate( ! 1219: thread_t thread ! 1220: ) ! 1221: { ! 1222: struct pcb *pcb = thread->pcb; ! 1223: ! 1224: /* ! 1225: * Give up the fpu if ! 1226: * necessary. ! 1227: */ ! 1228: fp_terminate(thread); ! 1229: ! 1230: #if PC_SUPPORT ! 1231: if (pcb->PCpriv) ! 1232: PCdestroy(thread); ! 1233: #endif ! 1234: ! 1235: /* ! 1236: * Free save area. ! 1237: */ ! 1238: if (pcb->save_area) ! 1239: kfree((void *)pcb->save_area, ! 1240: sizeof (*pcb->save_area)); ! 1241: ! 1242: /* ! 1243: * Free external tss. ! 1244: */ ! 1245: if (pcb->extern_tss) ! 1246: kfree( ! 1247: (void *)pcb->tss_store.external.base, ! 1248: pcb->tss_store.external.length); ! 1249: ! 1250: thread->pcb = 0; ! 1251: zfree(pcb_zone, pcb); ! 1252: } ! 1253: ! 1254: /* ! 1255: * Synchronize pcb with ! 1256: * hardware state. ! 1257: */ ! 1258: pcb_synch( ! 1259: thread_t thread ! 1260: ) ! 1261: { ! 1262: /* ! 1263: * Write out our fp state ! 1264: * if necessary. ! 1265: */ ! 1266: fp_synch(thread); ! 1267: } ! 1268: ! 1269: void ! 1270: pcb_common_terminate( ! 1271: task_t task ! 1272: ) ! 1273: { ! 1274: pcb_common_t *common = task->pcb_common; ! 1275: ! 1276: kfree((void *)common, sizeof (*common)); ! 1277: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.