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