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