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