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