]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/machine.c
xnu-123.5.tar.gz
[apple/xnu.git] / osfmk / kern / machine.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988,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 Software.Distribution@CS.CMU.EDU
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 */
52 /*
53 * File: kern/machine.c
54 * Author: Avadis Tevanian, Jr.
55 * Date: 1987
56 *
57 * Support for machine independent machine abstraction.
58 */
59
60 #include <cpus.h>
61
62 #include <string.h>
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>
82
83 #include <kern/sf.h>
84 #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/
85
86 /*
87 * Exported variables:
88 */
89
90 struct machine_info machine_info;
91 struct machine_slot machine_slot[NCPUS];
92
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)
98
99 thread_t machine_wake_thread;
100
101 /* Forwards */
102 processor_set_t processor_request_action(
103 processor_t processor,
104 processor_set_t new_pset);
105
106 void processor_doaction(
107 processor_t processor);
108
109 void processor_doshutdown(
110 processor_t processor);
111
112 /*
113 * cpu_up:
114 *
115 * Flag specified cpu as up and running. Called when a processor comes
116 * online.
117 */
118 void
119 cpu_up(
120 int cpu)
121 {
122 processor_t processor = cpu_to_processor(cpu);
123 struct machine_slot *ms;
124 spl_t s;
125
126 /*
127 * Just twiddle our thumbs; we've got nothing better to do
128 * yet, anyway.
129 */
130 while (!simple_lock_try(&default_pset.processors_lock))
131 continue;
132
133 s = splsched();
134 processor_lock(processor);
135 init_ast_check(processor);
136 ms = &machine_slot[cpu];
137 ms->running = TRUE;
138 machine_info.avail_cpus++;
139 pset_add_processor(&default_pset, processor);
140 processor->state = PROCESSOR_RUNNING;
141 processor_unlock(processor);
142 splx(s);
143
144 simple_unlock(&default_pset.processors_lock);
145 }
146
147 /*
148 * cpu_down:
149 *
150 * Flag specified cpu as down. Called when a processor is about to
151 * go offline.
152 */
153 void
154 cpu_down(
155 int cpu)
156 {
157 processor_t processor;
158 struct machine_slot *ms;
159 spl_t s;
160
161 processor = cpu_to_processor(cpu);
162
163 s = splsched();
164 processor_lock(processor);
165 ms = &machine_slot[cpu];
166 ms->running = FALSE;
167 machine_info.avail_cpus--;
168 /*
169 * processor has already been removed from pset.
170 */
171 processor->processor_set_next = PROCESSOR_SET_NULL;
172 processor->state = PROCESSOR_OFF_LINE;
173 processor_unlock(processor);
174 splx(s);
175 }
176
177 kern_return_t
178 host_reboot(
179 host_priv_t host_priv,
180 int options)
181 {
182 if (host_priv == HOST_PRIV_NULL)
183 return (KERN_INVALID_HOST);
184
185 assert(host_priv == &realhost);
186
187 if (options & HOST_REBOOT_DEBUGGER) {
188 Debugger("Debugger");
189 }
190 else
191 halt_all_cpus(!(options & HOST_REBOOT_HALT));
192
193 return (KERN_SUCCESS);
194 }
195
196 /*
197 * processor_request_action:
198 *
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
203 * if it's not NULL.
204 * For shutdown operations, it always returns PROCESSOR_SET_NULL.
205 */
206 processor_set_t
207 processor_request_action(
208 processor_t processor,
209 processor_set_t new_pset)
210 {
211 processor_set_t pset, old_next_pset;
212
213 /*
214 * Processor must be in a processor set. Must lock its idle lock to
215 * get at processor state.
216 */
217 pset = processor->processor_set;
218 simple_lock(&pset->idle_lock);
219
220 /*
221 * If the processor is dispatching, let it finish - it will set its
222 * state to running very soon.
223 */
224 while (*(volatile int *)&processor->state == PROCESSOR_DISPATCHING) {
225 simple_unlock(&pset->idle_lock);
226 simple_lock(&pset->idle_lock);
227 }
228
229 /*
230 * Now lock the action queue and do the dirty work.
231 */
232 simple_lock(&processor_action_lock);
233
234 switch (processor->state) {
235
236 case PROCESSOR_IDLE:
237 /*
238 * Remove from idle queue.
239 */
240 queue_remove(&pset->idle_queue, processor,
241 processor_t, processor_queue);
242 pset->idle_count--;
243
244 /* fall through ... */
245 case PROCESSOR_RUNNING:
246 /*
247 * Put it on the action queue.
248 */
249 queue_enter(&processor_action_queue, processor,
250 processor_t,processor_queue);
251
252 /* Fall through ... */
253 case PROCESSOR_ASSIGN:
254 /*
255 * And ask the action_thread to do the work.
256 */
257
258 if (new_pset == PROCESSOR_SET_NULL) {
259 processor->state = PROCESSOR_SHUTDOWN;
260 old_next_pset = PROCESSOR_SET_NULL;
261 } else {
262 processor->state = PROCESSOR_ASSIGN;
263 old_next_pset = processor->processor_set_next;
264 processor->processor_set_next = new_pset;
265 }
266 break;
267
268 default:
269 printf("state: %d\n", processor->state);
270 panic("processor_request_action: bad state");
271 }
272
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);
280 } else {
281 simple_unlock(&processor_action_lock);
282 simple_unlock(&pset->idle_lock);
283 }
284
285 return (old_next_pset);
286 }
287
288 kern_return_t
289 processor_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 */
304 kern_return_t
305 processor_shutdown(
306 processor_t processor)
307 {
308 spl_t s;
309
310 s = splsched();
311 processor_lock(processor);
312 if ((processor->state == PROCESSOR_OFF_LINE) ||
313 (processor->state == PROCESSOR_SHUTDOWN)) {
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
323 (void) processor_request_action(processor, PROCESSOR_SET_NULL);
324
325 assert_wait((event_t)processor, THREAD_UNINT);
326
327 processor_unlock(processor);
328 splx(s);
329
330 thread_block((void (*)(void)) 0);
331
332 return (KERN_SUCCESS);
333 }
334
335 /*
336 * processor_action() shuts down processors or changes their assignment.
337 */
338 static 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)) {
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);
354 splx(s);
355
356 processor_doaction(processor);
357
358 s = splsched();
359 simple_lock(&processor_action_lock);
360 }
361
362 processor_action_active = FALSE;
363 simple_unlock(&processor_action_lock);
364 splx(s);
365 }
366
367 void
368 processor_action(void)
369 {
370 queue_init(&processor_action_queue);
371 simple_lock_init(&processor_action_lock, ETAP_THREAD_ACTION);
372 processor_action_active = FALSE;
373
374 thread_call_setup(&processor_action_call_data, _processor_action, NULL);
375 processor_action_call = &processor_action_call_data;
376 }
377
378 /*
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.
382 */
383 void
384 processor_doaction(
385 processor_t processor)
386 {
387 thread_t self = current_thread();
388 processor_set_t pset;
389 thread_t old_thread;
390 spl_t s;
391
392 /*
393 * Get onto the processor to shutdown
394 */
395 thread_bind(self, processor);
396 thread_block((void (*)(void)) 0);
397
398 pset = processor->processor_set;
399 simple_lock(&pset->processors_lock);
400
401 if (pset->processor_count == 1) {
402 thread_t thread;
403 sched_policy_t *policy;
404 extern void start_cpu_thread(void);
405
406 simple_unlock(&pset->processors_lock);
407
408 /*
409 * Create the thread, and point it at the routine.
410 */
411 thread = kernel_thread_with_priority(kernel_task, MAXPRI_KERNBAND,
412 start_cpu_thread, FALSE);
413
414 disable_preemption();
415
416 s = splsched();
417 thread_lock(thread);
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);
424 splx(s);
425
426 simple_lock(&pset->processors_lock);
427 enable_preemption();
428 }
429
430 s = splsched();
431 processor_lock(processor);
432
433 /*
434 * Do shutdown, make sure we live when processor dies.
435 */
436 if (processor->state != PROCESSOR_SHUTDOWN) {
437 panic("action_thread -- bad processor state");
438 }
439
440 pset_remove_processor(pset, processor);
441 processor_unlock(processor);
442 simple_unlock(&pset->processors_lock);
443
444 /*
445 * Clean up.
446 */
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);
453 splx(s);
454 }
455
456 /*
457 * Actually do the processor shutdown. This is called at splsched,
458 * running on the processor's shutdown stack.
459 */
460
461 void
462 processor_doshutdown(
463 processor_t processor)
464 {
465 register int cpu = processor->slot_num;
466
467 thread_dispatch(current_thread());
468 timer_switch(&kernel_timer[cpu]);
469
470 /*
471 * OK, now exit this cpu.
472 */
473 PMAP_DEACTIVATE_KERNEL(cpu);
474 cpu_data[cpu].active_thread = THREAD_NULL;
475 active_kloaded[cpu] = THR_ACT_NULL;
476 cpu_down(cpu);
477 cpu_sleep();
478 panic("zombie processor");
479 /*NOTREACHED*/
480 }
481
482 kern_return_t
483 host_get_boot_info(
484 host_priv_t host_priv,
485 kernel_boot_info_t boot_info)
486 {
487 char *src = "";
488 extern char *machine_boot_info(
489 kernel_boot_info_t boot_info,
490 vm_size_t buf_len);
491
492 if (host_priv == HOST_PRIV_NULL)
493 return (KERN_INVALID_HOST);
494
495 assert(host_priv == &realhost);
496
497 /*
498 * Copy first operator string terminated by '\0' followed by
499 * standardized strings generated from boot string.
500 */
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);
504
505 return (KERN_SUCCESS);
506 }