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>
84 #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/
90 struct machine_info machine_info
;
91 struct machine_slot machine_slot
[NCPUS
];
93 static queue_head_t processor_action_queue
;
94 static boolean_t processor_action_active
;
95 static thread_call_t processor_action_call
;
96 static thread_call_data_t processor_action_call_data
;
97 decl_simple_lock_data(static,processor_action_lock
)
99 thread_t machine_wake_thread
;
102 processor_set_t
processor_request_action(
103 processor_t processor
,
104 processor_set_t new_pset
);
106 void processor_doaction(
107 processor_t processor
);
109 void processor_doshutdown(
110 processor_t processor
);
115 * Flag specified cpu as up and running. Called when a processor comes
122 processor_t processor
= cpu_to_processor(cpu
);
123 struct machine_slot
*ms
;
127 * Just twiddle our thumbs; we've got nothing better to do
130 while (!simple_lock_try(&default_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(&default_pset
, processor
);
140 processor
->state
= PROCESSOR_RUNNING
;
141 processor_unlock(processor
);
144 simple_unlock(&default_pset
.processors_lock
);
150 * Flag specified cpu as down. Called when a processor is about to
157 processor_t processor
;
158 struct machine_slot
*ms
;
161 processor
= cpu_to_processor(cpu
);
164 processor_lock(processor
);
165 ms
= &machine_slot
[cpu
];
167 machine_info
.avail_cpus
--;
169 * processor has already been removed from pset.
171 processor
->processor_set_next
= PROCESSOR_SET_NULL
;
172 processor
->state
= PROCESSOR_OFF_LINE
;
173 processor_unlock(processor
);
179 host_priv_t host_priv
,
182 if (host_priv
== HOST_PRIV_NULL
)
183 return (KERN_INVALID_HOST
);
185 assert(host_priv
== &realhost
);
187 if (options
& HOST_REBOOT_DEBUGGER
) {
188 Debugger("Debugger");
191 halt_all_cpus(!(options
& HOST_REBOOT_HALT
));
193 return (KERN_SUCCESS
);
197 * processor_request_action:
199 * Common internals of processor_assign and processor_shutdown.
200 * If new_pset is null, this is a shutdown, else it's an assign
201 * and caller must donate a reference.
202 * For assign operations, it returns an old pset that must be deallocated
204 * For shutdown operations, it always returns PROCESSOR_SET_NULL.
207 processor_request_action(
208 processor_t processor
,
209 processor_set_t new_pset
)
211 processor_set_t pset
, old_next_pset
;
214 * Processor must be in a processor set. Must lock its idle lock to
215 * get at processor state.
217 pset
= processor
->processor_set
;
218 simple_lock(&pset
->idle_lock
);
221 * If the processor is dispatching, let it finish - it will set its
222 * state to running very soon.
224 while (*(volatile int *)&processor
->state
== PROCESSOR_DISPATCHING
) {
225 simple_unlock(&pset
->idle_lock
);
226 simple_lock(&pset
->idle_lock
);
230 * Now lock the action queue and do the dirty work.
232 simple_lock(&processor_action_lock
);
234 switch (processor
->state
) {
238 * Remove from idle queue.
240 queue_remove(&pset
->idle_queue
, processor
,
241 processor_t
, processor_queue
);
244 /* fall through ... */
245 case PROCESSOR_RUNNING
:
247 * Put it on the action queue.
249 queue_enter(&processor_action_queue
, processor
,
250 processor_t
,processor_queue
);
252 /* Fall through ... */
253 case PROCESSOR_ASSIGN
:
255 * And ask the action_thread to do the work.
258 if (new_pset
== PROCESSOR_SET_NULL
) {
259 processor
->state
= PROCESSOR_SHUTDOWN
;
260 old_next_pset
= PROCESSOR_SET_NULL
;
262 processor
->state
= PROCESSOR_ASSIGN
;
263 old_next_pset
= processor
->processor_set_next
;
264 processor
->processor_set_next
= new_pset
;
269 printf("state: %d\n", processor
->state
);
270 panic("processor_request_action: bad state");
273 if (processor_action_active
== FALSE
) {
274 processor_action_active
= TRUE
;
275 simple_unlock(&processor_action_lock
);
276 simple_unlock(&pset
->idle_lock
);
277 processor_unlock(processor
);
278 thread_call_enter(processor_action_call
);
279 processor_lock(processor
);
281 simple_unlock(&processor_action_lock
);
282 simple_unlock(&pset
->idle_lock
);
285 return (old_next_pset
);
290 processor_t processor
,
291 processor_set_t new_pset
,
295 processor
++; new_pset
++; wait
++;
297 return (KERN_FAILURE
);
301 * processor_shutdown() queues a processor up for shutdown.
302 * Any assignment in progress is overriden.
306 processor_t processor
)
311 processor_lock(processor
);
312 if ((processor
->state
== PROCESSOR_OFF_LINE
) ||
313 (processor
->state
== PROCESSOR_SHUTDOWN
)) {
315 * Already shutdown or being shutdown -- nothing to do.
317 processor_unlock(processor
);
320 return (KERN_SUCCESS
);
323 (void) processor_request_action(processor
, PROCESSOR_SET_NULL
);
325 assert_wait((event_t
)processor
, THREAD_UNINT
);
327 processor_unlock(processor
);
330 thread_block((void (*)(void)) 0);
332 return (KERN_SUCCESS
);
336 * processor_action() shuts down processors or changes their assignment.
340 thread_call_param_t p0
,
341 thread_call_param_t p1
)
343 register processor_t processor
;
347 simple_lock(&processor_action_lock
);
349 while (!queue_empty(&processor_action_queue
)) {
350 processor
= (processor_t
) queue_first(&processor_action_queue
);
351 queue_remove(&processor_action_queue
, processor
,
352 processor_t
, processor_queue
);
353 simple_unlock(&processor_action_lock
);
356 processor_doaction(processor
);
359 simple_lock(&processor_action_lock
);
362 processor_action_active
= FALSE
;
363 simple_unlock(&processor_action_lock
);
368 processor_action(void)
370 queue_init(&processor_action_queue
);
371 simple_lock_init(&processor_action_lock
, ETAP_THREAD_ACTION
);
372 processor_action_active
= FALSE
;
374 thread_call_setup(&processor_action_call_data
, _processor_action
, NULL
);
375 processor_action_call
= &processor_action_call_data
;
379 * processor_doaction actually does the shutdown. The trick here
380 * is to schedule ourselves onto a cpu and then save our
381 * context back into the runqs before taking out the cpu.
385 processor_t processor
)
387 thread_t self
= current_thread();
388 processor_set_t pset
;
393 * Get onto the processor to shutdown
395 thread_bind(self
, processor
);
396 thread_block((void (*)(void)) 0);
398 pset
= processor
->processor_set
;
399 simple_lock(&pset
->processors_lock
);
401 if (pset
->processor_count
== 1) {
403 sched_policy_t
*policy
;
404 extern void start_cpu_thread(void);
406 simple_unlock(&pset
->processors_lock
);
409 * Create the thread, and point it at the routine.
411 thread
= kernel_thread_with_priority(kernel_task
, MAXPRI_KERNBAND
,
412 start_cpu_thread
, FALSE
);
414 disable_preemption();
418 thread
->state
|= TH_RUN
;
419 policy
= &sched_policy
[thread
->policy
];
420 (void)policy
->sp_ops
.sp_thread_unblock(policy
, thread
);
421 (void)rem_runq(thread
);
422 machine_wake_thread
= thread
;
423 thread_unlock(thread
);
426 simple_lock(&pset
->processors_lock
);
431 processor_lock(processor
);
434 * Do shutdown, make sure we live when processor dies.
436 if (processor
->state
!= PROCESSOR_SHUTDOWN
) {
437 panic("action_thread -- bad processor state");
440 pset_remove_processor(pset
, processor
);
441 processor_unlock(processor
);
442 simple_unlock(&pset
->processors_lock
);
447 thread_bind(self
, PROCESSOR_NULL
);
448 self
->continuation
= 0;
449 old_thread
= switch_to_shutdown_context(self
,
450 processor_doshutdown
, processor
);
451 thread_dispatch(old_thread
);
452 thread_wakeup((event_t
)processor
);
457 * Actually do the processor shutdown. This is called at splsched,
458 * running on the processor's shutdown stack.
462 processor_doshutdown(
463 processor_t processor
)
465 register int cpu
= processor
->slot_num
;
467 thread_dispatch(current_thread());
468 timer_switch(&kernel_timer
[cpu
]);
471 * OK, now exit this cpu.
473 PMAP_DEACTIVATE_KERNEL(cpu
);
474 cpu_data
[cpu
].active_thread
= THREAD_NULL
;
475 active_kloaded
[cpu
] = THR_ACT_NULL
;
478 panic("zombie processor");
484 host_priv_t host_priv
,
485 kernel_boot_info_t boot_info
)
488 extern char *machine_boot_info(
489 kernel_boot_info_t boot_info
,
492 if (host_priv
== HOST_PRIV_NULL
)
493 return (KERN_INVALID_HOST
);
495 assert(host_priv
== &realhost
);
498 * Copy first operator string terminated by '\0' followed by
499 * standardized strings generated from boot string.
501 src
= machine_boot_info(boot_info
, KERNEL_BOOT_INFO_MAX
);
502 if (src
!= boot_info
)
503 (void) strncpy(boot_info
, src
, KERNEL_BOOT_INFO_MAX
);
505 return (KERN_SUCCESS
);