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