]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/machine.c
xnu-517.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 * 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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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
86 #include <kern/mk_sp.h>
87
88 /*
89 * Exported variables:
90 */
91
92 struct machine_info machine_info;
93 struct machine_slot machine_slot[NCPUS];
94
95 thread_t machine_wake_thread;
96
97 /* Forwards */
98 void processor_doshutdown(
99 processor_t processor);
100
101 /*
102 * cpu_up:
103 *
104 * Flag specified cpu as up and running. Called when a processor comes
105 * online.
106 */
107 void
108 cpu_up(
109 int cpu)
110 {
111 processor_t processor = cpu_to_processor(cpu);
112 processor_set_t pset = &default_pset;
113 struct machine_slot *ms;
114 spl_t s;
115
116 s = splsched();
117 processor_lock(processor);
118 init_ast_check(processor);
119 ms = &machine_slot[cpu];
120 ms->running = TRUE;
121 machine_info.avail_cpus++;
122 simple_lock(&pset->sched_lock);
123 pset_add_processor(pset, processor);
124 enqueue_tail(&pset->active_queue, (queue_entry_t)processor);
125 processor->deadline = UINT64_MAX;
126 processor->state = PROCESSOR_RUNNING;
127 simple_unlock(&pset->sched_lock);
128 processor_unlock(processor);
129 splx(s);
130 }
131
132 /*
133 * cpu_down:
134 *
135 * Flag specified cpu as down. Called when a processor is about to
136 * go offline.
137 */
138 void
139 cpu_down(
140 int cpu)
141 {
142 processor_t processor;
143 struct machine_slot *ms;
144 spl_t s;
145
146 processor = cpu_to_processor(cpu);
147
148 s = splsched();
149 processor_lock(processor);
150 ms = &machine_slot[cpu];
151 ms->running = FALSE;
152 machine_info.avail_cpus--;
153 /*
154 * processor has already been removed from pset.
155 */
156 processor->state = PROCESSOR_OFF_LINE;
157 processor_unlock(processor);
158 splx(s);
159 }
160
161 kern_return_t
162 host_reboot(
163 host_priv_t host_priv,
164 int options)
165 {
166 if (host_priv == HOST_PRIV_NULL)
167 return (KERN_INVALID_HOST);
168
169 assert(host_priv == &realhost);
170
171 if (options & HOST_REBOOT_DEBUGGER) {
172 Debugger("Debugger");
173 return (KERN_SUCCESS);
174 }
175
176 halt_all_cpus(!(options & HOST_REBOOT_HALT));
177
178 return (KERN_SUCCESS);
179 }
180
181 kern_return_t
182 processor_assign(
183 processor_t processor,
184 processor_set_t new_pset,
185 boolean_t wait)
186 {
187 #ifdef lint
188 processor++; new_pset++; wait++;
189 #endif /* lint */
190 return (KERN_FAILURE);
191 }
192
193 kern_return_t
194 processor_shutdown(
195 processor_t processor)
196 {
197 processor_set_t pset;
198 spl_t s;
199
200 s = splsched();
201 processor_lock(processor);
202 if ( processor->state == PROCESSOR_OFF_LINE ||
203 processor->state == PROCESSOR_SHUTDOWN ) {
204 /*
205 * Success if already shutdown or being shutdown.
206 */
207 processor_unlock(processor);
208 splx(s);
209
210 return (KERN_SUCCESS);
211 }
212
213 if (processor->state == PROCESSOR_START) {
214 /*
215 * Failure if currently being started.
216 */
217 processor_unlock(processor);
218 splx(s);
219
220 return (KERN_FAILURE);
221 }
222
223 /*
224 * Processor must be in a processor set. Must lock the scheduling
225 * lock to get at the processor state.
226 */
227 pset = processor->processor_set;
228 simple_lock(&pset->sched_lock);
229
230 /*
231 * If the processor is dispatching, let it finish - it will set its
232 * state to running very soon.
233 */
234 while (*(volatile int *)&processor->state == PROCESSOR_DISPATCHING) {
235 simple_unlock(&pset->sched_lock);
236 delay(1);
237 simple_lock(&pset->sched_lock);
238 }
239
240 if (processor->state == PROCESSOR_IDLE) {
241 remqueue(&pset->idle_queue, (queue_entry_t)processor);
242 pset->idle_count--;
243 }
244 else
245 if (processor->state == PROCESSOR_RUNNING)
246 remqueue(&pset->active_queue, (queue_entry_t)processor);
247 else
248 panic("processor_request_action");
249
250 processor->state = PROCESSOR_SHUTDOWN;
251
252 simple_unlock(&pset->sched_lock);
253
254 processor_unlock(processor);
255
256 processor_doshutdown(processor);
257 splx(s);
258
259 return (KERN_SUCCESS);
260 }
261
262 /*
263 * Called at splsched.
264 */
265 void
266 processor_doshutdown(
267 processor_t processor)
268 {
269 thread_t old_thread, self = current_thread();
270 processor_set_t pset;
271 processor_t prev;
272
273 /*
274 * Get onto the processor to shutdown
275 */
276 prev = thread_bind(self, processor);
277 thread_block(THREAD_CONTINUE_NULL);
278
279 processor_lock(processor);
280 pset = processor->processor_set;
281 simple_lock(&pset->sched_lock);
282
283 if (pset->processor_count == 1) {
284 thread_t thread;
285 extern void start_cpu_thread(void);
286
287 simple_unlock(&pset->sched_lock);
288 processor_unlock(processor);
289
290 /*
291 * Create the thread, and point it at the routine.
292 */
293 thread = kernel_thread_create(start_cpu_thread, MAXPRI_KERNEL);
294
295 thread_lock(thread);
296 machine_wake_thread = thread;
297 thread->state = TH_RUN;
298 pset_run_incr(thread->processor_set);
299 thread_unlock(thread);
300
301 processor_lock(processor);
302 simple_lock(&pset->sched_lock);
303 }
304
305 assert(processor->state == PROCESSOR_SHUTDOWN);
306
307 pset_remove_processor(pset, processor);
308 simple_unlock(&pset->sched_lock);
309 processor_unlock(processor);
310
311 /*
312 * Clean up.
313 */
314 thread_bind(self, prev);
315 old_thread = switch_to_shutdown_context(self,
316 processor_offline, processor);
317 if (processor != current_processor())
318 timer_call_shutdown(processor);
319 thread_dispatch(old_thread);
320 }
321
322 /*
323 * Actually do the processor shutdown. This is called at splsched,
324 * running on the processor's shutdown stack.
325 */
326
327 void
328 processor_offline(
329 processor_t processor)
330 {
331 register thread_t old_thread = processor->active_thread;
332 register int cpu = processor->slot_num;
333
334 timer_call_cancel(&processor->quantum_timer);
335 timer_switch(&kernel_timer[cpu]);
336 processor->active_thread = processor->idle_thread;
337 machine_thread_set_current(processor->active_thread);
338 thread_dispatch(old_thread);
339
340 /*
341 * OK, now exit this cpu.
342 */
343 PMAP_DEACTIVATE_KERNEL(cpu);
344 cpu_down(cpu);
345 cpu_sleep();
346 panic("zombie processor");
347 /*NOTREACHED*/
348 }
349
350 kern_return_t
351 host_get_boot_info(
352 host_priv_t host_priv,
353 kernel_boot_info_t boot_info)
354 {
355 char *src = "";
356 extern char *machine_boot_info(
357 kernel_boot_info_t boot_info,
358 vm_size_t buf_len);
359
360 if (host_priv == HOST_PRIV_NULL)
361 return (KERN_INVALID_HOST);
362
363 assert(host_priv == &realhost);
364
365 /*
366 * Copy first operator string terminated by '\0' followed by
367 * standardized strings generated from boot string.
368 */
369 src = machine_boot_info(boot_info, KERNEL_BOOT_INFO_MAX);
370 if (src != boot_info)
371 (void) strncpy(boot_info, src, KERNEL_BOOT_INFO_MAX);
372
373 return (KERN_SUCCESS);
374 }