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