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/lock.h> 83#include <kern/machine.h> 84#include <kern/misc_protos.h> 85#include <kern/processor.h> 86#include <kern/queue.h> 87#include <kern/sched.h> 88#include <kern/task.h> 89#include <kern/thread.h> 90 91#include <machine/commpage.h> 92 93#if HIBERNATION 94#include <IOKit/IOHibernatePrivate.h> 95#endif 96#include <IOKit/IOPlatformExpert.h> 97 98/* 99 * Exported variables: 100 */ 101 102struct machine_info machine_info; 103 104/* Forwards */ 105void processor_doshutdown( 106 processor_t processor); 107 108/* 109 * processor_up: 110 * 111 * Flag processor as up and running, and available 112 * for scheduling. 113 */ 114void 115processor_up( 116 processor_t processor) 117{ 118 processor_set_t pset; 119 spl_t s; 120 121 s = splsched(); 122 init_ast_check(processor); 123 pset = processor->processor_set; 124 pset_lock(pset); 125 if (++pset->online_processor_count == 1) { 126 pset_pri_init_hint(pset, processor); 127 pset_count_init_hint(pset, processor); 128 } 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 138kern_return_t 139host_reboot( 140 host_priv_t host_priv, 141 int options) 142{ 143 if (host_priv == HOST_PRIV_NULL) 144 return (KERN_INVALID_HOST); 145 146 assert(host_priv == &realhost); 147 148 if (options & HOST_REBOOT_DEBUGGER) { 149 Debugger("Debugger"); 150 return (KERN_SUCCESS); 151 } 152 153 if (options & HOST_REBOOT_UPSDELAY) { 154 // UPS power cutoff path 155 PEHaltRestart( kPEUPSDelayHaltCPU ); 156 } else { 157 halt_all_cpus(!(options & HOST_REBOOT_HALT)); 158 } 159 160 return (KERN_SUCCESS); 161} 162 163kern_return_t 164processor_assign( 165 __unused processor_t processor, 166 __unused processor_set_t new_pset, 167 __unused boolean_t wait) 168{ 169 return (KERN_FAILURE); 170} 171 172kern_return_t 173processor_shutdown( 174 processor_t processor) 175{ 176 processor_set_t pset; 177 spl_t s; 178 179 s = splsched(); 180 pset = processor->processor_set; 181 pset_lock(pset); 182 if (processor->state == PROCESSOR_OFF_LINE) { 183 /* 184 * Success if already shutdown. 185 */ 186 pset_unlock(pset); 187 splx(s); 188 189 return (KERN_SUCCESS); 190 } 191 192 if (processor->state == PROCESSOR_START) { 193 /* 194 * Failure if currently being started. 195 */ 196 pset_unlock(pset); 197 splx(s); 198 199 return (KERN_FAILURE); 200 } 201 202 /* 203 * If the processor is dispatching, let it finish. 204 */ 205 while (processor->state == PROCESSOR_DISPATCHING) { 206 pset_unlock(pset); 207 delay(1); 208 pset_lock(pset); 209 } 210 211 /* 212 * Success if already being shutdown. 213 */ 214 if (processor->state == PROCESSOR_SHUTDOWN) { 215 pset_unlock(pset); 216 splx(s); 217 218 return (KERN_SUCCESS); 219 } 220 221 if (processor->state == PROCESSOR_IDLE) 222 remqueue((queue_entry_t)processor); 223 else 224 if (processor->state == PROCESSOR_RUNNING) 225 remqueue((queue_entry_t)processor); 226 227 processor->state = PROCESSOR_SHUTDOWN; 228 229 pset_unlock(pset); 230 231 processor_doshutdown(processor); 232 splx(s); 233 234 cpu_exit_wait(processor->cpu_id); 235 236 return (KERN_SUCCESS); 237} 238 239/* 240 * Called with interrupts disabled. 241 */ 242void 243processor_doshutdown( 244 processor_t processor) 245{ 246 thread_t old_thread, self = current_thread(); 247 processor_t prev; 248 processor_set_t pset; 249 250 /* 251 * Get onto the processor to shutdown 252 */ 253 prev = thread_bind(processor); 254 thread_block(THREAD_CONTINUE_NULL); 255 256 assert(processor->state == PROCESSOR_SHUTDOWN); 257 258 ml_cpu_down(); 259 260#if HIBERNATION 261 if (processor_avail_count < 2) { 262 hibernate_vm_lock(); 263 hibernate_vm_unlock(); 264 } 265#endif 266 267 pset = processor->processor_set; 268 pset_lock(pset); 269 processor->state = PROCESSOR_OFF_LINE; 270 if (--pset->online_processor_count == 0) { 271 pset_pri_init_hint(pset, PROCESSOR_NULL); 272 pset_count_init_hint(pset, PROCESSOR_NULL); 273 } 274 (void)hw_atomic_sub(&processor_avail_count, 1); 275 commpage_update_active_cpus(); 276 SCHED(processor_queue_shutdown)(processor); 277 /* pset lock dropped */ 278 279 /* 280 * Continue processor shutdown in shutdown context. 281 */ 282 thread_bind(prev); 283 old_thread = machine_processor_shutdown(self, processor_offline, processor); 284 285 thread_dispatch(old_thread, self); 286} 287 288/* 289 *Complete the shutdown and place the processor offline. 290 * 291 * Called at splsched in the shutdown context. 292 */ 293void 294processor_offline( 295 processor_t processor) 296{ 297 thread_t new_thread, old_thread = processor->active_thread; 298 299 new_thread = processor->idle_thread; 300 processor->active_thread = new_thread; 301 processor->current_pri = IDLEPRI; 302 processor->current_thmode = TH_MODE_NONE; 303 processor->deadline = UINT64_MAX; 304 new_thread->last_processor = processor; 305 306 processor->last_dispatch = mach_absolute_time(); 307 timer_stop(PROCESSOR_DATA(processor, thread_timer), processor->last_dispatch); 308 309 machine_set_current_thread(new_thread); 310 311 thread_dispatch(old_thread, new_thread); 312 313 PMAP_DEACTIVATE_KERNEL(processor->cpu_id); 314 315 cpu_sleep(); 316 panic("zombie processor"); 317 /*NOTREACHED*/ 318} 319 320kern_return_t 321host_get_boot_info( 322 host_priv_t host_priv, 323 kernel_boot_info_t boot_info) 324{ 325 const char *src = ""; 326 if (host_priv == HOST_PRIV_NULL) 327 return (KERN_INVALID_HOST); 328 329 assert(host_priv == &realhost); 330 331 /* 332 * Copy first operator string terminated by '\0' followed by 333 * standardized strings generated from boot string. 334 */ 335 src = machine_boot_info(boot_info, KERNEL_BOOT_INFO_MAX); 336 if (src != boot_info) 337 (void) strncpy(boot_info, src, KERNEL_BOOT_INFO_MAX); 338 339 return (KERN_SUCCESS); 340} 341