]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
6601e61a | 4 | * @APPLE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
6601e61a A |
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. | |
8f6c56a5 | 11 | * |
6601e61a A |
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 | |
8f6c56a5 A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
6601e61a A |
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. | |
8f6c56a5 | 19 | * |
6601e61a | 20 | * @APPLE_LICENSE_HEADER_END@ |
1c79356b A |
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 | ||
1c79356b | 60 | #include <string.h> |
91447636 A |
61 | |
62 | #include <mach/mach_types.h> | |
1c79356b A |
63 | #include <mach/boolean.h> |
64 | #include <mach/kern_return.h> | |
1c79356b A |
65 | #include <mach/machine.h> |
66 | #include <mach/host_info.h> | |
67 | #include <mach/host_reboot.h> | |
91447636 A |
68 | #include <mach/host_priv_server.h> |
69 | #include <mach/processor_server.h> | |
70 | ||
71 | #include <kern/kern_types.h> | |
1c79356b A |
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> | |
91447636 | 78 | #include <kern/misc_protos.h> |
1c79356b A |
79 | #include <kern/processor.h> |
80 | #include <kern/queue.h> | |
81 | #include <kern/sched.h> | |
82 | #include <kern/task.h> | |
83 | #include <kern/thread.h> | |
1c79356b | 84 | |
3a60a9f5 | 85 | #include <IOKit/IOHibernatePrivate.h> |
0c530ab8 | 86 | #include <IOKit/IOPlatformExpert.h> |
1c79356b A |
87 | |
88 | /* | |
89 | * Exported variables: | |
90 | */ | |
91 | ||
92 | struct machine_info machine_info; | |
1c79356b A |
93 | |
94 | /* Forwards */ | |
1c79356b A |
95 | void processor_doshutdown( |
96 | processor_t processor); | |
97 | ||
98 | /* | |
91447636 | 99 | * processor_up: |
1c79356b | 100 | * |
91447636 A |
101 | * Flag processor as up and running, and available |
102 | * for scheduling. | |
1c79356b A |
103 | */ |
104 | void | |
91447636 A |
105 | processor_up( |
106 | processor_t processor) | |
1c79356b | 107 | { |
91447636 A |
108 | processor_set_t pset = &default_pset; |
109 | spl_t s; | |
1c79356b A |
110 | |
111 | s = splsched(); | |
112 | processor_lock(processor); | |
113 | init_ast_check(processor); | |
9bccf70c | 114 | simple_lock(&pset->sched_lock); |
55e303ae | 115 | pset_add_processor(pset, processor); |
9bccf70c | 116 | enqueue_tail(&pset->active_queue, (queue_entry_t)processor); |
1c79356b | 117 | processor->state = PROCESSOR_RUNNING; |
9bccf70c | 118 | simple_unlock(&pset->sched_lock); |
91447636 A |
119 | hw_atomic_add(&machine_info.avail_cpus, 1); |
120 | ml_cpu_up(); | |
1c79356b A |
121 | processor_unlock(processor); |
122 | splx(s); | |
123 | } | |
124 | ||
125 | kern_return_t | |
126 | host_reboot( | |
55e303ae | 127 | host_priv_t host_priv, |
1c79356b A |
128 | int options) |
129 | { | |
130 | if (host_priv == HOST_PRIV_NULL) | |
131 | return (KERN_INVALID_HOST); | |
132 | ||
133 | assert(host_priv == &realhost); | |
134 | ||
135 | if (options & HOST_REBOOT_DEBUGGER) { | |
136 | Debugger("Debugger"); | |
55e303ae | 137 | return (KERN_SUCCESS); |
1c79356b A |
138 | } |
139 | ||
0c530ab8 A |
140 | if (options & HOST_REBOOT_UPSDELAY) { |
141 | // UPS power cutoff path | |
142 | PEHaltRestart( kPEUPSDelayHaltCPU ); | |
143 | } else { | |
144 | halt_all_cpus(!(options & HOST_REBOOT_HALT)); | |
145 | } | |
9bccf70c | 146 | |
55e303ae | 147 | return (KERN_SUCCESS); |
1c79356b A |
148 | } |
149 | ||
150 | kern_return_t | |
151 | processor_assign( | |
91447636 A |
152 | __unused processor_t processor, |
153 | __unused processor_set_t new_pset, | |
154 | __unused boolean_t wait) | |
1c79356b | 155 | { |
1c79356b A |
156 | return (KERN_FAILURE); |
157 | } | |
158 | ||
1c79356b A |
159 | kern_return_t |
160 | processor_shutdown( | |
55e303ae | 161 | processor_t processor) |
1c79356b | 162 | { |
55e303ae A |
163 | processor_set_t pset; |
164 | spl_t s; | |
1c79356b A |
165 | |
166 | s = splsched(); | |
167 | processor_lock(processor); | |
91447636 | 168 | if (processor->state == PROCESSOR_OFF_LINE) { |
1c79356b | 169 | /* |
91447636 | 170 | * Success if already shutdown. |
1c79356b A |
171 | */ |
172 | processor_unlock(processor); | |
173 | splx(s); | |
174 | ||
175 | return (KERN_SUCCESS); | |
176 | } | |
177 | ||
55e303ae A |
178 | if (processor->state == PROCESSOR_START) { |
179 | /* | |
180 | * Failure if currently being started. | |
181 | */ | |
182 | processor_unlock(processor); | |
183 | splx(s); | |
1c79356b | 184 | |
55e303ae A |
185 | return (KERN_FAILURE); |
186 | } | |
1c79356b | 187 | |
55e303ae | 188 | /* |
91447636 A |
189 | * Must lock the scheduling lock |
190 | * to get at the processor state. | |
55e303ae A |
191 | */ |
192 | pset = processor->processor_set; | |
91447636 | 193 | if (pset != PROCESSOR_SET_NULL) { |
55e303ae | 194 | simple_lock(&pset->sched_lock); |
91447636 A |
195 | |
196 | /* | |
197 | * If the processor is dispatching, let it finish. | |
198 | */ | |
199 | while (processor->state == PROCESSOR_DISPATCHING) { | |
200 | simple_unlock(&pset->sched_lock); | |
201 | delay(1); | |
202 | simple_lock(&pset->sched_lock); | |
203 | } | |
204 | ||
205 | /* | |
206 | * Success if already being shutdown. | |
207 | */ | |
208 | if (processor->state == PROCESSOR_SHUTDOWN) { | |
209 | simple_unlock(&pset->sched_lock); | |
210 | processor_unlock(processor); | |
211 | splx(s); | |
212 | ||
213 | return (KERN_SUCCESS); | |
214 | } | |
215 | } | |
216 | else { | |
217 | /* | |
218 | * Success, already being shutdown. | |
219 | */ | |
220 | processor_unlock(processor); | |
221 | splx(s); | |
222 | ||
223 | return (KERN_SUCCESS); | |
55e303ae | 224 | } |
1c79356b | 225 | |
55e303ae A |
226 | if (processor->state == PROCESSOR_IDLE) { |
227 | remqueue(&pset->idle_queue, (queue_entry_t)processor); | |
228 | pset->idle_count--; | |
229 | } | |
230 | else | |
231 | if (processor->state == PROCESSOR_RUNNING) | |
232 | remqueue(&pset->active_queue, (queue_entry_t)processor); | |
233 | else | |
91447636 | 234 | panic("processor_shutdown"); |
1c79356b | 235 | |
55e303ae | 236 | processor->state = PROCESSOR_SHUTDOWN; |
1c79356b | 237 | |
55e303ae | 238 | simple_unlock(&pset->sched_lock); |
1c79356b | 239 | |
55e303ae | 240 | processor_unlock(processor); |
1c79356b | 241 | |
55e303ae | 242 | processor_doshutdown(processor); |
1c79356b | 243 | splx(s); |
1c79356b | 244 | |
91447636 | 245 | cpu_exit_wait(PROCESSOR_DATA(processor, slot_num)); |
5353443c | 246 | |
55e303ae | 247 | return (KERN_SUCCESS); |
1c79356b A |
248 | } |
249 | ||
250 | /* | |
55e303ae | 251 | * Called at splsched. |
1c79356b A |
252 | */ |
253 | void | |
55e303ae A |
254 | processor_doshutdown( |
255 | processor_t processor) | |
1c79356b | 256 | { |
55e303ae | 257 | thread_t old_thread, self = current_thread(); |
1c79356b | 258 | processor_set_t pset; |
55e303ae | 259 | processor_t prev; |
91447636 | 260 | int pcount; |
1c79356b A |
261 | |
262 | /* | |
263 | * Get onto the processor to shutdown | |
264 | */ | |
55e303ae | 265 | prev = thread_bind(self, processor); |
9bccf70c | 266 | thread_block(THREAD_CONTINUE_NULL); |
1c79356b | 267 | |
55e303ae | 268 | processor_lock(processor); |
1c79356b | 269 | pset = processor->processor_set; |
55e303ae | 270 | simple_lock(&pset->sched_lock); |
1c79356b | 271 | |
91447636 | 272 | if ((pcount = pset->processor_count) == 1) { |
55e303ae A |
273 | simple_unlock(&pset->sched_lock); |
274 | processor_unlock(processor); | |
1c79356b | 275 | |
3a60a9f5 A |
276 | hibernate_vm_lock(); |
277 | ||
55e303ae A |
278 | processor_lock(processor); |
279 | simple_lock(&pset->sched_lock); | |
1c79356b A |
280 | } |
281 | ||
55e303ae | 282 | assert(processor->state == PROCESSOR_SHUTDOWN); |
1c79356b A |
283 | |
284 | pset_remove_processor(pset, processor); | |
55e303ae | 285 | simple_unlock(&pset->sched_lock); |
1c79356b | 286 | processor_unlock(processor); |
1c79356b | 287 | |
3a60a9f5 A |
288 | if (pcount == 1) |
289 | hibernate_vm_unlock(); | |
91447636 | 290 | |
1c79356b | 291 | /* |
91447636 | 292 | * Continue processor shutdown in shutdown context. |
1c79356b | 293 | */ |
55e303ae | 294 | thread_bind(self, prev); |
91447636 | 295 | old_thread = machine_processor_shutdown(self, processor_offline, processor); |
a3d08fcd | 296 | |
91447636 | 297 | thread_begin(self, self->last_processor); |
a3d08fcd | 298 | |
1c79356b | 299 | thread_dispatch(old_thread); |
91447636 A |
300 | |
301 | /* | |
302 | * If we just shutdown another processor, move the | |
303 | * timer call outs to the current processor. | |
304 | */ | |
305 | if (processor != current_processor()) { | |
306 | processor_lock(processor); | |
307 | if ( processor->state == PROCESSOR_OFF_LINE || | |
308 | processor->state == PROCESSOR_SHUTDOWN ) | |
309 | timer_call_shutdown(processor); | |
310 | processor_unlock(processor); | |
311 | } | |
1c79356b A |
312 | } |
313 | ||
314 | /* | |
91447636 A |
315 | * Complete the shutdown and place the processor offline. |
316 | * | |
317 | * Called at splsched in the shutdown context. | |
1c79356b | 318 | */ |
1c79356b | 319 | void |
55e303ae | 320 | processor_offline( |
1c79356b A |
321 | processor_t processor) |
322 | { | |
91447636 A |
323 | thread_t thread, old_thread = processor->active_thread; |
324 | ||
325 | thread = processor->idle_thread; | |
326 | processor->active_thread = thread; | |
327 | processor->current_pri = IDLEPRI; | |
328 | ||
329 | processor->last_dispatch = mach_absolute_time(); | |
330 | timer_switch((uint32_t)processor->last_dispatch, | |
331 | &PROCESSOR_DATA(processor, offline_timer)); | |
332 | ||
333 | thread_done(old_thread, thread, processor); | |
334 | ||
335 | machine_set_current_thread(thread); | |
336 | ||
337 | thread_begin(thread, processor); | |
1c79356b | 338 | |
55e303ae | 339 | thread_dispatch(old_thread); |
1c79356b | 340 | |
91447636 A |
341 | PMAP_DEACTIVATE_KERNEL(PROCESSOR_DATA(processor, slot_num)); |
342 | ||
343 | processor_lock(processor); | |
344 | processor->state = PROCESSOR_OFF_LINE; | |
345 | hw_atomic_sub(&machine_info.avail_cpus, 1); | |
346 | ml_cpu_down(); | |
347 | processor_unlock(processor); | |
348 | ||
1c79356b A |
349 | cpu_sleep(); |
350 | panic("zombie processor"); | |
351 | /*NOTREACHED*/ | |
352 | } | |
353 | ||
354 | kern_return_t | |
355 | host_get_boot_info( | |
356 | host_priv_t host_priv, | |
357 | kernel_boot_info_t boot_info) | |
358 | { | |
91447636 | 359 | const char *src = ""; |
1c79356b A |
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 | } |