2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 * File: kern/machine.c
54 * Author: Avadis Tevanian, Jr.
57 * Support for machine independent machine abstraction.
63 #include <mach/boolean.h>
64 #include <mach/kern_return.h>
65 #include <mach/mach_types.h>
66 #include <mach/machine.h>
67 #include <mach/host_info.h>
68 #include <mach/host_reboot.h>
69 #include <kern/counters.h>
70 #include <kern/cpu_data.h>
71 #include <kern/ipc_host.h>
72 #include <kern/host.h>
73 #include <kern/lock.h>
74 #include <kern/machine.h>
75 #include <kern/processor.h>
76 #include <kern/queue.h>
77 #include <kern/sched.h>
78 #include <kern/task.h>
79 #include <kern/thread.h>
80 #include <kern/thread_swap.h>
81 #include <kern/misc_protos.h>
83 #include <kern/mk_sp.h>
89 struct machine_info machine_info
;
90 struct machine_slot machine_slot
[NCPUS
];
92 static queue_head_t processor_action_queue
;
93 static boolean_t processor_action_active
;
94 static thread_call_t processor_action_call
;
95 static thread_call_data_t processor_action_call_data
;
96 decl_simple_lock_data(static,processor_action_lock
)
98 thread_t machine_wake_thread
;
101 processor_set_t
processor_request_action(
102 processor_t processor
,
103 processor_set_t new_pset
);
105 void processor_doaction(
106 processor_t processor
);
108 void processor_doshutdown(
109 processor_t processor
);
114 * Flag specified cpu as up and running. Called when a processor comes
121 processor_t processor
= cpu_to_processor(cpu
);
122 processor_set_t pset
= &default_pset
;
123 struct machine_slot
*ms
;
127 * Just twiddle our thumbs; we've got nothing better to do
130 while (!simple_lock_try(&pset
->processors_lock
))
134 processor_lock(processor
);
135 init_ast_check(processor
);
136 ms
= &machine_slot
[cpu
];
138 machine_info
.avail_cpus
++;
139 pset_add_processor(pset
, processor
);
140 simple_lock(&pset
->sched_lock
);
141 enqueue_tail(&pset
->active_queue
, (queue_entry_t
)processor
);
142 processor
->state
= PROCESSOR_RUNNING
;
143 simple_unlock(&pset
->sched_lock
);
144 processor_unlock(processor
);
147 simple_unlock(&pset
->processors_lock
);
153 * Flag specified cpu as down. Called when a processor is about to
160 processor_t processor
;
161 struct machine_slot
*ms
;
164 processor
= cpu_to_processor(cpu
);
167 processor_lock(processor
);
168 ms
= &machine_slot
[cpu
];
170 machine_info
.avail_cpus
--;
172 * processor has already been removed from pset.
174 processor
->processor_set_next
= PROCESSOR_SET_NULL
;
175 processor
->state
= PROCESSOR_OFF_LINE
;
176 processor_unlock(processor
);
182 host_priv_t host_priv
,
185 if (host_priv
== HOST_PRIV_NULL
)
186 return (KERN_INVALID_HOST
);
188 assert(host_priv
== &realhost
);
190 if (options
& HOST_REBOOT_DEBUGGER
) {
191 Debugger("Debugger");
194 halt_all_cpus(!(options
& HOST_REBOOT_HALT
));
196 return (KERN_SUCCESS
);
200 * processor_request_action:
202 * Common internals of processor_assign and processor_shutdown.
203 * If new_pset is null, this is a shutdown, else it's an assign
204 * and caller must donate a reference.
205 * For assign operations, it returns an old pset that must be deallocated
207 * For shutdown operations, it always returns PROCESSOR_SET_NULL.
210 processor_request_action(
211 processor_t processor
,
212 processor_set_t new_pset
)
214 processor_set_t pset
, old_pset
;
217 * Processor must be in a processor set. Must lock its idle lock to
218 * get at processor state.
220 pset
= processor
->processor_set
;
221 simple_lock(&pset
->sched_lock
);
224 * If the processor is dispatching, let it finish - it will set its
225 * state to running very soon.
227 while (*(volatile int *)&processor
->state
== PROCESSOR_DISPATCHING
) {
228 simple_unlock(&pset
->sched_lock
);
230 simple_lock(&pset
->sched_lock
);
233 assert( processor
->state
== PROCESSOR_IDLE
||
234 processor
->state
== PROCESSOR_RUNNING
||
235 processor
->state
== PROCESSOR_ASSIGN
);
238 * Now lock the action queue and do the dirty work.
240 simple_lock(&processor_action_lock
);
242 if (processor
->state
== PROCESSOR_IDLE
) {
243 remqueue(&pset
->idle_queue
, (queue_entry_t
)processor
);
247 if (processor
->state
== PROCESSOR_RUNNING
)
248 remqueue(&pset
->active_queue
, (queue_entry_t
)processor
);
250 if (processor
->state
!= PROCESSOR_ASSIGN
)
251 enqueue_tail(&processor_action_queue
, (queue_entry_t
)processor
);
254 * And ask the action_thread to do the work.
256 if (new_pset
!= PROCESSOR_SET_NULL
) {
257 processor
->state
= PROCESSOR_ASSIGN
;
258 old_pset
= processor
->processor_set_next
;
259 processor
->processor_set_next
= new_pset
;
262 processor
->state
= PROCESSOR_SHUTDOWN
;
263 old_pset
= PROCESSOR_SET_NULL
;
266 simple_unlock(&pset
->sched_lock
);
268 if (processor_action_active
) {
269 simple_unlock(&processor_action_lock
);
274 processor_action_active
= TRUE
;
275 simple_unlock(&processor_action_lock
);
277 processor_unlock(processor
);
279 thread_call_enter(processor_action_call
);
280 processor_lock(processor
);
287 processor_t processor
,
288 processor_set_t new_pset
,
292 processor
++; new_pset
++; wait
++;
294 return (KERN_FAILURE
);
298 * processor_shutdown() queues a processor up for shutdown.
299 * Any assignment in progress is overriden.
303 processor_t processor
)
308 processor_lock(processor
);
309 if ( processor
->state
== PROCESSOR_OFF_LINE
||
310 processor
->state
== PROCESSOR_SHUTDOWN
) {
312 * Already shutdown or being shutdown -- nothing to do.
314 processor_unlock(processor
);
317 return (KERN_SUCCESS
);
320 processor_request_action(processor
, PROCESSOR_SET_NULL
);
322 assert_wait((event_t
)processor
, THREAD_UNINT
);
324 processor_unlock(processor
);
327 thread_block(THREAD_CONTINUE_NULL
);
329 return (KERN_SUCCESS
);
333 * processor_action() shuts down processors or changes their assignment.
337 thread_call_param_t p0
,
338 thread_call_param_t p1
)
340 register processor_t processor
;
344 simple_lock(&processor_action_lock
);
346 while (!queue_empty(&processor_action_queue
)) {
347 processor
= (processor_t
)dequeue_head(&processor_action_queue
);
348 simple_unlock(&processor_action_lock
);
351 processor_doaction(processor
);
354 simple_lock(&processor_action_lock
);
357 processor_action_active
= FALSE
;
358 simple_unlock(&processor_action_lock
);
363 processor_action(void)
365 queue_init(&processor_action_queue
);
366 simple_lock_init(&processor_action_lock
, ETAP_THREAD_ACTION
);
367 processor_action_active
= FALSE
;
369 thread_call_setup(&processor_action_call_data
, _processor_action
, NULL
);
370 processor_action_call
= &processor_action_call_data
;
374 * processor_doaction actually does the shutdown. The trick here
375 * is to schedule ourselves onto a cpu and then save our
376 * context back into the runqs before taking out the cpu.
380 processor_t processor
)
382 thread_t self
= current_thread();
383 processor_set_t pset
;
388 * Get onto the processor to shutdown
390 thread_bind(self
, processor
);
391 thread_block(THREAD_CONTINUE_NULL
);
393 pset
= processor
->processor_set
;
394 simple_lock(&pset
->processors_lock
);
396 if (pset
->processor_count
== 1) {
398 extern void start_cpu_thread(void);
400 simple_unlock(&pset
->processors_lock
);
403 * Create the thread, and point it at the routine.
405 thread
= kernel_thread_with_priority(
406 kernel_task
, MAXPRI_KERNEL
,
407 start_cpu_thread
, TRUE
, FALSE
);
409 disable_preemption();
413 machine_wake_thread
= thread
;
414 thread_go_locked(thread
, THREAD_AWAKENED
);
415 (void)rem_runq(thread
);
416 thread_unlock(thread
);
419 simple_lock(&pset
->processors_lock
);
424 processor_lock(processor
);
427 * Do shutdown, make sure we live when processor dies.
429 if (processor
->state
!= PROCESSOR_SHUTDOWN
) {
430 panic("action_thread -- bad processor state");
433 pset_remove_processor(pset
, processor
);
434 processor_unlock(processor
);
435 simple_unlock(&pset
->processors_lock
);
440 thread_bind(self
, PROCESSOR_NULL
);
441 self
->continuation
= 0;
442 old_thread
= switch_to_shutdown_context(self
,
443 processor_doshutdown
, processor
);
444 if (processor
!= current_processor())
445 timer_call_shutdown(processor
);
446 thread_dispatch(old_thread
);
447 thread_wakeup((event_t
)processor
);
452 * Actually do the processor shutdown. This is called at splsched,
453 * running on the processor's shutdown stack.
457 processor_doshutdown(
458 processor_t processor
)
460 register int cpu
= processor
->slot_num
;
462 timer_call_cancel(&processor
->quantum_timer
);
463 thread_dispatch(current_thread());
464 timer_switch(&kernel_timer
[cpu
]);
467 * OK, now exit this cpu.
469 PMAP_DEACTIVATE_KERNEL(cpu
);
470 thread_machine_set_current(processor
->idle_thread
);
473 panic("zombie processor");
479 host_priv_t host_priv
,
480 kernel_boot_info_t boot_info
)
483 extern char *machine_boot_info(
484 kernel_boot_info_t boot_info
,
487 if (host_priv
== HOST_PRIV_NULL
)
488 return (KERN_INVALID_HOST
);
490 assert(host_priv
== &realhost
);
493 * Copy first operator string terminated by '\0' followed by
494 * standardized strings generated from boot string.
496 src
= machine_boot_info(boot_info
, KERNEL_BOOT_INFO_MAX
);
497 if (src
!= boot_info
)
498 (void) strncpy(boot_info
, src
, KERNEL_BOOT_INFO_MAX
);
500 return (KERN_SUCCESS
);