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 struct machine_slot
*ms
;
126 * Just twiddle our thumbs; we've got nothing better to do
129 while (!simple_lock_try(&default_pset
.processors_lock
))
133 processor_lock(processor
);
134 init_ast_check(processor
);
135 ms
= &machine_slot
[cpu
];
137 machine_info
.avail_cpus
++;
138 pset_add_processor(&default_pset
, processor
);
139 processor
->state
= PROCESSOR_RUNNING
;
140 processor_unlock(processor
);
143 simple_unlock(&default_pset
.processors_lock
);
149 * Flag specified cpu as down. Called when a processor is about to
156 processor_t processor
;
157 struct machine_slot
*ms
;
160 processor
= cpu_to_processor(cpu
);
163 processor_lock(processor
);
164 ms
= &machine_slot
[cpu
];
166 machine_info
.avail_cpus
--;
168 * processor has already been removed from pset.
170 processor
->processor_set_next
= PROCESSOR_SET_NULL
;
171 processor
->state
= PROCESSOR_OFF_LINE
;
172 processor_unlock(processor
);
178 host_priv_t host_priv
,
181 if (host_priv
== HOST_PRIV_NULL
)
182 return (KERN_INVALID_HOST
);
184 assert(host_priv
== &realhost
);
186 if (options
& HOST_REBOOT_DEBUGGER
) {
187 Debugger("Debugger");
190 halt_all_cpus(!(options
& HOST_REBOOT_HALT
));
192 return (KERN_SUCCESS
);
196 * processor_request_action:
198 * Common internals of processor_assign and processor_shutdown.
199 * If new_pset is null, this is a shutdown, else it's an assign
200 * and caller must donate a reference.
201 * For assign operations, it returns an old pset that must be deallocated
203 * For shutdown operations, it always returns PROCESSOR_SET_NULL.
206 processor_request_action(
207 processor_t processor
,
208 processor_set_t new_pset
)
210 processor_set_t pset
, old_next_pset
;
213 * Processor must be in a processor set. Must lock its idle lock to
214 * get at processor state.
216 pset
= processor
->processor_set
;
217 simple_lock(&pset
->idle_lock
);
220 * If the processor is dispatching, let it finish - it will set its
221 * state to running very soon.
223 while (*(volatile int *)&processor
->state
== PROCESSOR_DISPATCHING
) {
224 simple_unlock(&pset
->idle_lock
);
225 simple_lock(&pset
->idle_lock
);
229 * Now lock the action queue and do the dirty work.
231 simple_lock(&processor_action_lock
);
233 switch (processor
->state
) {
237 * Remove from idle queue.
239 queue_remove(&pset
->idle_queue
, processor
,
240 processor_t
, processor_queue
);
243 /* fall through ... */
244 case PROCESSOR_RUNNING
:
246 * Put it on the action queue.
248 queue_enter(&processor_action_queue
, processor
,
249 processor_t
,processor_queue
);
251 /* Fall through ... */
252 case PROCESSOR_ASSIGN
:
254 * And ask the action_thread to do the work.
257 if (new_pset
== PROCESSOR_SET_NULL
) {
258 processor
->state
= PROCESSOR_SHUTDOWN
;
259 old_next_pset
= PROCESSOR_SET_NULL
;
261 processor
->state
= PROCESSOR_ASSIGN
;
262 old_next_pset
= processor
->processor_set_next
;
263 processor
->processor_set_next
= new_pset
;
268 printf("state: %d\n", processor
->state
);
269 panic("processor_request_action: bad state");
272 if (processor_action_active
== FALSE
) {
273 processor_action_active
= TRUE
;
274 simple_unlock(&processor_action_lock
);
275 simple_unlock(&pset
->idle_lock
);
276 processor_unlock(processor
);
277 thread_call_enter(processor_action_call
);
278 processor_lock(processor
);
280 simple_unlock(&processor_action_lock
);
281 simple_unlock(&pset
->idle_lock
);
284 return (old_next_pset
);
289 processor_t processor
,
290 processor_set_t new_pset
,
294 processor
++; new_pset
++; wait
++;
296 return (KERN_FAILURE
);
300 * processor_shutdown() queues a processor up for shutdown.
301 * Any assignment in progress is overriden.
305 processor_t processor
)
310 processor_lock(processor
);
311 if ((processor
->state
== PROCESSOR_OFF_LINE
) ||
312 (processor
->state
== PROCESSOR_SHUTDOWN
)) {
314 * Already shutdown or being shutdown -- nothing to do.
316 processor_unlock(processor
);
319 return (KERN_SUCCESS
);
322 (void) processor_request_action(processor
, PROCESSOR_SET_NULL
);
324 assert_wait((event_t
)processor
, THREAD_UNINT
);
326 processor_unlock(processor
);
329 thread_block((void (*)(void)) 0);
331 return (KERN_SUCCESS
);
335 * processor_action() shuts down processors or changes their assignment.
339 thread_call_param_t p0
,
340 thread_call_param_t p1
)
342 register processor_t processor
;
346 simple_lock(&processor_action_lock
);
348 while (!queue_empty(&processor_action_queue
)) {
349 processor
= (processor_t
) queue_first(&processor_action_queue
);
350 queue_remove(&processor_action_queue
, processor
,
351 processor_t
, processor_queue
);
352 simple_unlock(&processor_action_lock
);
355 processor_doaction(processor
);
358 simple_lock(&processor_action_lock
);
361 processor_action_active
= FALSE
;
362 simple_unlock(&processor_action_lock
);
367 processor_action(void)
369 queue_init(&processor_action_queue
);
370 simple_lock_init(&processor_action_lock
, ETAP_THREAD_ACTION
);
371 processor_action_active
= FALSE
;
373 thread_call_setup(&processor_action_call_data
, _processor_action
, NULL
);
374 processor_action_call
= &processor_action_call_data
;
378 * processor_doaction actually does the shutdown. The trick here
379 * is to schedule ourselves onto a cpu and then save our
380 * context back into the runqs before taking out the cpu.
384 processor_t processor
)
386 thread_t self
= current_thread();
387 processor_set_t pset
;
392 * Get onto the processor to shutdown
394 thread_bind(self
, processor
);
395 thread_block((void (*)(void)) 0);
397 pset
= processor
->processor_set
;
398 simple_lock(&pset
->processors_lock
);
400 if (pset
->processor_count
== 1) {
402 extern void start_cpu_thread(void);
404 simple_unlock(&pset
->processors_lock
);
407 * Create the thread, and point it at the routine.
409 thread
= kernel_thread_with_priority(
410 kernel_task
, MAXPRI_KERNEL
,
411 start_cpu_thread
, TRUE
, FALSE
);
413 disable_preemption();
417 thread
->state
|= TH_RUN
;
418 _mk_sp_thread_unblock(thread
);
419 (void)rem_runq(thread
);
420 machine_wake_thread
= thread
;
421 thread_unlock(thread
);
424 simple_lock(&pset
->processors_lock
);
429 processor_lock(processor
);
432 * Do shutdown, make sure we live when processor dies.
434 if (processor
->state
!= PROCESSOR_SHUTDOWN
) {
435 panic("action_thread -- bad processor state");
438 pset_remove_processor(pset
, processor
);
439 processor_unlock(processor
);
440 simple_unlock(&pset
->processors_lock
);
445 thread_bind(self
, PROCESSOR_NULL
);
446 self
->continuation
= 0;
447 old_thread
= switch_to_shutdown_context(self
,
448 processor_doshutdown
, processor
);
449 thread_dispatch(old_thread
);
450 thread_wakeup((event_t
)processor
);
455 * Actually do the processor shutdown. This is called at splsched,
456 * running on the processor's shutdown stack.
460 processor_doshutdown(
461 processor_t processor
)
463 register int cpu
= processor
->slot_num
;
465 timer_call_cancel(&processor
->quantum_timer
);
466 thread_dispatch(current_thread());
467 timer_switch(&kernel_timer
[cpu
]);
470 * OK, now exit this cpu.
472 PMAP_DEACTIVATE_KERNEL(cpu
);
473 cpu_data
[cpu
].active_thread
= THREAD_NULL
;
474 active_kloaded
[cpu
] = THR_ACT_NULL
;
477 panic("zombie processor");
483 host_priv_t host_priv
,
484 kernel_boot_info_t boot_info
)
487 extern char *machine_boot_info(
488 kernel_boot_info_t boot_info
,
491 if (host_priv
== HOST_PRIV_NULL
)
492 return (KERN_INVALID_HOST
);
494 assert(host_priv
== &realhost
);
497 * Copy first operator string terminated by '\0' followed by
498 * standardized strings generated from boot string.
500 src
= machine_boot_info(boot_info
, KERNEL_BOOT_INFO_MAX
);
501 if (src
!= boot_info
)
502 (void) strncpy(boot_info
, src
, KERNEL_BOOT_INFO_MAX
);
504 return (KERN_SUCCESS
);