|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: kern/machine.c ! 31: * Author: Avadis Tevanian, Jr. ! 32: * Date: 1987 ! 33: * ! 34: * Support for machine independent machine abstraction. ! 35: */ ! 36: ! 37: #include <norma_ether.h> ! 38: #include <cpus.h> ! 39: #include <mach_host.h> ! 40: ! 41: #include <mach/boolean.h> ! 42: #include <mach/kern_return.h> ! 43: #include <mach/mach_types.h> ! 44: #include <mach/machine.h> ! 45: #include <mach/host_info.h> ! 46: #include <kern/counters.h> ! 47: #include <kern/ipc_host.h> ! 48: #include <kern/host.h> ! 49: #include <kern/lock.h> ! 50: #include <kern/processor.h> ! 51: #include <kern/queue.h> ! 52: #include <kern/sched.h> ! 53: #include <kern/task.h> ! 54: #include <kern/thread.h> ! 55: #include <machine/machspl.h> /* for splsched */ ! 56: #include <sys/reboot.h> ! 57: ! 58: ! 59: ! 60: /* ! 61: * Exported variables: ! 62: */ ! 63: ! 64: struct machine_info machine_info; ! 65: struct machine_slot machine_slot[NCPUS]; ! 66: ! 67: queue_head_t action_queue; /* assign/shutdown queue */ ! 68: decl_simple_lock_data(,action_lock); ! 69: ! 70: /* ! 71: * xxx_host_info: ! 72: * ! 73: * Return the host_info structure. This routine is exported to the ! 74: * user level. ! 75: */ ! 76: kern_return_t xxx_host_info(task, info) ! 77: task_t task; ! 78: machine_info_t info; ! 79: { ! 80: #ifdef lint ! 81: task++; ! 82: #endif /* lint */ ! 83: *info = machine_info; ! 84: return(KERN_SUCCESS); ! 85: } ! 86: ! 87: /* ! 88: * xxx_slot_info: ! 89: * ! 90: * Return the slot_info structure for the specified slot. This routine ! 91: * is exported to the user level. ! 92: */ ! 93: kern_return_t xxx_slot_info(task, slot, info) ! 94: task_t task; ! 95: int slot; ! 96: machine_slot_t info; ! 97: { ! 98: #ifdef lint ! 99: task++; ! 100: #endif /* lint */ ! 101: if ((slot < 0) || (slot >= NCPUS)) ! 102: return(KERN_INVALID_ARGUMENT); ! 103: *info = machine_slot[slot]; ! 104: return(KERN_SUCCESS); ! 105: } ! 106: ! 107: /* ! 108: * xxx_cpu_control: ! 109: * ! 110: * Support for user control of cpus. The user indicates which cpu ! 111: * he is interested in, and whether or not that cpu should be running. ! 112: */ ! 113: kern_return_t xxx_cpu_control(task, cpu, runnable) ! 114: task_t task; ! 115: int cpu; ! 116: boolean_t runnable; ! 117: { ! 118: #ifdef lint ! 119: task++; cpu++; runnable++; ! 120: #endif /* lint */ ! 121: return(KERN_FAILURE); ! 122: } ! 123: ! 124: /* ! 125: * cpu_up: ! 126: * ! 127: * Flag specified cpu as up and running. Called when a processor comes ! 128: * online. ! 129: */ ! 130: void cpu_up(cpu) ! 131: int cpu; ! 132: { ! 133: register struct machine_slot *ms; ! 134: register processor_t processor; ! 135: register spl_t s; ! 136: ! 137: processor = cpu_to_processor(cpu); ! 138: pset_lock(&default_pset); ! 139: s = splsched(); ! 140: processor_lock(processor); ! 141: #if NCPUS > 1 ! 142: init_ast_check(processor); ! 143: #endif /* NCPUS > 1 */ ! 144: ms = &machine_slot[cpu]; ! 145: ms->running = TRUE; ! 146: machine_info.avail_cpus++; ! 147: pset_add_processor(&default_pset, processor); ! 148: processor->state = PROCESSOR_RUNNING; ! 149: processor_unlock(processor); ! 150: splx(s); ! 151: pset_unlock(&default_pset); ! 152: } ! 153: ! 154: /* ! 155: * cpu_down: ! 156: * ! 157: * Flag specified cpu as down. Called when a processor is about to ! 158: * go offline. ! 159: */ ! 160: void cpu_down(cpu) ! 161: int cpu; ! 162: { ! 163: register struct machine_slot *ms; ! 164: register processor_t processor; ! 165: register spl_t s; ! 166: ! 167: s = splsched(); ! 168: processor = cpu_to_processor(cpu); ! 169: processor_lock(processor); ! 170: ms = &machine_slot[cpu]; ! 171: ms->running = FALSE; ! 172: machine_info.avail_cpus--; ! 173: /* ! 174: * processor has already been removed from pset. ! 175: */ ! 176: processor->processor_set_next = PROCESSOR_SET_NULL; ! 177: processor->state = PROCESSOR_OFF_LINE; ! 178: processor_unlock(processor); ! 179: splx(s); ! 180: } ! 181: ! 182: kern_return_t ! 183: host_reboot(host, options) ! 184: host_t host; ! 185: int options; ! 186: { ! 187: if (host == HOST_NULL) ! 188: return (KERN_INVALID_HOST); ! 189: ! 190: if (options & RB_DEBUGGER) { ! 191: extern void Debugger(); ! 192: Debugger("Debugger"); ! 193: } else { ! 194: #ifdef parisc ! 195: /* XXX this could be made common */ ! 196: halt_all_cpus(options); ! 197: #else ! 198: halt_all_cpus(!(options & RB_HALT)); ! 199: #endif ! 200: } ! 201: return (KERN_SUCCESS); ! 202: } ! 203: ! 204: #if NCPUS > 1 ! 205: /* ! 206: * processor_request_action - common internals of processor_assign ! 207: * and processor_shutdown. If new_pset is null, this is ! 208: * a shutdown, else it's an assign and caller must donate ! 209: * a reference. ! 210: */ ! 211: void ! 212: processor_request_action(processor, new_pset) ! 213: processor_t processor; ! 214: processor_set_t new_pset; ! 215: { ! 216: register processor_set_t pset; ! 217: ! 218: /* ! 219: * Processor must be in a processor set. Must lock its idle lock to ! 220: * get at processor state. ! 221: */ ! 222: pset = processor->processor_set; ! 223: simple_lock(&pset->idle_lock); ! 224: ! 225: /* ! 226: * If the processor is dispatching, let it finish - it will set its ! 227: * state to running very soon. ! 228: */ ! 229: while (*(volatile int *)&processor->state == PROCESSOR_DISPATCHING) ! 230: continue; ! 231: ! 232: /* ! 233: * Now lock the action queue and do the dirty work. ! 234: */ ! 235: simple_lock(&action_lock); ! 236: ! 237: switch (processor->state) { ! 238: case PROCESSOR_IDLE: ! 239: /* ! 240: * Remove from idle queue. ! 241: */ ! 242: queue_remove(&pset->idle_queue, processor, processor_t, ! 243: processor_queue); ! 244: pset->idle_count--; ! 245: ! 246: /* fall through ... */ ! 247: case PROCESSOR_RUNNING: ! 248: /* ! 249: * Put it on the action queue. ! 250: */ ! 251: queue_enter(&action_queue, processor, processor_t, ! 252: processor_queue); ! 253: ! 254: /* fall through ... */ ! 255: case PROCESSOR_ASSIGN: ! 256: /* ! 257: * And ask the action_thread to do the work. ! 258: */ ! 259: ! 260: if (new_pset == PROCESSOR_SET_NULL) { ! 261: processor->state = PROCESSOR_SHUTDOWN; ! 262: } ! 263: else { ! 264: assert(processor->state != PROCESSOR_ASSIGN); ! 265: processor->state = PROCESSOR_ASSIGN; ! 266: processor->processor_set_next = new_pset; ! 267: } ! 268: break; ! 269: ! 270: default: ! 271: printf("state: %d\n", processor->state); ! 272: panic("processor_request_action: bad state"); ! 273: } ! 274: simple_unlock(&action_lock); ! 275: simple_unlock(&pset->idle_lock); ! 276: ! 277: thread_wakeup((event_t)&action_queue); ! 278: } ! 279: ! 280: #if MACH_HOST ! 281: /* ! 282: * processor_assign() changes the processor set that a processor is ! 283: * assigned to. Any previous assignment in progress is overridden. ! 284: * Synchronizes with assignment completion if wait is TRUE. ! 285: */ ! 286: kern_return_t ! 287: processor_assign(processor, new_pset, wait) ! 288: processor_t processor; ! 289: processor_set_t new_pset; ! 290: boolean_t wait; ! 291: { ! 292: spl_t s; ! 293: ! 294: /* ! 295: * Check for null arguments. ! 296: * XXX Can't assign master processor. ! 297: */ ! 298: if (processor == PROCESSOR_NULL || new_pset == PROCESSOR_SET_NULL || ! 299: processor == master_processor) { ! 300: return(KERN_INVALID_ARGUMENT); ! 301: } ! 302: ! 303: /* ! 304: * Get pset reference to donate to processor_request_action. ! 305: */ ! 306: pset_reference(new_pset); ! 307: ! 308: /* ! 309: * Check processor status. ! 310: * If shutdown or being shutdown, can`t reassign. ! 311: * If being assigned, wait for assignment to finish. ! 312: */ ! 313: Retry: ! 314: s = splsched(); ! 315: processor_lock(processor); ! 316: if(processor->state == PROCESSOR_OFF_LINE || ! 317: processor->state == PROCESSOR_SHUTDOWN) { ! 318: /* ! 319: * Already shutdown or being shutdown -- Can't reassign. ! 320: */ ! 321: processor_unlock(processor); ! 322: (void) splx(s); ! 323: pset_deallocate(new_pset); ! 324: return(KERN_FAILURE); ! 325: } ! 326: ! 327: if (processor->state == PROCESSOR_ASSIGN) { ! 328: assert_wait((event_t) processor, TRUE); ! 329: processor_unlock(processor); ! 330: splx(s); ! 331: thread_block((void(*)()) 0); ! 332: goto Retry; ! 333: } ! 334: ! 335: /* ! 336: * Avoid work if processor is already in this processor set. ! 337: */ ! 338: if (processor->processor_set == new_pset) { ! 339: processor_unlock(processor); ! 340: (void) splx(s); ! 341: /* clean up dangling ref */ ! 342: pset_deallocate(new_pset); ! 343: return(KERN_SUCCESS); ! 344: } ! 345: ! 346: /* ! 347: * OK to start processor assignment. ! 348: */ ! 349: processor_request_action(processor, new_pset); ! 350: ! 351: /* ! 352: * Synchronization with completion. ! 353: */ ! 354: if (wait) { ! 355: while (processor->state == PROCESSOR_ASSIGN || ! 356: processor->state == PROCESSOR_SHUTDOWN) { ! 357: assert_wait((event_t)processor, TRUE); ! 358: processor_unlock(processor); ! 359: splx(s); ! 360: thread_block((void (*)()) 0); ! 361: s = splsched(); ! 362: processor_lock(processor); ! 363: } ! 364: } ! 365: processor_unlock(processor); ! 366: splx(s); ! 367: ! 368: return(KERN_SUCCESS); ! 369: } ! 370: ! 371: #else /* MACH_HOST */ ! 372: ! 373: kern_return_t ! 374: processor_assign(processor, new_pset, wait) ! 375: processor_t processor; ! 376: processor_set_t new_pset; ! 377: boolean_t wait; ! 378: { ! 379: #ifdef lint ! 380: processor++; new_pset++; wait++; ! 381: #endif ! 382: return KERN_FAILURE; ! 383: } ! 384: ! 385: #endif /* MACH_HOST */ ! 386: ! 387: /* ! 388: * processor_shutdown() queues a processor up for shutdown. ! 389: * Any assignment in progress is overriden. It does not synchronize ! 390: * with the shutdown (can be called from interrupt level). ! 391: */ ! 392: kern_return_t ! 393: processor_shutdown(processor) ! 394: processor_t processor; ! 395: { ! 396: spl_t s; ! 397: ! 398: if (processor == PROCESSOR_NULL) ! 399: return KERN_INVALID_ARGUMENT; ! 400: ! 401: s = splsched(); ! 402: processor_lock(processor); ! 403: if(processor->state == PROCESSOR_OFF_LINE || ! 404: processor->state == PROCESSOR_SHUTDOWN) { ! 405: /* ! 406: * Already shutdown or being shutdown -- nothing to do. ! 407: */ ! 408: processor_unlock(processor); ! 409: splx(s); ! 410: return(KERN_SUCCESS); ! 411: } ! 412: ! 413: processor_request_action(processor, PROCESSOR_SET_NULL); ! 414: processor_unlock(processor); ! 415: splx(s); ! 416: ! 417: return(KERN_SUCCESS); ! 418: } ! 419: ! 420: /* ! 421: * action_thread() shuts down processors or changes their assignment. ! 422: */ ! 423: void processor_doaction(); /* forward */ ! 424: ! 425: void action_thread_continue() ! 426: { ! 427: register processor_t processor; ! 428: register spl_t s; ! 429: ! 430: while (TRUE) { ! 431: s = splsched(); ! 432: simple_lock(&action_lock); ! 433: while ( !queue_empty(&action_queue)) { ! 434: processor = (processor_t) queue_first(&action_queue); ! 435: queue_remove(&action_queue, processor, processor_t, ! 436: processor_queue); ! 437: simple_unlock(&action_lock); ! 438: (void) splx(s); ! 439: ! 440: processor_doaction(processor); ! 441: ! 442: s = splsched(); ! 443: simple_lock(&action_lock); ! 444: } ! 445: ! 446: assert_wait((event_t) &action_queue, FALSE); ! 447: simple_unlock(&action_lock); ! 448: (void) splx(s); ! 449: counter(c_action_thread_block++); ! 450: thread_block(action_thread_continue); ! 451: } ! 452: } ! 453: ! 454: void action_thread() ! 455: { ! 456: action_thread_continue(); ! 457: /*NOTREACHED*/ ! 458: } ! 459: ! 460: /* ! 461: * processor_doaction actually does the shutdown. The trick here ! 462: * is to schedule ourselves onto a cpu and then save our ! 463: * context back into the runqs before taking out the cpu. ! 464: */ ! 465: #ifdef __GNUC__ ! 466: __volatile__ ! 467: #endif ! 468: void processor_doshutdown(); /* forward */ ! 469: ! 470: void processor_doaction(processor) ! 471: register processor_t processor; ! 472: { ! 473: thread_t this_thread; ! 474: spl_t s; ! 475: register processor_set_t pset; ! 476: #if MACH_HOST ! 477: register processor_set_t new_pset; ! 478: register thread_t thread; ! 479: register thread_t prev_thread = THREAD_NULL; ! 480: boolean_t have_pset_ref = FALSE; ! 481: #endif /* MACH_HOST */ ! 482: ! 483: /* ! 484: * Get onto the processor to shutdown ! 485: */ ! 486: this_thread = current_thread(); ! 487: thread_bind(this_thread, processor); ! 488: thread_block((void (*)()) 0); ! 489: ! 490: pset = processor->processor_set; ! 491: #if MACH_HOST ! 492: /* ! 493: * If this is the last processor in the processor_set, ! 494: * stop all the threads first. ! 495: */ ! 496: pset_lock(pset); ! 497: if (pset->processor_count == 1) { ! 498: /* ! 499: * First suspend all of them. ! 500: */ ! 501: queue_iterate(&pset->threads, thread, thread_t, pset_threads) { ! 502: thread_hold(thread); ! 503: } ! 504: pset->empty = TRUE; ! 505: /* ! 506: * Now actually stop them. Need a pset reference. ! 507: */ ! 508: pset->ref_count++; ! 509: have_pset_ref = TRUE; ! 510: ! 511: Restart_thread: ! 512: prev_thread = THREAD_NULL; ! 513: queue_iterate(&pset->threads, thread, thread_t, pset_threads) { ! 514: thread_reference(thread); ! 515: pset_unlock(pset); ! 516: if (prev_thread != THREAD_NULL) ! 517: thread_deallocate(prev_thread); ! 518: ! 519: /* ! 520: * Only wait for threads still in the pset. ! 521: */ ! 522: thread_freeze(thread); ! 523: if (thread->processor_set != pset) { ! 524: /* ! 525: * It got away - start over. ! 526: */ ! 527: thread_unfreeze(thread); ! 528: thread_deallocate(thread); ! 529: pset_lock(pset); ! 530: goto Restart_thread; ! 531: } ! 532: ! 533: (void) thread_dowait(thread, TRUE); ! 534: prev_thread = thread; ! 535: pset_lock(pset); ! 536: thread_unfreeze(prev_thread); ! 537: } ! 538: } ! 539: pset_unlock(pset); ! 540: ! 541: /* ! 542: * At this point, it is ok to remove the processor from the pset. ! 543: * We can use processor->processor_set_next without locking the ! 544: * processor, since it cannot change while processor->state is ! 545: * PROCESSOR_ASSIGN or PROCESSOR_SHUTDOWN. ! 546: */ ! 547: ! 548: new_pset = processor->processor_set_next; ! 549: ! 550: Restart_pset: ! 551: if (new_pset) { ! 552: /* ! 553: * Reassigning processor. ! 554: */ ! 555: ! 556: if ((integer_t) pset < (integer_t) new_pset) { ! 557: pset_lock(pset); ! 558: pset_lock(new_pset); ! 559: } ! 560: else { ! 561: pset_lock(new_pset); ! 562: pset_lock(pset); ! 563: } ! 564: if (!(new_pset->active)) { ! 565: pset_unlock(new_pset); ! 566: pset_unlock(pset); ! 567: pset_deallocate(new_pset); ! 568: new_pset = &default_pset; ! 569: pset_reference(new_pset); ! 570: goto Restart_pset; ! 571: } ! 572: ! 573: /* ! 574: * Handle remove last / assign first race. ! 575: * Only happens if there is more than one action thread. ! 576: */ ! 577: while (new_pset->empty && new_pset->processor_count > 0) { ! 578: pset_unlock(new_pset); ! 579: pset_unlock(pset); ! 580: while (*(volatile boolean_t *)&new_pset->empty && ! 581: *(volatile int *)&new_pset->processor_count > 0) ! 582: /* spin */; ! 583: goto Restart_pset; ! 584: } ! 585: ! 586: /* ! 587: * Lock the processor. new_pset should not have changed. ! 588: */ ! 589: s = splsched(); ! 590: processor_lock(processor); ! 591: assert(processor->processor_set_next == new_pset); ! 592: ! 593: /* ! 594: * Shutdown may have been requested while this assignment ! 595: * was in progress. ! 596: */ ! 597: if (processor->state == PROCESSOR_SHUTDOWN) { ! 598: processor->processor_set_next = PROCESSOR_SET_NULL; ! 599: pset_unlock(new_pset); ! 600: goto shutdown; /* releases pset reference */ ! 601: } ! 602: ! 603: /* ! 604: * Do assignment, then wakeup anyone waiting for it. ! 605: */ ! 606: pset_remove_processor(pset, processor); ! 607: pset_unlock(pset); ! 608: ! 609: pset_add_processor(new_pset, processor); ! 610: if (new_pset->empty) { ! 611: /* ! 612: * Set all the threads loose. ! 613: * ! 614: * NOTE: this appears to violate the locking ! 615: * order, since the processor lock should ! 616: * be taken AFTER a thread lock. However, ! 617: * thread_setrun (called by thread_release) ! 618: * only takes the processor lock if the ! 619: * processor is idle. The processor is ! 620: * not idle here. ! 621: */ ! 622: queue_iterate(&new_pset->threads, thread, thread_t, ! 623: pset_threads) { ! 624: thread_release(thread); ! 625: } ! 626: new_pset->empty = FALSE; ! 627: } ! 628: processor->processor_set_next = PROCESSOR_SET_NULL; ! 629: processor->state = PROCESSOR_RUNNING; ! 630: thread_wakeup((event_t)processor); ! 631: processor_unlock(processor); ! 632: splx(s); ! 633: pset_unlock(new_pset); ! 634: ! 635: /* ! 636: * Clean up dangling references, and release our binding. ! 637: */ ! 638: pset_deallocate(new_pset); ! 639: if (have_pset_ref) ! 640: pset_deallocate(pset); ! 641: if (prev_thread != THREAD_NULL) ! 642: thread_deallocate(prev_thread); ! 643: thread_bind(this_thread, PROCESSOR_NULL); ! 644: ! 645: thread_block((void (*)()) 0); ! 646: return; ! 647: } ! 648: ! 649: #endif /* MACH_HOST */ ! 650: ! 651: /* ! 652: * Do shutdown, make sure we live when processor dies. ! 653: */ ! 654: if (processor->state != PROCESSOR_SHUTDOWN) { ! 655: printf("state: %d\n", processor->state); ! 656: panic("action_thread -- bad processor state"); ! 657: } ! 658: ! 659: s = splsched(); ! 660: processor_lock(processor); ! 661: ! 662: shutdown: ! 663: pset_remove_processor(pset, processor); ! 664: processor_unlock(processor); ! 665: pset_unlock(pset); ! 666: splx(s); ! 667: ! 668: /* ! 669: * Clean up dangling references, and release our binding. ! 670: */ ! 671: #if MACH_HOST ! 672: if (new_pset != PROCESSOR_SET_NULL) ! 673: pset_deallocate(new_pset); ! 674: if (have_pset_ref) ! 675: pset_deallocate(pset); ! 676: if (prev_thread != THREAD_NULL) ! 677: thread_deallocate(prev_thread); ! 678: #endif /* MACH_HOST */ ! 679: ! 680: thread_bind(this_thread, PROCESSOR_NULL); ! 681: switch_to_shutdown_context(this_thread, ! 682: processor_doshutdown, ! 683: processor); ! 684: ! 685: } ! 686: ! 687: /* ! 688: * Actually do the processor shutdown. This is called at splsched, ! 689: * running on the processor's shutdown stack. ! 690: */ ! 691: ! 692: #ifdef __GNUC__ ! 693: extern __volatile__ void halt_cpu(); ! 694: #endif ! 695: ! 696: #ifdef __GNUC__ ! 697: __volatile__ ! 698: #endif ! 699: void processor_doshutdown(processor) ! 700: register processor_t processor; ! 701: { ! 702: register int cpu = processor->slot_num; ! 703: ! 704: timer_switch(&kernel_timer[cpu]); ! 705: ! 706: /* ! 707: * Ok, now exit this cpu. ! 708: */ ! 709: PMAP_DEACTIVATE_KERNEL(cpu); ! 710: #ifndef MIGRATING_THREADS ! 711: active_threads[cpu] = THREAD_NULL; ! 712: #endif ! 713: cpu_down(cpu); ! 714: thread_wakeup((event_t)processor); ! 715: halt_cpu(); ! 716: /* ! 717: * The action thread returns to life after the call to ! 718: * switch_to_shutdown_context above, on some other cpu. ! 719: */ ! 720: ! 721: /*NOTREACHED*/ ! 722: } ! 723: #else /* NCPUS > 1 */ ! 724: ! 725: kern_return_t ! 726: processor_assign(processor, new_pset, wait) ! 727: processor_t processor; ! 728: processor_set_t new_pset; ! 729: boolean_t wait; ! 730: { ! 731: #ifdef lint ! 732: processor++; new_pset++; wait++; ! 733: #endif lint ! 734: return(KERN_FAILURE); ! 735: } ! 736: ! 737: #endif /* NCPUS > 1 */ ! 738: ! 739: kern_return_t ! 740: host_get_boot_info(priv_host, boot_info) ! 741: host_t priv_host; ! 742: kernel_boot_info_t boot_info; ! 743: { ! 744: char *src = ""; ! 745: ! 746: if (priv_host == HOST_NULL) { ! 747: return KERN_INVALID_HOST; ! 748: } ! 749: ! 750: #if NORMA_ETHER ! 751: { ! 752: extern char *norma_ether_boot_info(); ! 753: src = norma_ether_boot_info(); ! 754: } ! 755: #endif /* NORMA_ETHER */ ! 756: #if defined(iPSC386) || defined(iPSC860) ! 757: { ! 758: extern char *ipsc_boot_environ(); ! 759: src = ipsc_boot_environ(); ! 760: } ! 761: #endif /* defined(iPSC386) || defined(iPSC860) */ ! 762: ! 763: (void) strncpy(boot_info, src, KERNEL_BOOT_INFO_MAX); ! 764: return KERN_SUCCESS; ! 765: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.