]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/machine.c
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / kern / machine.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37
A
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_COPYRIGHT@
27 */
28/*
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53/*
54 */
55/*
56 * File: kern/machine.c
57 * Author: Avadis Tevanian, Jr.
58 * Date: 1987
59 *
60 * Support for machine independent machine abstraction.
61 */
62
63#include <cpus.h>
64
65#include <string.h>
66#include <mach/boolean.h>
67#include <mach/kern_return.h>
68#include <mach/mach_types.h>
69#include <mach/machine.h>
70#include <mach/host_info.h>
71#include <mach/host_reboot.h>
72#include <kern/counters.h>
73#include <kern/cpu_data.h>
74#include <kern/ipc_host.h>
75#include <kern/host.h>
76#include <kern/lock.h>
77#include <kern/machine.h>
78#include <kern/processor.h>
79#include <kern/queue.h>
80#include <kern/sched.h>
81#include <kern/task.h>
82#include <kern/thread.h>
83#include <kern/thread_swap.h>
84#include <kern/misc_protos.h>
85
0b4e3aa0 86#include <kern/mk_sp.h>
1c79356b
A
87
88/*
89 * Exported variables:
90 */
91
92struct machine_info machine_info;
93struct machine_slot machine_slot[NCPUS];
94
95static queue_head_t processor_action_queue;
96static boolean_t processor_action_active;
97static thread_call_t processor_action_call;
98static thread_call_data_t processor_action_call_data;
99decl_simple_lock_data(static,processor_action_lock)
100
101thread_t machine_wake_thread;
102
103/* Forwards */
104processor_set_t processor_request_action(
105 processor_t processor,
106 processor_set_t new_pset);
107
108void processor_doaction(
109 processor_t processor);
110
111void processor_doshutdown(
112 processor_t processor);
113
114/*
115 * cpu_up:
116 *
117 * Flag specified cpu as up and running. Called when a processor comes
118 * online.
119 */
120void
121cpu_up(
122 int cpu)
123{
124 processor_t processor = cpu_to_processor(cpu);
9bccf70c 125 processor_set_t pset = &default_pset;
1c79356b
A
126 struct machine_slot *ms;
127 spl_t s;
128
129 /*
130 * Just twiddle our thumbs; we've got nothing better to do
131 * yet, anyway.
132 */
9bccf70c 133 while (!simple_lock_try(&pset->processors_lock))
1c79356b
A
134 continue;
135
136 s = splsched();
137 processor_lock(processor);
138 init_ast_check(processor);
139 ms = &machine_slot[cpu];
140 ms->running = TRUE;
141 machine_info.avail_cpus++;
9bccf70c
A
142 pset_add_processor(pset, processor);
143 simple_lock(&pset->sched_lock);
144 enqueue_tail(&pset->active_queue, (queue_entry_t)processor);
1c79356b 145 processor->state = PROCESSOR_RUNNING;
9bccf70c 146 simple_unlock(&pset->sched_lock);
1c79356b
A
147 processor_unlock(processor);
148 splx(s);
149
9bccf70c 150 simple_unlock(&pset->processors_lock);
1c79356b
A
151}
152
153/*
154 * cpu_down:
155 *
156 * Flag specified cpu as down. Called when a processor is about to
157 * go offline.
158 */
159void
160cpu_down(
161 int cpu)
162{
163 processor_t processor;
164 struct machine_slot *ms;
165 spl_t s;
166
167 processor = cpu_to_processor(cpu);
168
169 s = splsched();
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
183kern_return_t
184host_reboot(
185 host_priv_t host_priv,
186 int options)
187{
188 if (host_priv == HOST_PRIV_NULL)
189 return (KERN_INVALID_HOST);
190
191 assert(host_priv == &realhost);
192
193 if (options & HOST_REBOOT_DEBUGGER) {
194 Debugger("Debugger");
195 }
196 else
197 halt_all_cpus(!(options & HOST_REBOOT_HALT));
198
199 return (KERN_SUCCESS);
200}
201
202/*
203 * processor_request_action:
204 *
205 * Common internals of processor_assign and processor_shutdown.
206 * If new_pset is null, this is a shutdown, else it's an assign
207 * and caller must donate a reference.
208 * For assign operations, it returns an old pset that must be deallocated
209 * if it's not NULL.
210 * For shutdown operations, it always returns PROCESSOR_SET_NULL.
211 */
212processor_set_t
213processor_request_action(
214 processor_t processor,
215 processor_set_t new_pset)
216{
9bccf70c 217 processor_set_t pset, old_pset;
1c79356b
A
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;
9bccf70c 224 simple_lock(&pset->sched_lock);
1c79356b
A
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) {
9bccf70c
A
231 simple_unlock(&pset->sched_lock);
232
233 simple_lock(&pset->sched_lock);
1c79356b
A
234 }
235
9bccf70c
A
236 assert( processor->state == PROCESSOR_IDLE ||
237 processor->state == PROCESSOR_RUNNING ||
238 processor->state == PROCESSOR_ASSIGN );
239
1c79356b
A
240 /*
241 * Now lock the action queue and do the dirty work.
242 */
243 simple_lock(&processor_action_lock);
244
9bccf70c
A
245 if (processor->state == PROCESSOR_IDLE) {
246 remqueue(&pset->idle_queue, (queue_entry_t)processor);
1c79356b 247 pset->idle_count--;
9bccf70c
A
248 }
249 else
250 if (processor->state == PROCESSOR_RUNNING)
251 remqueue(&pset->active_queue, (queue_entry_t)processor);
1c79356b 252
9bccf70c
A
253 if (processor->state != PROCESSOR_ASSIGN)
254 enqueue_tail(&processor_action_queue, (queue_entry_t)processor);
1c79356b 255
9bccf70c
A
256 /*
257 * And ask the action_thread to do the work.
258 */
259 if (new_pset != PROCESSOR_SET_NULL) {
260 processor->state = PROCESSOR_ASSIGN;
261 old_pset = processor->processor_set_next;
262 processor->processor_set_next = new_pset;
263 }
264 else {
265 processor->state = PROCESSOR_SHUTDOWN;
266 old_pset = PROCESSOR_SET_NULL;
1c79356b
A
267 }
268
9bccf70c
A
269 simple_unlock(&pset->sched_lock);
270
271 if (processor_action_active) {
1c79356b 272 simple_unlock(&processor_action_lock);
9bccf70c
A
273
274 return (old_pset);
1c79356b
A
275 }
276
9bccf70c
A
277 processor_action_active = TRUE;
278 simple_unlock(&processor_action_lock);
279
280 processor_unlock(processor);
281
282 thread_call_enter(processor_action_call);
283 processor_lock(processor);
284
285 return (old_pset);
1c79356b
A
286}
287
288kern_return_t
289processor_assign(
290 processor_t processor,
291 processor_set_t new_pset,
292 boolean_t wait)
293{
294#ifdef lint
295 processor++; new_pset++; wait++;
296#endif /* lint */
297 return (KERN_FAILURE);
298}
299
300/*
301 * processor_shutdown() queues a processor up for shutdown.
302 * Any assignment in progress is overriden.
303 */
304kern_return_t
305processor_shutdown(
306 processor_t processor)
307{
308 spl_t s;
309
310 s = splsched();
311 processor_lock(processor);
9bccf70c
A
312 if ( processor->state == PROCESSOR_OFF_LINE ||
313 processor->state == PROCESSOR_SHUTDOWN ) {
1c79356b
A
314 /*
315 * Already shutdown or being shutdown -- nothing to do.
316 */
317 processor_unlock(processor);
318 splx(s);
319
320 return (KERN_SUCCESS);
321 }
322
9bccf70c 323 processor_request_action(processor, PROCESSOR_SET_NULL);
1c79356b
A
324
325 assert_wait((event_t)processor, THREAD_UNINT);
326
327 processor_unlock(processor);
328 splx(s);
329
9bccf70c 330 thread_block(THREAD_CONTINUE_NULL);
1c79356b
A
331
332 return (KERN_SUCCESS);
333}
334
335/*
336 * processor_action() shuts down processors or changes their assignment.
337 */
338static void
339_processor_action(
340 thread_call_param_t p0,
341 thread_call_param_t p1)
342{
343 register processor_t processor;
344 spl_t s;
345
346 s = splsched();
347 simple_lock(&processor_action_lock);
348
349 while (!queue_empty(&processor_action_queue)) {
9bccf70c 350 processor = (processor_t)dequeue_head(&processor_action_queue);
1c79356b
A
351 simple_unlock(&processor_action_lock);
352 splx(s);
353
354 processor_doaction(processor);
355
356 s = splsched();
357 simple_lock(&processor_action_lock);
358 }
359
360 processor_action_active = FALSE;
361 simple_unlock(&processor_action_lock);
362 splx(s);
363}
364
365void
366processor_action(void)
367{
368 queue_init(&processor_action_queue);
369 simple_lock_init(&processor_action_lock, ETAP_THREAD_ACTION);
370 processor_action_active = FALSE;
371
372 thread_call_setup(&processor_action_call_data, _processor_action, NULL);
373 processor_action_call = &processor_action_call_data;
374}
375
376/*
377 * processor_doaction actually does the shutdown. The trick here
378 * is to schedule ourselves onto a cpu and then save our
379 * context back into the runqs before taking out the cpu.
380 */
381void
382processor_doaction(
383 processor_t processor)
384{
385 thread_t self = current_thread();
386 processor_set_t pset;
387 thread_t old_thread;
388 spl_t s;
389
390 /*
391 * Get onto the processor to shutdown
392 */
393 thread_bind(self, processor);
9bccf70c 394 thread_block(THREAD_CONTINUE_NULL);
1c79356b
A
395
396 pset = processor->processor_set;
397 simple_lock(&pset->processors_lock);
398
399 if (pset->processor_count == 1) {
400 thread_t thread;
1c79356b
A
401 extern void start_cpu_thread(void);
402
403 simple_unlock(&pset->processors_lock);
404
405 /*
406 * Create the thread, and point it at the routine.
407 */
0b4e3aa0
A
408 thread = kernel_thread_with_priority(
409 kernel_task, MAXPRI_KERNEL,
410 start_cpu_thread, TRUE, FALSE);
1c79356b
A
411
412 disable_preemption();
413
414 s = splsched();
415 thread_lock(thread);
1c79356b 416 machine_wake_thread = thread;
9bccf70c
A
417 thread_go_locked(thread, THREAD_AWAKENED);
418 (void)rem_runq(thread);
1c79356b
A
419 thread_unlock(thread);
420 splx(s);
421
422 simple_lock(&pset->processors_lock);
423 enable_preemption();
424 }
425
426 s = splsched();
427 processor_lock(processor);
428
429 /*
430 * Do shutdown, make sure we live when processor dies.
431 */
432 if (processor->state != PROCESSOR_SHUTDOWN) {
433 panic("action_thread -- bad processor state");
434 }
435
436 pset_remove_processor(pset, processor);
437 processor_unlock(processor);
438 simple_unlock(&pset->processors_lock);
439
440 /*
441 * Clean up.
442 */
443 thread_bind(self, PROCESSOR_NULL);
444 self->continuation = 0;
445 old_thread = switch_to_shutdown_context(self,
446 processor_doshutdown, processor);
9bccf70c
A
447 if (processor != current_processor())
448 timer_call_shutdown(processor);
1c79356b
A
449 thread_dispatch(old_thread);
450 thread_wakeup((event_t)processor);
451 splx(s);
452}
453
454/*
455 * Actually do the processor shutdown. This is called at splsched,
456 * running on the processor's shutdown stack.
457 */
458
459void
460processor_doshutdown(
461 processor_t processor)
462{
de355530 463 register int cpu = processor->slot_num;
1c79356b 464
0b4e3aa0 465 timer_call_cancel(&processor->quantum_timer);
de355530 466 thread_dispatch(current_thread());
1c79356b
A
467 timer_switch(&kernel_timer[cpu]);
468
469 /*
470 * OK, now exit this cpu.
471 */
472 PMAP_DEACTIVATE_KERNEL(cpu);
de355530 473 thread_machine_set_current(processor->idle_thread);
1c79356b
A
474 cpu_down(cpu);
475 cpu_sleep();
476 panic("zombie processor");
477 /*NOTREACHED*/
478}
479
480kern_return_t
481host_get_boot_info(
482 host_priv_t host_priv,
483 kernel_boot_info_t boot_info)
484{
485 char *src = "";
486 extern char *machine_boot_info(
487 kernel_boot_info_t boot_info,
488 vm_size_t buf_len);
489
490 if (host_priv == HOST_PRIV_NULL)
491 return (KERN_INVALID_HOST);
492
493 assert(host_priv == &realhost);
494
495 /*
496 * Copy first operator string terminated by '\0' followed by
497 * standardized strings generated from boot string.
498 */
499 src = machine_boot_info(boot_info, KERNEL_BOOT_INFO_MAX);
500 if (src != boot_info)
501 (void) strncpy(boot_info, src, KERNEL_BOOT_INFO_MAX);
502
503 return (KERN_SUCCESS);
504}