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