|
|
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.