]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/cpu.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / osfmk / i386 / cpu.c
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 * File: i386/cpu.c
30 *
31 * cpu specific routines
32 */
33
34 #include <kern/kalloc.h>
35 #include <kern/misc_protos.h>
36 #include <kern/lock_group.h>
37 #include <kern/machine.h>
38 #include <mach/processor_info.h>
39 #include <i386/pmap.h>
40 #include <i386/machine_cpu.h>
41 #include <i386/machine_routines.h>
42 #include <i386/misc_protos.h>
43 #include <i386/cpu_threads.h>
44 #include <i386/rtclock_protos.h>
45 #include <i386/cpuid.h>
46 #if CONFIG_VMX
47 #include <i386/vmx/vmx_cpu.h>
48 #endif
49 #include <vm/vm_kern.h>
50 #include <kern/timer_call.h>
51
52 const char *processor_to_datastring(const char *prefix, processor_t target_processor);
53
54 struct processor processor_master;
55
56 /*ARGSUSED*/
57 kern_return_t
58 cpu_control(
59 int slot_num,
60 processor_info_t info,
61 unsigned int count)
62 {
63 printf("cpu_control(%d,%p,%d) not implemented\n",
64 slot_num, info, count);
65 return KERN_FAILURE;
66 }
67
68 /*ARGSUSED*/
69 kern_return_t
70 cpu_info_count(
71 __unused processor_flavor_t flavor,
72 unsigned int *count)
73 {
74 *count = 0;
75 return KERN_FAILURE;
76 }
77
78 /*ARGSUSED*/
79 kern_return_t
80 cpu_info(
81 processor_flavor_t flavor,
82 int slot_num,
83 processor_info_t info,
84 unsigned int *count)
85 {
86 printf("cpu_info(%d,%d,%p,%p) not implemented\n",
87 flavor, slot_num, info, count);
88 return KERN_FAILURE;
89 }
90
91 void
92 cpu_sleep(void)
93 {
94 cpu_data_t *cdp = current_cpu_datap();
95
96 /* This calls IOCPURunPlatformQuiesceActions when sleeping the boot cpu */
97 PE_cpu_machine_quiesce(cdp->cpu_id);
98
99 cpu_thread_halt();
100 }
101
102 void
103 cpu_init(void)
104 {
105 cpu_data_t *cdp = current_cpu_datap();
106
107 timer_call_queue_init(&cdp->rtclock_timer.queue);
108 cdp->rtclock_timer.deadline = EndOfAllTime;
109
110 cdp->cpu_type = cpuid_cputype();
111 cdp->cpu_subtype = cpuid_cpusubtype();
112
113 i386_activate_cpu();
114 }
115
116 kern_return_t
117 cpu_start(
118 int cpu)
119 {
120 kern_return_t ret;
121
122 if (cpu == cpu_number()) {
123 cpu_machine_init();
124 return KERN_SUCCESS;
125 }
126
127 /*
128 * Try to bring the CPU back online without a reset.
129 * If the fast restart doesn't succeed, fall back to
130 * the slow way.
131 */
132 ret = intel_startCPU_fast(cpu);
133 if (ret != KERN_SUCCESS) {
134 /*
135 * Should call out through PE.
136 * But take the shortcut here.
137 */
138 ret = intel_startCPU(cpu);
139 }
140
141 if (ret != KERN_SUCCESS) {
142 kprintf("cpu: cpu_start(%d) returning failure!\n", cpu);
143 }
144
145 return ret;
146 }
147
148 void
149 cpu_exit_wait(
150 int cpu)
151 {
152 cpu_data_t *cdp = cpu_datap(cpu);
153 boolean_t intrs_enabled;
154 uint64_t tsc_timeout;
155
156 /*
157 * Wait until the CPU indicates that it has stopped.
158 * Disable interrupts while the topo lock is held -- arguably
159 * this should always be done but in this instance it can lead to
160 * a timeout if long-running interrupt were to occur here.
161 */
162 intrs_enabled = ml_set_interrupts_enabled(FALSE);
163 mp_safe_spin_lock(&x86_topo_lock);
164 /* Set a generous timeout of several seconds (in TSC ticks) */
165 tsc_timeout = rdtsc64() + (10ULL * 1000 * 1000 * 1000);
166 while ((cdp->lcpu.state != LCPU_HALT)
167 && (cdp->lcpu.state != LCPU_OFF)
168 && !cdp->lcpu.stopped) {
169 simple_unlock(&x86_topo_lock);
170 ml_set_interrupts_enabled(intrs_enabled);
171 cpu_pause();
172 if (rdtsc64() > tsc_timeout) {
173 panic("cpu_exit_wait(%d) timeout", cpu);
174 }
175 ml_set_interrupts_enabled(FALSE);
176 mp_safe_spin_lock(&x86_topo_lock);
177 }
178 simple_unlock(&x86_topo_lock);
179 ml_set_interrupts_enabled(intrs_enabled);
180 }
181
182 void
183 cpu_machine_init(
184 void)
185 {
186 cpu_data_t *cdp = current_cpu_datap();
187
188 PE_cpu_machine_init(cdp->cpu_id, !cdp->cpu_boot_complete);
189 cdp->cpu_boot_complete = TRUE;
190 cdp->cpu_running = TRUE;
191 ml_init_interrupt();
192
193 #if CONFIG_VMX
194 /* initialize VMX for every CPU */
195 vmx_cpu_init();
196 #endif
197 }
198
199 processor_t
200 cpu_processor_alloc(boolean_t is_boot_cpu)
201 {
202 int ret;
203 processor_t proc;
204
205 if (is_boot_cpu) {
206 return &processor_master;
207 }
208
209 ret = kmem_alloc(kernel_map, (vm_offset_t *) &proc, sizeof(*proc), VM_KERN_MEMORY_OSFMK);
210 if (ret != KERN_SUCCESS) {
211 return NULL;
212 }
213
214 bzero((void *) proc, sizeof(*proc));
215 return proc;
216 }
217
218 void
219 cpu_processor_free(processor_t proc)
220 {
221 if (proc != NULL && proc != &processor_master) {
222 kfree(proc, sizeof(*proc));
223 }
224 }
225
226 processor_t
227 current_processor(void)
228 {
229 return current_cpu_datap()->cpu_processor;
230 }
231
232 processor_t
233 cpu_to_processor(
234 int cpu)
235 {
236 return cpu_datap(cpu)->cpu_processor;
237 }
238
239 ast_t *
240 ast_pending(void)
241 {
242 return &current_cpu_datap()->cpu_pending_ast;
243 }
244
245 cpu_type_t
246 slot_type(
247 int slot_num)
248 {
249 return cpu_datap(slot_num)->cpu_type;
250 }
251
252 cpu_subtype_t
253 slot_subtype(
254 int slot_num)
255 {
256 return cpu_datap(slot_num)->cpu_subtype;
257 }
258
259 cpu_threadtype_t
260 slot_threadtype(
261 int slot_num)
262 {
263 return cpu_datap(slot_num)->cpu_threadtype;
264 }
265
266 cpu_type_t
267 cpu_type(void)
268 {
269 return current_cpu_datap()->cpu_type;
270 }
271
272 cpu_subtype_t
273 cpu_subtype(void)
274 {
275 return current_cpu_datap()->cpu_subtype;
276 }
277
278 cpu_threadtype_t
279 cpu_threadtype(void)
280 {
281 return current_cpu_datap()->cpu_threadtype;
282 }
283
284 const char *
285 processor_to_datastring(const char *prefix, processor_t target_processor)
286 {
287 static char printBuf[256];
288 uint32_t cpu_num = target_processor->cpu_id;
289
290 cpu_data_t *cpup = cpu_datap(cpu_num);
291 thread_t act;
292
293 act = ml_validate_nofault((vm_offset_t)cpup->cpu_active_thread,
294 sizeof(struct thread)) ? cpup->cpu_active_thread : NULL;
295
296 snprintf(printBuf, sizeof(printBuf),
297 "%s: tCPU %u (%d) [tid=0x%llx(bp=%d sp=%d) s=0x%x ps=0x%x cpa=0x%x spa=0x%llx pl=%d il=%d r=%d]",
298 prefix,
299 cpu_num,
300 target_processor->state,
301 act ? act->thread_id : ~0ULL,
302 act ? act->base_pri : -1,
303 act ? act->sched_pri : -1,
304 cpup->cpu_signals,
305 cpup->cpu_prior_signals,
306 cpup->cpu_pending_ast,
307 target_processor->processor_set->pending_AST_URGENT_cpu_mask,
308 cpup->cpu_preemption_level,
309 cpup->cpu_interrupt_level,
310 cpup->cpu_running);
311
312 return (const char *)&printBuf[0];
313 }