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