]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/machine.c
fe6ab43ce1a50dd69fe0ebbe1d173b7b8ecf296d
[apple/xnu.git] / osfmk / kern / machine.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_COPYRIGHT@
32 */
33 /*
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
36 * All Rights Reserved.
37 *
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
43 *
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47 *
48 * Carnegie Mellon requests users of this software to return to
49 *
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
54 *
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
57 */
58 /*
59 */
60 /*
61 * File: kern/machine.c
62 * Author: Avadis Tevanian, Jr.
63 * Date: 1987
64 *
65 * Support for machine independent machine abstraction.
66 */
67
68 #include <string.h>
69
70 #include <mach/mach_types.h>
71 #include <mach/boolean.h>
72 #include <mach/kern_return.h>
73 #include <mach/machine.h>
74 #include <mach/host_info.h>
75 #include <mach/host_reboot.h>
76 #include <mach/host_priv_server.h>
77 #include <mach/processor_server.h>
78
79 #include <kern/kern_types.h>
80 #include <kern/counters.h>
81 #include <kern/cpu_data.h>
82 #include <kern/ipc_host.h>
83 #include <kern/host.h>
84 #include <kern/lock.h>
85 #include <kern/machine.h>
86 #include <kern/misc_protos.h>
87 #include <kern/processor.h>
88 #include <kern/queue.h>
89 #include <kern/sched.h>
90 #include <kern/task.h>
91 #include <kern/thread.h>
92
93 #include <IOKit/IOHibernatePrivate.h>
94
95 /*
96 * Exported variables:
97 */
98
99 struct machine_info machine_info;
100
101 /* Forwards */
102 void processor_doshutdown(
103 processor_t processor);
104
105 /*
106 * processor_up:
107 *
108 * Flag processor as up and running, and available
109 * for scheduling.
110 */
111 void
112 processor_up(
113 processor_t processor)
114 {
115 processor_set_t pset = &default_pset;
116 spl_t s;
117
118 s = splsched();
119 processor_lock(processor);
120 init_ast_check(processor);
121 simple_lock(&pset->sched_lock);
122 pset_add_processor(pset, processor);
123 enqueue_tail(&pset->active_queue, (queue_entry_t)processor);
124 processor->state = PROCESSOR_RUNNING;
125 simple_unlock(&pset->sched_lock);
126 hw_atomic_add(&machine_info.avail_cpus, 1);
127 ml_cpu_up();
128 processor_unlock(processor);
129 splx(s);
130 }
131
132 kern_return_t
133 host_reboot(
134 host_priv_t host_priv,
135 int options)
136 {
137 if (host_priv == HOST_PRIV_NULL)
138 return (KERN_INVALID_HOST);
139
140 assert(host_priv == &realhost);
141
142 if (options & HOST_REBOOT_DEBUGGER) {
143 Debugger("Debugger");
144 return (KERN_SUCCESS);
145 }
146
147 halt_all_cpus(!(options & HOST_REBOOT_HALT));
148
149 return (KERN_SUCCESS);
150 }
151
152 kern_return_t
153 processor_assign(
154 __unused processor_t processor,
155 __unused processor_set_t new_pset,
156 __unused boolean_t wait)
157 {
158 return (KERN_FAILURE);
159 }
160
161 kern_return_t
162 processor_shutdown(
163 processor_t processor)
164 {
165 processor_set_t pset;
166 spl_t s;
167
168 s = splsched();
169 processor_lock(processor);
170 if (processor->state == PROCESSOR_OFF_LINE) {
171 /*
172 * Success if already shutdown.
173 */
174 processor_unlock(processor);
175 splx(s);
176
177 return (KERN_SUCCESS);
178 }
179
180 if (processor->state == PROCESSOR_START) {
181 /*
182 * Failure if currently being started.
183 */
184 processor_unlock(processor);
185 splx(s);
186
187 return (KERN_FAILURE);
188 }
189
190 /*
191 * Must lock the scheduling lock
192 * to get at the processor state.
193 */
194 pset = processor->processor_set;
195 if (pset != PROCESSOR_SET_NULL) {
196 simple_lock(&pset->sched_lock);
197
198 /*
199 * If the processor is dispatching, let it finish.
200 */
201 while (processor->state == PROCESSOR_DISPATCHING) {
202 simple_unlock(&pset->sched_lock);
203 delay(1);
204 simple_lock(&pset->sched_lock);
205 }
206
207 /*
208 * Success if already being shutdown.
209 */
210 if (processor->state == PROCESSOR_SHUTDOWN) {
211 simple_unlock(&pset->sched_lock);
212 processor_unlock(processor);
213 splx(s);
214
215 return (KERN_SUCCESS);
216 }
217 }
218 else {
219 /*
220 * Success, already being shutdown.
221 */
222 processor_unlock(processor);
223 splx(s);
224
225 return (KERN_SUCCESS);
226 }
227
228 if (processor->state == PROCESSOR_IDLE) {
229 remqueue(&pset->idle_queue, (queue_entry_t)processor);
230 pset->idle_count--;
231 }
232 else
233 if (processor->state == PROCESSOR_RUNNING)
234 remqueue(&pset->active_queue, (queue_entry_t)processor);
235 else
236 panic("processor_shutdown");
237
238 processor->state = PROCESSOR_SHUTDOWN;
239
240 simple_unlock(&pset->sched_lock);
241
242 processor_unlock(processor);
243
244 processor_doshutdown(processor);
245 splx(s);
246
247 cpu_exit_wait(PROCESSOR_DATA(processor, slot_num));
248
249 return (KERN_SUCCESS);
250 }
251
252 /*
253 * Called at splsched.
254 */
255 void
256 processor_doshutdown(
257 processor_t processor)
258 {
259 thread_t old_thread, self = current_thread();
260 processor_set_t pset;
261 processor_t prev;
262 int pcount;
263
264 /*
265 * Get onto the processor to shutdown
266 */
267 prev = thread_bind(self, processor);
268 thread_block(THREAD_CONTINUE_NULL);
269
270 processor_lock(processor);
271 pset = processor->processor_set;
272 simple_lock(&pset->sched_lock);
273
274 if ((pcount = pset->processor_count) == 1) {
275 simple_unlock(&pset->sched_lock);
276 processor_unlock(processor);
277
278 hibernate_vm_lock();
279
280 processor_lock(processor);
281 simple_lock(&pset->sched_lock);
282 }
283
284 assert(processor->state == PROCESSOR_SHUTDOWN);
285
286 pset_remove_processor(pset, processor);
287 simple_unlock(&pset->sched_lock);
288 processor_unlock(processor);
289
290 if (pcount == 1)
291 hibernate_vm_unlock();
292
293 /*
294 * Continue processor shutdown in shutdown context.
295 */
296 thread_bind(self, prev);
297 old_thread = machine_processor_shutdown(self, processor_offline, processor);
298
299 thread_begin(self, self->last_processor);
300
301 thread_dispatch(old_thread);
302
303 /*
304 * If we just shutdown another processor, move the
305 * timer call outs to the current processor.
306 */
307 if (processor != current_processor()) {
308 processor_lock(processor);
309 if ( processor->state == PROCESSOR_OFF_LINE ||
310 processor->state == PROCESSOR_SHUTDOWN )
311 timer_call_shutdown(processor);
312 processor_unlock(processor);
313 }
314 }
315
316 /*
317 * Complete the shutdown and place the processor offline.
318 *
319 * Called at splsched in the shutdown context.
320 */
321 void
322 processor_offline(
323 processor_t processor)
324 {
325 thread_t thread, old_thread = processor->active_thread;
326
327 thread = processor->idle_thread;
328 processor->active_thread = thread;
329 processor->current_pri = IDLEPRI;
330
331 processor->last_dispatch = mach_absolute_time();
332 timer_switch((uint32_t)processor->last_dispatch,
333 &PROCESSOR_DATA(processor, offline_timer));
334
335 thread_done(old_thread, thread, processor);
336
337 machine_set_current_thread(thread);
338
339 thread_begin(thread, processor);
340
341 thread_dispatch(old_thread);
342
343 PMAP_DEACTIVATE_KERNEL(PROCESSOR_DATA(processor, slot_num));
344
345 processor_lock(processor);
346 processor->state = PROCESSOR_OFF_LINE;
347 hw_atomic_sub(&machine_info.avail_cpus, 1);
348 ml_cpu_down();
349 processor_unlock(processor);
350
351 cpu_sleep();
352 panic("zombie processor");
353 /*NOTREACHED*/
354 }
355
356 kern_return_t
357 host_get_boot_info(
358 host_priv_t host_priv,
359 kernel_boot_info_t boot_info)
360 {
361 const char *src = "";
362 if (host_priv == HOST_PRIV_NULL)
363 return (KERN_INVALID_HOST);
364
365 assert(host_priv == &realhost);
366
367 /*
368 * Copy first operator string terminated by '\0' followed by
369 * standardized strings generated from boot string.
370 */
371 src = machine_boot_info(boot_info, KERNEL_BOOT_INFO_MAX);
372 if (src != boot_info)
373 (void) strncpy(boot_info, src, KERNEL_BOOT_INFO_MAX);
374
375 return (KERN_SUCCESS);
376 }