]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOCPU.cpp
64b3a283fe4c40a45167ffa12eaa20f5216bc9cd
[apple/xnu.git] / iokit / Kernel / IOCPU.cpp
1 /*
2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
32 *
33 * DRI: Josh de Cesare
34 *
35 */
36
37 extern "C" {
38 #include <machine/machine_routines.h>
39 #include <pexpert/pexpert.h>
40 }
41
42 #include <IOKit/IOLib.h>
43 #include <IOKit/IOPlatformExpert.h>
44 #include <IOKit/IOUserClient.h>
45 #include <IOKit/IOCPU.h>
46
47
48 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
49
50 kern_return_t PE_cpu_start(cpu_id_t target,
51 vm_offset_t start_paddr, vm_offset_t arg_paddr)
52 {
53 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
54
55 if (targetCPU == 0) return KERN_FAILURE;
56 return targetCPU->startCPU(start_paddr, arg_paddr);
57 }
58
59 void PE_cpu_halt(cpu_id_t target)
60 {
61 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
62
63 if (targetCPU) targetCPU->haltCPU();
64 }
65
66 void PE_cpu_signal(cpu_id_t source, cpu_id_t target)
67 {
68 IOCPU *sourceCPU = OSDynamicCast(IOCPU, (OSObject *)source);
69 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
70
71 if (sourceCPU && targetCPU) sourceCPU->signalCPU(targetCPU);
72 }
73
74 void PE_cpu_machine_init(cpu_id_t target, boolean_t boot)
75 {
76 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
77
78 if (targetCPU) targetCPU->initCPU(boot);
79 }
80
81 void PE_cpu_machine_quiesce(cpu_id_t target)
82 {
83 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
84
85 if (targetCPU) targetCPU->quiesceCPU();
86 }
87
88 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
89
90 #define super IOService
91
92 OSDefineMetaClassAndAbstractStructors(IOCPU, IOService);
93 OSMetaClassDefineReservedUnused(IOCPU, 0);
94 OSMetaClassDefineReservedUnused(IOCPU, 1);
95 OSMetaClassDefineReservedUnused(IOCPU, 2);
96 OSMetaClassDefineReservedUnused(IOCPU, 3);
97 OSMetaClassDefineReservedUnused(IOCPU, 4);
98 OSMetaClassDefineReservedUnused(IOCPU, 5);
99 OSMetaClassDefineReservedUnused(IOCPU, 6);
100 OSMetaClassDefineReservedUnused(IOCPU, 7);
101
102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
103
104 static OSArray *gIOCPUs;
105 static const OSSymbol *gIOCPUStateKey;
106 static OSString *gIOCPUStateNames[kIOCPUStateCount];
107
108 void IOCPUSleepKernel(void)
109 {
110 long cnt, numCPUs;
111 IOCPU *target;
112
113 numCPUs = gIOCPUs->getCount();
114
115 // Sleep the CPUs.
116 cnt = numCPUs;
117 while (cnt--) {
118 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
119 if (target->getCPUState() == kIOCPUStateRunning) {
120 target->haltCPU();
121 }
122 }
123
124 // Wake the other CPUs.
125 for (cnt = 1; cnt < numCPUs; cnt++) {
126 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
127 if (target->getCPUState() == kIOCPUStateStopped) {
128 processor_start(target->getMachProcessor());
129 }
130 }
131 }
132
133 void IOCPU::initCPUs(void)
134 {
135 if (gIOCPUs == 0) {
136 gIOCPUs = OSArray::withCapacity(1);
137
138 gIOCPUStateKey = OSSymbol::withCStringNoCopy("IOCPUState");
139
140 gIOCPUStateNames[kIOCPUStateUnregistered] =
141 OSString::withCStringNoCopy("Unregistered");
142 gIOCPUStateNames[kIOCPUStateUninitalized] =
143 OSString::withCStringNoCopy("Uninitalized");
144 gIOCPUStateNames[kIOCPUStateStopped] =
145 OSString::withCStringNoCopy("Stopped");
146 gIOCPUStateNames[kIOCPUStateRunning] =
147 OSString::withCStringNoCopy("Running");
148 }
149 }
150
151 bool IOCPU::start(IOService *provider)
152 {
153 OSData *busFrequency, *cpuFrequency, *timebaseFrequency;
154
155 if (!super::start(provider)) return false;
156
157 initCPUs();
158
159 _cpuGroup = gIOCPUs;
160 cpuNub = provider;
161
162 gIOCPUs->setObject(this);
163
164 // Correct the bus, cpu and timebase frequencies in the device tree.
165 if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
166 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
167 } else {
168 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_frequency_hz, 8);
169 }
170 provider->setProperty("bus-frequency", busFrequency);
171 busFrequency->release();
172
173 if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
174 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
175 } else {
176 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_frequency_hz, 8);
177 }
178 provider->setProperty("clock-frequency", cpuFrequency);
179 cpuFrequency->release();
180
181 timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
182 provider->setProperty("timebase-frequency", timebaseFrequency);
183 timebaseFrequency->release();
184
185 super::setProperty("IOCPUID", (UInt32)this, 32);
186
187 setCPUNumber(0);
188 setCPUState(kIOCPUStateUnregistered);
189
190 return true;
191 }
192
193 OSObject *IOCPU::getProperty(const OSSymbol *aKey) const
194 {
195 if (aKey == gIOCPUStateKey) return gIOCPUStateNames[_cpuState];
196
197 return super::getProperty(aKey);
198 }
199
200 bool IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject)
201 {
202 OSString *stateStr;
203
204 if (aKey == gIOCPUStateKey) {
205 stateStr = OSDynamicCast(OSString, anObject);
206 if (stateStr == 0) return false;
207
208 if (_cpuNumber == 0) return false;
209
210 if (stateStr->isEqualTo("running")) {
211 if (_cpuState == kIOCPUStateStopped) {
212 processor_start(machProcessor);
213 } else if (_cpuState != kIOCPUStateRunning) {
214 return false;
215 }
216 } else if (stateStr->isEqualTo("stopped")) {
217 if (_cpuState == kIOCPUStateRunning) {
218 haltCPU();
219 } else if (_cpuState != kIOCPUStateStopped) {
220 return false;
221 }
222 } else return false;
223
224 return true;
225 }
226
227 return super::setProperty(aKey, anObject);
228 }
229
230 bool IOCPU::serializeProperties(OSSerialize *serialize) const
231 {
232 super::setProperty(gIOCPUStateKey, gIOCPUStateNames[_cpuState]);
233
234 return super::serializeProperties(serialize);
235 }
236
237 IOReturn IOCPU::setProperties(OSObject *properties)
238 {
239 OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
240 OSString *stateStr;
241 IOReturn result;
242
243 if (dict == 0) return kIOReturnUnsupported;
244
245 stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey));
246 if (stateStr != 0) {
247 result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
248 if (result != kIOReturnSuccess) return result;
249
250 if (setProperty(gIOCPUStateKey, stateStr)) return kIOReturnSuccess;
251
252 return kIOReturnUnsupported;
253 }
254
255 return kIOReturnUnsupported;
256 }
257
258 void IOCPU::signalCPU(IOCPU */*target*/)
259 {
260 }
261
262 void IOCPU::enableCPUTimeBase(bool /*enable*/)
263 {
264 }
265
266 UInt32 IOCPU::getCPUNumber(void)
267 {
268 return _cpuNumber;
269 }
270
271 void IOCPU::setCPUNumber(UInt32 cpuNumber)
272 {
273 _cpuNumber = cpuNumber;
274 super::setProperty("IOCPUNumber", _cpuNumber, 32);
275 }
276
277 UInt32 IOCPU::getCPUState(void)
278 {
279 return _cpuState;
280 }
281
282 void IOCPU::setCPUState(UInt32 cpuState)
283 {
284 if (cpuState < kIOCPUStateCount) {
285 _cpuState = cpuState;
286 }
287 }
288
289 OSArray *IOCPU::getCPUGroup(void)
290 {
291 return _cpuGroup;
292 }
293
294 UInt32 IOCPU::getCPUGroupSize(void)
295 {
296 return _cpuGroup->getCount();
297 }
298
299 processor_t IOCPU::getMachProcessor(void)
300 {
301 return machProcessor;
302 }
303
304
305 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
306
307 #undef super
308 #define super IOInterruptController
309
310 OSDefineMetaClassAndStructors(IOCPUInterruptController, IOInterruptController);
311
312 OSMetaClassDefineReservedUnused(IOCPUInterruptController, 0);
313 OSMetaClassDefineReservedUnused(IOCPUInterruptController, 1);
314 OSMetaClassDefineReservedUnused(IOCPUInterruptController, 2);
315 OSMetaClassDefineReservedUnused(IOCPUInterruptController, 3);
316 OSMetaClassDefineReservedUnused(IOCPUInterruptController, 4);
317 OSMetaClassDefineReservedUnused(IOCPUInterruptController, 5);
318
319
320
321 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
322
323
324 IOReturn IOCPUInterruptController::initCPUInterruptController(int sources)
325 {
326 int cnt;
327
328 if (!super::init()) return kIOReturnInvalid;
329
330 numCPUs = sources;
331
332 cpus = (IOCPU **)IOMalloc(numCPUs * sizeof(IOCPU *));
333 if (cpus == 0) return kIOReturnNoMemory;
334 bzero(cpus, numCPUs * sizeof(IOCPU *));
335
336 vectors = (IOInterruptVector *)IOMalloc(numCPUs * sizeof(IOInterruptVector));
337 if (vectors == 0) return kIOReturnNoMemory;
338 bzero(vectors, numCPUs * sizeof(IOInterruptVector));
339
340 // Allocate locks for the
341 for (cnt = 0; cnt < numCPUs; cnt++) {
342 vectors[cnt].interruptLock = IOLockAlloc();
343 if (vectors[cnt].interruptLock == NULL) {
344 for (cnt = 0; cnt < numCPUs; cnt++) {
345 if (vectors[cnt].interruptLock != NULL)
346 IOLockFree(vectors[cnt].interruptLock);
347 }
348 return kIOReturnNoResources;
349 }
350 }
351
352 ml_init_max_cpus(numCPUs);
353
354 return kIOReturnSuccess;
355 }
356
357 void IOCPUInterruptController::registerCPUInterruptController(void)
358 {
359 registerService();
360
361 getPlatform()->registerInterruptController(gPlatformInterruptControllerName,
362 this);
363 }
364
365 void IOCPUInterruptController::setCPUInterruptProperties(IOService *service)
366 {
367 int cnt;
368 OSArray *controller;
369 OSArray *specifier;
370 OSData *tmpData;
371 long tmpLong;
372
373 // Create the interrupt specifer array.
374 specifier = OSArray::withCapacity(numCPUs);
375 for (cnt = 0; cnt < numCPUs; cnt++) {
376 tmpLong = cnt;
377 tmpData = OSData::withBytes(&tmpLong, sizeof(tmpLong));
378 specifier->setObject(tmpData);
379 tmpData->release();
380 };
381
382 // Create the interrupt controller array.
383 controller = OSArray::withCapacity(numCPUs);
384 for (cnt = 0; cnt < numCPUs; cnt++) {
385 controller->setObject(gPlatformInterruptControllerName);
386 }
387
388 // Put the two arrays into the property table.
389 service->setProperty(gIOInterruptControllersKey, controller);
390 service->setProperty(gIOInterruptSpecifiersKey, specifier);
391 controller->release();
392 specifier->release();
393 }
394
395 void IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu)
396 {
397 ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this,
398 (IOInterruptHandler)&IOCPUInterruptController::handleInterrupt, 0);
399
400 enabledCPUs++;
401
402 if (enabledCPUs == numCPUs) thread_wakeup(this);
403 }
404
405 IOReturn IOCPUInterruptController::registerInterrupt(IOService *nub,
406 int source,
407 void *target,
408 IOInterruptHandler handler,
409 void *refCon)
410 {
411 IOInterruptVector *vector;
412
413 if (source >= numCPUs) return kIOReturnNoResources;
414
415 vector = &vectors[source];
416
417 // Get the lock for this vector.
418 IOTakeLock(vector->interruptLock);
419
420 // Make sure the vector is not in use.
421 if (vector->interruptRegistered) {
422 IOUnlock(vector->interruptLock);
423 return kIOReturnNoResources;
424 }
425
426 // Fill in vector with the client's info.
427 vector->handler = handler;
428 vector->nub = nub;
429 vector->source = source;
430 vector->target = target;
431 vector->refCon = refCon;
432
433 // Get the vector ready. It starts hard disabled.
434 vector->interruptDisabledHard = 1;
435 vector->interruptDisabledSoft = 1;
436 vector->interruptRegistered = 1;
437
438 IOUnlock(vector->interruptLock);
439
440 if (enabledCPUs != numCPUs) {
441 assert_wait(this, THREAD_UNINT);
442 thread_block(THREAD_CONTINUE_NULL);
443 }
444
445 return kIOReturnSuccess;
446 }
447
448 IOReturn IOCPUInterruptController::getInterruptType(IOService */*nub*/,
449 int /*source*/,
450 int *interruptType)
451 {
452 if (interruptType == 0) return kIOReturnBadArgument;
453
454 *interruptType = kIOInterruptTypeLevel;
455
456 return kIOReturnSuccess;
457 }
458
459 IOReturn IOCPUInterruptController::enableInterrupt(IOService */*nub*/,
460 int /*source*/)
461 {
462 // ml_set_interrupts_enabled(true);
463 return kIOReturnSuccess;
464 }
465
466 IOReturn IOCPUInterruptController::disableInterrupt(IOService */*nub*/,
467 int /*source*/)
468 {
469 // ml_set_interrupts_enabled(false);
470 return kIOReturnSuccess;
471 }
472
473 IOReturn IOCPUInterruptController::causeInterrupt(IOService */*nub*/,
474 int /*source*/)
475 {
476 ml_cause_interrupt();
477 return kIOReturnSuccess;
478 }
479
480 IOReturn IOCPUInterruptController::handleInterrupt(void */*refCon*/,
481 IOService */*nub*/,
482 int source)
483 {
484 IOInterruptVector *vector;
485
486 vector = &vectors[source];
487
488 if (!vector->interruptRegistered) return kIOReturnInvalid;
489
490 vector->handler(vector->target, vector->refCon,
491 vector->nub, vector->source);
492
493 return kIOReturnSuccess;
494 }
495
496 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */