--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+extern "C" {
+#include <mach/task.h>
+#include <machine/machine_routines.h>
+#include <pexpert/pexpert.h>
+};
+
+#include <IOKit/IOPlatformExpert.h>
+#include <IOKit/IOService.h>
+#include <IOKit/PassthruInterruptController.h>
+
+#define super IOInterruptController
+OSDefineMetaClassAndStructors(PassthruInterruptController, IOInterruptController);
+
+bool
+PassthruInterruptController::init(void)
+{
+ if (!super::init() ||
+ !this->setProperty(gPlatformInterruptControllerName, kOSBooleanTrue) ||
+ !this->attach(getPlatform())) {
+ return false;
+ }
+ registerService();
+ if (getPlatform()->registerInterruptController(gPlatformInterruptControllerName, this) != kIOReturnSuccess) {
+ return false;
+ }
+ if (semaphore_create(kernel_task, &child_sentinel, SYNC_POLICY_FIFO, 0) != KERN_SUCCESS) {
+ return false;
+ }
+ return true;
+}
+
+void
+PassthruInterruptController::setCPUInterruptProperties(IOService *service)
+{
+ if ((service->getProperty(gIOInterruptControllersKey) != NULL) &&
+ (service->getProperty(gIOInterruptSpecifiersKey) != NULL)) {
+ return;
+ }
+
+ long zero = 0;
+ OSArray *specifier = OSArray::withCapacity(1);
+ OSData *tmpData = OSData::withBytes(&zero, sizeof(zero));
+ specifier->setObject(tmpData);
+ tmpData->release();
+ service->setProperty(gIOInterruptSpecifiersKey, specifier);
+ specifier->release();
+
+ OSArray *controller = OSArray::withCapacity(1);
+ controller->setObject(gPlatformInterruptControllerName);
+ service->setProperty(gIOInterruptControllersKey, controller);
+ controller->release();
+}
+
+IOReturn
+PassthruInterruptController::registerInterrupt(IOService *nub,
+ int source,
+ void *target,
+ IOInterruptHandler handler,
+ void *refCon)
+{
+ child_handler = handler;
+ child_nub = nub;
+ child_target = target;
+ child_refCon = refCon;
+
+ // Wake up waitForChildController() to tell it that AIC is registered
+ semaphore_signal(child_sentinel);
+ return kIOReturnSuccess;
+}
+
+void *
+PassthruInterruptController::waitForChildController(void)
+{
+ // Block if child controller isn't registered yet. Assumes that this
+ // is only called from one place.
+ semaphore_wait(child_sentinel);
+
+ // NOTE: Assumes that AppleInterruptController passes |this| as the target argument.
+ return child_target;
+}
+
+IOReturn
+PassthruInterruptController::getInterruptType(IOService */*nub*/,
+ int /*source*/,
+ int *interruptType)
+{
+ if (interruptType == NULL) {
+ return kIOReturnBadArgument;
+ }
+
+ *interruptType = kIOInterruptTypeLevel;
+
+ return kIOReturnSuccess;
+}
+
+IOReturn
+PassthruInterruptController::enableInterrupt(IOService */*nub*/,
+ int /*source*/)
+{
+ return kIOReturnSuccess;
+}
+
+IOReturn
+PassthruInterruptController::disableInterrupt(IOService */*nub*/,
+ int /*source*/)
+{
+ return kIOReturnSuccess;
+}
+
+IOReturn
+PassthruInterruptController::causeInterrupt(IOService */*nub*/,
+ int /*source*/)
+{
+ ml_cause_interrupt();
+ return kIOReturnSuccess;
+}
+
+IOReturn
+PassthruInterruptController::handleInterrupt(void */*refCon*/,
+ IOService */*nub*/,
+ int source)
+{
+ panic("handleInterrupt shouldn't be invoked directly");
+}
+
+void
+PassthruInterruptController::externalInterrupt(void)
+{
+ child_handler(child_target, child_refCon, child_nub, 0);
+}