|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1993-1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: * File: kern/machine.c
52: * Author: Avadis Tevanian, Jr.
53: * Date: 1987
54: *
55: * Support for machine independent machine abstraction.
56: */
57:
58: #include <norma_ether.h>
59: #include <cpus.h>
60: #include <mach_host.h>
61:
62: #include <mach/boolean.h>
63: #include <mach/kern_return.h>
64: #include <mach/mach_types.h>
65: #include <mach/machine.h>
66: #include <mach/host_info.h>
67: #include <kern/counters.h>
68: #include <kern/ipc_host.h>
69: #include <kern/host.h>
70: #include <kern/lock.h>
71: #include <kern/processor.h>
72: #include <kern/queue.h>
73: #include <kern/sched.h>
74: #include <kern/task.h>
75: #include <kern/thread.h>
76: #include <machine/machspl.h> /* for splsched */
77: #include <sys/reboot.h>
78:
79:
80:
81: /*
82: * Exported variables:
83: */
84:
85: struct machine_info machine_info;
86: struct machine_slot machine_slot[NCPUS];
87:
88: queue_head_t action_queue; /* assign/shutdown queue */
89: decl_simple_lock_data(,action_lock);
90:
91: /*
92: * xxx_host_info:
93: *
94: * Return the host_info structure. This routine is exported to the
95: * user level.
96: */
97: kern_return_t xxx_host_info(task, info)
98: task_t task;
99: machine_info_t info;
100: {
101: #ifdef lint
102: task++;
103: #endif /* lint */
104: *info = machine_info;
105: return(KERN_SUCCESS);
106: }
107:
108: /*
109: * xxx_slot_info:
110: *
111: * Return the slot_info structure for the specified slot. This routine
112: * is exported to the user level.
113: */
114: kern_return_t xxx_slot_info(task, slot, info)
115: task_t task;
116: int slot;
117: machine_slot_t info;
118: {
119: #ifdef lint
120: task++;
121: #endif /* lint */
122: if ((slot < 0) || (slot >= NCPUS))
123: return(KERN_INVALID_ARGUMENT);
124: *info = machine_slot[slot];
125: return(KERN_SUCCESS);
126: }
127:
128: /*
129: * xxx_cpu_control:
130: *
131: * Support for user control of cpus. The user indicates which cpu
132: * he is interested in, and whether or not that cpu should be running.
133: */
134: kern_return_t xxx_cpu_control(task, cpu, runnable)
135: task_t task;
136: int cpu;
137: boolean_t runnable;
138: {
139: #ifdef lint
140: task++; cpu++; runnable++;
141: #endif /* lint */
142: return(KERN_FAILURE);
143: }
144:
145: /*
146: * cpu_up:
147: *
148: * Flag specified cpu as up and running. Called when a processor comes
149: * online.
150: */
151: void cpu_up(cpu)
152: int cpu;
153: {
154: register struct machine_slot *ms;
155: register processor_t processor;
156: register spl_t s;
157:
158: processor = cpu_to_processor(cpu);
159: pset_lock(&default_pset);
160: s = splsched();
161: processor_lock(processor);
162: #if NCPUS > 1
163: init_ast_check(processor);
164: #endif /* NCPUS > 1 */
165: ms = &machine_slot[cpu];
166: ms->running = TRUE;
167: machine_info.avail_cpus++;
168: pset_add_processor(&default_pset, processor);
169: processor->state = PROCESSOR_RUNNING;
170: processor_unlock(processor);
171: splx(s);
172: pset_unlock(&default_pset);
173: }
174:
175: /*
176: * cpu_down:
177: *
178: * Flag specified cpu as down. Called when a processor is about to
179: * go offline.
180: */
181: void cpu_down(cpu)
182: int cpu;
183: {
184: register struct machine_slot *ms;
185: register processor_t processor;
186: register spl_t s;
187:
188: s = splsched();
189: processor = cpu_to_processor(cpu);
190: processor_lock(processor);
191: ms = &machine_slot[cpu];
192: ms->running = FALSE;
193: machine_info.avail_cpus--;
194: /*
195: * processor has already been removed from pset.
196: */
197: processor->processor_set_next = PROCESSOR_SET_NULL;
198: processor->state = PROCESSOR_OFF_LINE;
199: processor_unlock(processor);
200: splx(s);
201: }
202:
203: #if NCPUS > 1
204: /*
205: * processor_request_action - common internals of processor_assign
206: * and processor_shutdown. If new_pset is null, this is
207: * a shutdown, else it's an assign and caller must donate
208: * a reference.
209: */
210: void
211: processor_request_action(processor, new_pset)
212: processor_t processor;
213: processor_set_t new_pset;
214: {
215: register processor_set_t pset;
216:
217: /*
218: * Processor must be in a processor set. Must lock its idle lock to
219: * get at processor state.
220: */
221: pset = processor->processor_set;
222: simple_lock(&pset->idle_lock);
223:
224: /*
225: * If the processor is dispatching, let it finish - it will set its
226: * state to running very soon.
227: */
228: while (*(volatile int *)&processor->state == PROCESSOR_DISPATCHING)
229: continue;
230:
231: /*
232: * Now lock the action queue and do the dirty work.
233: */
234: simple_lock(&action_lock);
235:
236: switch (processor->state) {
237: case PROCESSOR_IDLE:
238: /*
239: * Remove from idle queue.
240: */
241: queue_remove(&pset->idle_queue, processor, processor_t,
242: processor_queue);
243: pset->idle_count--;
244:
245: /* fall through ... */
246: case PROCESSOR_RUNNING:
247: /*
248: * Put it on the action queue.
249: */
250: queue_enter(&action_queue, processor, processor_t,
251: processor_queue);
252:
253: /* fall through ... */
254: case PROCESSOR_ASSIGN:
255: /*
256: * And ask the action_thread to do the work.
257: */
258:
259: if (new_pset == PROCESSOR_SET_NULL) {
260: processor->state = PROCESSOR_SHUTDOWN;
261: }
262: else {
263: assert(processor->state != PROCESSOR_ASSIGN);
264: processor->state = PROCESSOR_ASSIGN;
265: processor->processor_set_next = new_pset;
266: }
267: break;
268:
269: default:
270: printf("state: %d\n", processor->state);
271: panic("processor_request_action: bad state");
272: }
273: simple_unlock(&action_lock);
274: simple_unlock(&pset->idle_lock);
275:
276: thread_wakeup((event_t)&action_queue);
277: }
278:
279: #if MACH_HOST
280: /*
281: * processor_assign() changes the processor set that a processor is
282: * assigned to. Any previous assignment in progress is overridden.
283: * Synchronizes with assignment completion if wait is TRUE.
284: */
285: kern_return_t
286: processor_assign(processor, new_pset, wait)
287: processor_t processor;
288: processor_set_t new_pset;
289: boolean_t wait;
290: {
291: spl_t s;
292:
293: /*
294: * Check for null arguments.
295: * XXX Can't assign master processor.
296: */
297: if (processor == PROCESSOR_NULL || new_pset == PROCESSOR_SET_NULL ||
298: processor == master_processor) {
299: return(KERN_INVALID_ARGUMENT);
300: }
301:
302: /*
303: * Get pset reference to donate to processor_request_action.
304: */
305: pset_reference(new_pset);
306:
307: /*
308: * Check processor status.
309: * If shutdown or being shutdown, can`t reassign.
310: * If being assigned, wait for assignment to finish.
311: */
312: Retry:
313: s = splsched();
314: processor_lock(processor);
315: if(processor->state == PROCESSOR_OFF_LINE ||
316: processor->state == PROCESSOR_SHUTDOWN) {
317: /*
318: * Already shutdown or being shutdown -- Can't reassign.
319: */
320: processor_unlock(processor);
321: (void) splx(s);
322: pset_deallocate(new_pset);
323: return(KERN_FAILURE);
324: }
325:
326: if (processor->state == PROCESSOR_ASSIGN) {
327: assert_wait((event_t) processor, TRUE);
328: processor_unlock(processor);
329: splx(s);
330: thread_block_continue((void(*)()) 0);
331: goto Retry;
332: }
333:
334: /*
335: * Avoid work if processor is already in this processor set.
336: */
337: if (processor->processor_set == new_pset) {
338: processor_unlock(processor);
339: (void) splx(s);
340: /* clean up dangling ref */
341: pset_deallocate(new_pset);
342: return(KERN_SUCCESS);
343: }
344:
345: /*
346: * OK to start processor assignment.
347: */
348: processor_request_action(processor, new_pset);
349:
350: /*
351: * Synchronization with completion.
352: */
353: if (wait) {
354: while (processor->state == PROCESSOR_ASSIGN ||
355: processor->state == PROCESSOR_SHUTDOWN) {
356: assert_wait((event_t)processor, TRUE);
357: processor_unlock(processor);
358: splx(s);
359: thread_block_continue((void (*)()) 0);
360: s = splsched();
361: processor_lock(processor);
362: }
363: }
364: processor_unlock(processor);
365: splx(s);
366:
367: return(KERN_SUCCESS);
368: }
369:
370: #else /* MACH_HOST */
371:
372: kern_return_t
373: processor_assign(processor, new_pset, wait)
374: processor_t processor;
375: processor_set_t new_pset;
376: boolean_t wait;
377: {
378: #ifdef lint
379: processor++; new_pset++; wait++;
380: #endif
381: return KERN_FAILURE;
382: }
383:
384: #endif /* MACH_HOST */
385:
386: /*
387: * processor_shutdown() queues a processor up for shutdown.
388: * Any assignment in progress is overriden. It does not synchronize
389: * with the shutdown (can be called from interrupt level).
390: */
391: kern_return_t
392: processor_shutdown(processor)
393: processor_t processor;
394: {
395: spl_t s;
396:
397: if (processor == PROCESSOR_NULL)
398: return KERN_INVALID_ARGUMENT;
399:
400: s = splsched();
401: processor_lock(processor);
402: if(processor->state == PROCESSOR_OFF_LINE ||
403: processor->state == PROCESSOR_SHUTDOWN) {
404: /*
405: * Already shutdown or being shutdown -- nothing to do.
406: */
407: processor_unlock(processor);
408: splx(s);
409: return(KERN_SUCCESS);
410: }
411:
412: processor_request_action(processor, PROCESSOR_SET_NULL);
413: processor_unlock(processor);
414: splx(s);
415:
416: return(KERN_SUCCESS);
417: }
418:
419: /*
420: * action_thread() shuts down processors or changes their assignment.
421: */
422: void processor_doaction(); /* forward */
423:
424: void action_thread_continue()
425: {
426: register processor_t processor;
427: register spl_t s;
428:
429: while (TRUE) {
430: s = splsched();
431: simple_lock(&action_lock);
432: while ( !queue_empty(&action_queue)) {
433: processor = (processor_t) queue_first(&action_queue);
434: queue_remove(&action_queue, processor, processor_t,
435: processor_queue);
436: simple_unlock(&action_lock);
437: (void) splx(s);
438:
439: processor_doaction(processor);
440:
441: s = splsched();
442: simple_lock(&action_lock);
443: }
444:
445: assert_wait((event_t) &action_queue, FALSE);
446: simple_unlock(&action_lock);
447: (void) splx(s);
448: counter(c_action_thread_block++);
449: thread_block_continue(action_thread_continue);
450: }
451: }
452:
453: void action_thread()
454: {
455: action_thread_continue();
456: /*NOTREACHED*/
457: }
458:
459: /*
460: * processor_doaction actually does the shutdown. The trick here
461: * is to schedule ourselves onto a cpu and then save our
462: * context back into the runqs before taking out the cpu.
463: */
464: #ifdef __GNUC__
465: __volatile__
466: #endif
467: void processor_doshutdown(); /* forward */
468:
469: void processor_doaction(processor)
470: register processor_t processor;
471: {
472: thread_t this_thread;
473: spl_t s;
474: register processor_set_t pset;
475: #if MACH_HOST
476: register processor_set_t new_pset;
477: register thread_t thread;
478: register thread_t prev_thread = THREAD_NULL;
479: boolean_t have_pset_ref = FALSE;
480: #endif /* MACH_HOST */
481:
482: /*
483: * Get onto the processor to shutdown
484: */
485: this_thread = current_thread();
486: thread_bind(this_thread, processor);
487: thread_block_continue((void (*)()) 0);
488:
489: pset = processor->processor_set;
490: #if MACH_HOST
491: /*
492: * If this is the last processor in the processor_set,
493: * stop all the threads first.
494: */
495: pset_lock(pset);
496: if (pset->processor_count == 1) {
497: /*
498: * First suspend all of them.
499: */
500: queue_iterate(&pset->threads, thread, thread_t, pset_threads) {
501: thread_hold(thread);
502: }
503: pset->empty = TRUE;
504: /*
505: * Now actually stop them. Need a pset reference.
506: */
507: pset->ref_count++;
508: have_pset_ref = TRUE;
509:
510: Restart_thread:
511: prev_thread = THREAD_NULL;
512: queue_iterate(&pset->threads, thread, thread_t, pset_threads) {
513: thread_reference(thread);
514: pset_unlock(pset);
515: if (prev_thread != THREAD_NULL)
516: thread_deallocate(prev_thread);
517:
518: /*
519: * Only wait for threads still in the pset.
520: */
521: thread_freeze(thread);
522: if (thread->processor_set != pset) {
523: /*
524: * It got away - start over.
525: */
526: thread_unfreeze(thread);
527: thread_deallocate(thread);
528: pset_lock(pset);
529: goto Restart_thread;
530: }
531:
532: (void) thread_dowait(thread, TRUE);
533: prev_thread = thread;
534: pset_lock(pset);
535: thread_unfreeze(prev_thread);
536: }
537: }
538: pset_unlock(pset);
539:
540: /*
541: * At this point, it is ok to remove the processor from the pset.
542: * We can use processor->processor_set_next without locking the
543: * processor, since it cannot change while processor->state is
544: * PROCESSOR_ASSIGN or PROCESSOR_SHUTDOWN.
545: */
546:
547: new_pset = processor->processor_set_next;
548:
549: Restart_pset:
550: if (new_pset) {
551: /*
552: * Reassigning processor.
553: */
554:
555: if ((integer_t) pset < (integer_t) new_pset) {
556: pset_lock(pset);
557: pset_lock(new_pset);
558: }
559: else {
560: pset_lock(new_pset);
561: pset_lock(pset);
562: }
563: if (!(new_pset->active)) {
564: pset_unlock(new_pset);
565: pset_unlock(pset);
566: pset_deallocate(new_pset);
567: new_pset = &default_pset;
568: pset_reference(new_pset);
569: goto Restart_pset;
570: }
571:
572: /*
573: * Handle remove last / assign first race.
574: * Only happens if there is more than one action thread.
575: */
576: while (new_pset->empty && new_pset->processor_count > 0) {
577: pset_unlock(new_pset);
578: pset_unlock(pset);
579: while (*(volatile boolean_t *)&new_pset->empty &&
580: *(volatile int *)&new_pset->processor_count > 0)
581: /* spin */;
582: goto Restart_pset;
583: }
584:
585: /*
586: * Lock the processor. new_pset should not have changed.
587: */
588: s = splsched();
589: processor_lock(processor);
590: assert(processor->processor_set_next == new_pset);
591:
592: /*
593: * Shutdown may have been requested while this assignment
594: * was in progress.
595: */
596: if (processor->state == PROCESSOR_SHUTDOWN) {
597: processor->processor_set_next = PROCESSOR_SET_NULL;
598: pset_unlock(new_pset);
599: goto shutdown; /* releases pset reference */
600: }
601:
602: /*
603: * Do assignment, then wakeup anyone waiting for it.
604: */
605: pset_remove_processor(pset, processor);
606: pset_unlock(pset);
607:
608: pset_add_processor(new_pset, processor);
609: if (new_pset->empty) {
610: /*
611: * Set all the threads loose.
612: *
613: * NOTE: this appears to violate the locking
614: * order, since the processor lock should
615: * be taken AFTER a thread lock. However,
616: * thread_setrun (called by thread_release)
617: * only takes the processor lock if the
618: * processor is idle. The processor is
619: * not idle here.
620: */
621: queue_iterate(&new_pset->threads, thread, thread_t,
622: pset_threads) {
623: thread_release(thread);
624: }
625: new_pset->empty = FALSE;
626: }
627: processor->processor_set_next = PROCESSOR_SET_NULL;
628: processor->state = PROCESSOR_RUNNING;
629: thread_wakeup((event_t)processor);
630: processor_unlock(processor);
631: splx(s);
632: pset_unlock(new_pset);
633:
634: /*
635: * Clean up dangling references, and release our binding.
636: */
637: pset_deallocate(new_pset);
638: if (have_pset_ref)
639: pset_deallocate(pset);
640: if (prev_thread != THREAD_NULL)
641: thread_deallocate(prev_thread);
642: thread_bind(this_thread, PROCESSOR_NULL);
643:
644: thread_block_continue((void (*)()) 0);
645: return;
646: }
647:
648: #endif /* MACH_HOST */
649:
650: /*
651: * Do shutdown, make sure we live when processor dies.
652: */
653: if (processor->state != PROCESSOR_SHUTDOWN) {
654: printf("state: %d\n", processor->state);
655: panic("action_thread -- bad processor state");
656: }
657:
658: s = splsched();
659: processor_lock(processor);
660:
661: shutdown:
662: pset_remove_processor(pset, processor);
663: processor_unlock(processor);
664: pset_unlock(pset);
665: splx(s);
666:
667: /*
668: * Clean up dangling references, and release our binding.
669: */
670: #if MACH_HOST
671: if (new_pset != PROCESSOR_SET_NULL)
672: pset_deallocate(new_pset);
673: if (have_pset_ref)
674: pset_deallocate(pset);
675: if (prev_thread != THREAD_NULL)
676: thread_deallocate(prev_thread);
677: #endif /* MACH_HOST */
678:
679: thread_bind(this_thread, PROCESSOR_NULL);
680: switch_to_shutdown_context(this_thread,
681: processor_doshutdown,
682: processor);
683:
684: }
685:
686: /*
687: * Actually do the processor shutdown. This is called at splsched,
688: * running on the processor's shutdown stack.
689: */
690:
691: #ifdef __GNUC__
692: extern __volatile__ void halt_cpu();
693: #endif
694:
695: #ifdef __GNUC__
696: __volatile__
697: #endif
698: void processor_doshutdown(processor)
699: register processor_t processor;
700: {
701: register int cpu = processor->slot_num;
702:
703: timer_switch(&kernel_timer[cpu]);
704:
705: /*
706: * Ok, now exit this cpu.
707: */
708: PMAP_DEACTIVATE_KERNEL(cpu);
709: active_threads[cpu] = THREAD_NULL;
710: cpu_down(cpu);
711: thread_wakeup((event_t)processor);
712: halt_cpu();
713: /*
714: * The action thread returns to life after the call to
715: * switch_to_shutdown_context above, on some other cpu.
716: */
717:
718: /*NOTREACHED*/
719: }
720: #else /* NCPUS > 1 */
721:
722: kern_return_t
723: processor_assign(processor, new_pset, wait)
724: processor_t processor;
725: processor_set_t new_pset;
726: boolean_t wait;
727: {
728: #ifdef lint
729: processor++; new_pset++; wait++;
730: #endif lint
731: return(KERN_FAILURE);
732: }
733:
734: #endif /* NCPUS > 1 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.