Loading...
iokit/Kernel/IOUserServer.cpp xnu-12377.121.6 xnu-8792.81.2
--- xnu/xnu-12377.121.6/iokit/Kernel/IOUserServer.cpp
+++ xnu/xnu-8792.81.2/iokit/Kernel/IOUserServer.cpp
@@ -43,13 +43,10 @@
 #include <IOKit/IOHibernatePrivate.h>
 #include <IOKit/IOBSD.h>
 #include <IOKit/system.h>
-#include "IOServicePrivate.h"
 #include <IOKit/IOUserServer.h>
 #include <IOKit/IOInterruptEventSource.h>
 #include <IOKit/IOTimerEventSource.h>
-#include <IOKit/IODeviceTreeSupport.h>
 #include <IOKit/pwr_mgt/RootDomain.h>
-#include <IOKit/pwr_mgt/IOPowerConnection.h>
 #include <libkern/c++/OSAllocation.h>
 #include <libkern/c++/OSKext.h>
 #include <libkern/c++/OSSharedPtr.h>
@@ -61,10 +58,7 @@
 #include <sys/proc.h>
 #include <sys/reboot.h>
 #include <sys/codesign.h>
-#include <vm/vm_iokit.h>
-#include <mach_debug/mach_debug_types.h>
 #include "IOKitKernelInternal.h"
-#include "IOServicePMPrivate.h"
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -90,20 +84,11 @@
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-enum{
-	kIOUserServerCheckInTimeoutMSecs = 120000ULL,
-	kIOUserServerCheckInMaxRetry     = 3,
-};
-
 TUNABLE(SInt64, gIODKDebug, "dk", kIODKEnable);
 
 #if DEBUG || DEVELOPMENT
-uint64_t driverkit_checkin_timed_out = 0;
 TUNABLE(bool, disable_dext_crash_reboot, "disable_dext_crash_reboot", 0);
-extern "C" kern_return_t kern_register_userspace_coredump(task_t task, const char * name, boolean_t emergency);
 #endif /* DEBUG || DEVELOPMENT */
-
-extern bool restore_boot;
 
 static OSString       * gIOSystemStateSleepDescriptionKey;
 static const OSSymbol * gIOSystemStateSleepDescriptionReasonKey;
@@ -111,7 +96,6 @@
 
 static OSString       * gIOSystemStateWakeDescriptionKey;
 static const OSSymbol * gIOSystemStateWakeDescriptionWakeReasonKey;
-static const OSSymbol * gIOSystemStateWakeDescriptionContinuousTimeOffsetKey;
 
 static OSString       * gIOSystemStateHaltDescriptionKey;
 static const OSSymbol * gIOSystemStateHaltDescriptionHaltStateKey;
@@ -122,9 +106,6 @@
 extern bool gInUserspaceReboot;
 
 extern void iokit_clear_registered_ports(task_t task);
-
-static IORPCMessage *
-IORPCMessageFromMachReply(IORPCMessageMach * msg);
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -165,6 +146,32 @@
 OSDefineMetaClassAndStructors(IOUserService, IOService)
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+class IOUserUserClient : public IOUserClient
+{
+	OSDeclareDefaultStructors(IOUserUserClient);
+public:
+	task_t          fTask;
+	OSDictionary  * fWorkGroups;
+	OSDictionary  * fEventLinks;
+	IOLock        * fLock;
+
+	IOReturn                   setTask(task_t task);
+	IOReturn                   eventlinkConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
+	IOReturn                   workgroupConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
+
+	virtual bool           init( OSDictionary * dictionary ) APPLE_KEXT_OVERRIDE;
+	virtual void           free() APPLE_KEXT_OVERRIDE;
+	virtual void           stop(IOService * provider) APPLE_KEXT_OVERRIDE;
+	virtual IOReturn       clientClose(void) APPLE_KEXT_OVERRIDE;
+	virtual IOReturn       setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
+	virtual IOReturn       externalMethod(uint32_t selector, IOExternalMethodArguments * args,
+	    IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) APPLE_KEXT_OVERRIDE;
+	virtual IOReturn           clientMemoryForType(UInt32 type,
+	    IOOptionBits * options,
+	    IOMemoryDescriptor ** memory) APPLE_KEXT_OVERRIDE;
+	virtual IOExternalTrap * getTargetAndTrapForIndex( IOService **targetP, UInt32 index ) APPLE_KEXT_OVERRIDE;
+};
 
 OSDefineMetaClassAndStructors(IOUserServerCheckInToken, OSObject);
 OSDefineMetaClassAndStructors(_IOUserServerCheckInCancellationHandler, OSObject);
@@ -399,11 +406,6 @@
 	uint32_t index;
 
 	if (!reserved->uvars) {
-		return kIOReturnError;
-	}
-
-	if (!reserved->uvars->queueArray) {
-		// CopyDispatchQueue should not be called after the service has stopped
 		return kIOReturnError;
 	}
 
@@ -628,7 +630,7 @@
 	}
 	ret = requireMaxBusStall(ns);
 
-	return ret;
+	return kIOReturnSuccess;
 }
 
 #if PRIVATE_WIFI_ONLY
@@ -729,9 +731,6 @@
 	case kIOMemoryMapCacheModeWriteThrough:
 		koptions |= kIOMapWriteThruCache;
 		break;
-	case kIOMemoryMapCacheModeRealTime:
-		koptions |= kIOMapRealTimeCache;
-		break;
 	default:
 		ret = kIOReturnBadArgument;
 	}
@@ -1002,8 +1001,6 @@
 
 	return ret;
 }
-
-#define fInternalState reserved
 
 kern_return_t
 IODMACommand::PrepareForDMA_Impl(
@@ -1029,26 +1026,23 @@
 		return kIOReturnBadArgument;
 	}
 
-	assert(fInternalState->fDextLock);
-	IOLockLock(fInternalState->fDextLock);
-
 	// uses IOMD direction
 	ret = memory->prepare();
 	if (kIOReturnSuccess != ret) {
-		goto exit;
+		return ret;
 	}
 
 	ret = setMemoryDescriptor(memory, false);
 	if (kIOReturnSuccess != ret) {
 		memory->complete();
-		goto exit;
+		return ret;
 	}
 
 	ret = prepare(offset, length);
 	if (kIOReturnSuccess != ret) {
 		clearMemoryDescriptor(false);
 		memory->complete();
-		goto exit;
+		return ret;
 	}
 
 	static_assert(sizeof(IODMACommand::Segment64) == sizeof(IOAddressSegment));
@@ -1057,25 +1051,18 @@
 	genOffset   = 0;
 	ret = genIOVMSegments(&genOffset, segments, &numSegments);
 
-	if (kIOReturnSuccess != ret) {
-		clearMemoryDescriptor(true);
-		memory->complete();
-		goto exit;
-	}
-
-	mdFlags = fMemory->getFlags();
-	lflags  = 0;
-	if (kIODirectionOut & mdFlags) {
-		lflags |= kIOMemoryDirectionOut;
-	}
-	if (kIODirectionIn & mdFlags) {
-		lflags |= kIOMemoryDirectionIn;
-	}
-	*flags = lflags;
-	*segmentsCount = numSegments;
-
-exit:
-	IOLockUnlock(fInternalState->fDextLock);
+	if (kIOReturnSuccess == ret) {
+		mdFlags = fMemory->getFlags();
+		lflags  = 0;
+		if (kIODirectionOut & mdFlags) {
+			lflags |= kIOMemoryDirectionOut;
+		}
+		if (kIODirectionIn & mdFlags) {
+			lflags |= kIOMemoryDirectionIn;
+		}
+		*flags = lflags;
+		*segmentsCount = numSegments;
+	}
 
 	return ret;
 }
@@ -1091,13 +1078,8 @@
 		// no other options currently defined
 		return kIOReturnBadArgument;
 	}
-
-	assert(fInternalState->fDextLock);
-	IOLockLock(fInternalState->fDextLock);
-
-	if (!fInternalState->fPrepared) {
-		ret = kIOReturnNotReady;
-		goto exit;
+	if (!fActive) {
+		return kIOReturnNotReady;
 	}
 
 	md = __DECONST(IOMemoryDescriptor *, fMemory);
@@ -1114,8 +1096,6 @@
 			ret = completeRet;
 		}
 	}
-exit:
-	IOLockUnlock(fInternalState->fDextLock);
 
 	return ret;
 }
@@ -1468,11 +1448,7 @@
 	bool           canceled;
 };
 
-void
-IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
-    IOService * nub, int source );
-
-void
+static void
 IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
     IOService * nub, int source )
 {
@@ -1564,8 +1540,11 @@
 void
 IOInterruptDispatchSource::free()
 {
+	IOReturn ret;
+
 	if (ivars && ivars->provider) {
-		(void) ivars->provider->unregisterInterrupt(ivars->intIndex);
+		ret = ivars->provider->unregisterInterrupt(ivars->intIndex);
+		assert(kIOReturnSuccess == ret);
 		ivars->provider->release();
 	}
 
@@ -1608,11 +1587,6 @@
 	if (enable == ivars->enable) {
 		return kIOReturnSuccess;
 	}
-
-	if (ivars->canceled) {
-		return kIOReturnUnsupported;
-	}
-	assert(ivars->provider != NULL);
 
 	if (enable) {
 		is = IOSimpleLockLockDisableInterrupt(ivars->lock);
@@ -1634,7 +1608,6 @@
 	IODispatchSourceCancelHandler handler)
 {
 	IOInterruptState is;
-	IOService * provider;
 
 	is = IOSimpleLockLockDisableInterrupt(ivars->lock);
 	ivars->canceled = true;
@@ -1642,16 +1615,7 @@
 		thread_wakeup_thread((event_t) ivars, ivars->waiter);
 		ivars->waiter = NULL;
 	}
-	provider = ivars->provider;
-	if (provider) {
-		ivars->provider = NULL;
-	}
 	IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
-
-	if (provider) {
-		(void) provider->unregisterInterrupt(ivars->intIndex);
-		provider->release();
-	}
 
 	return kIOReturnSuccess;
 }
@@ -1811,7 +1775,7 @@
 	inst->ivars->notifier = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0 /*priority*/,
 	    ^bool (IOService * newService, IONotifier * notifier) {
 		bool         notifyReady = false;
-		IONotifier * interest = NULL;
+		IONotifier * interest;
 		OSObject   * serverName;
 		bool         okToUse;
 
@@ -1819,78 +1783,41 @@
 		okToUse = (serverName && inst->ivars->serverName->isEqualTo(serverName));
 		OSSafeReleaseNULL(serverName);
 		if (!okToUse) {
-		        OSObject * prop;
-		        OSObject * str;
-
-		        if (!newService->reserved->uvars || !newService->reserved->uvars->userServer) {
-		                return false;
-			}
-		        str = OSString::withCStringNoCopy(kIODriverKitAllowsPublishEntitlementsKey);
-		        if (!str) {
-		                return false;
-			}
-		        okToUse = newService->reserved->uvars->userServer->checkEntitlements(str, NULL, NULL);
-		        if (!okToUse) {
-		                if (kIODKLogSetup & gIODKDebug) {
-		                        DKLOG(DKS ": publisher entitlements check failed\n", DKN(newService));
-				}
-		                return false;
-			}
-		        prop = newService->copyProperty(kIODriverKitPublishEntitlementsKey);
-		        if (!prop) {
-		                return false;
-			}
-		        okToUse = us->checkEntitlements(prop, NULL, NULL);
-		        if (!okToUse) {
-		                if (kIODKLogSetup & gIODKDebug) {
-		                        DKLOG(DKS ": subscriber entitlements check failed\n", DKN(newService));
-				}
-		                return false;
-			}
+		        return false;
 		}
 
 		IOLockLock(inst->ivars->lock);
 		notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeMatched]->getCount());
 		inst->ivars->pending[kIOServiceNotificationTypeMatched]->setObject(newService);
-		bool needInterest = (NULL == inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService));
 		IOLockUnlock(inst->ivars->lock);
 
-		if (needInterest) {
-		        interest = newService->registerInterest(gIOGeneralInterest,
-		        ^IOReturn (uint32_t messageType, IOService * provider,
-		        void * messageArgument, size_t argSize) {
-				IONotifier * interest;
-				bool         notifyReady = false;
-
-				// after the notifier remove, IOServiceNotificationDispatchSource::free
-				// will not wait for this code to complete
-				if (!inst->taggedTryRetain(NULL)) {
-				        return kIOReturnSuccess;
+		interest = newService->registerInterest(gIOGeneralInterest,
+		^IOReturn (uint32_t messageType, IOService * provider,
+		void * messageArgument, size_t argSize) {
+			IONotifier * interest;
+			bool         notifyReady = false;
+
+			switch (messageType) {
+			case kIOMessageServiceIsTerminated:
+				IOLockLock(inst->ivars->lock);
+				notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeTerminated]->getCount());
+				inst->ivars->pending[kIOServiceNotificationTypeTerminated]->setObject(provider);
+				if (inst->ivars->interestNotifiers != NULL) {
+				        interest = (typeof(interest))inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService);
+				        assert(interest);
+				        interest->remove();
+				        inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
 				}
-
-				switch (messageType) {
-				case kIOMessageServiceIsTerminated:
-					IOLockLock(inst->ivars->lock);
-					notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeTerminated]->getCount());
-					inst->ivars->pending[kIOServiceNotificationTypeTerminated]->setObject(provider);
-					if (inst->ivars->interestNotifiers != NULL) {
-					        interest = (typeof(interest))inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService);
-					        assert(interest);
-					        interest->remove();
-					        inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
-					}
-					IOLockUnlock(inst->ivars->lock);
-					break;
-				default:
-					break;
-				}
-				if (notifyReady && inst->ivars->action) {
-				        inst->ServiceNotificationReady(inst->ivars->action);
-				}
-				inst->release();
-				return kIOReturnSuccess;
-			});
-		}
+				IOLockUnlock(inst->ivars->lock);
+				break;
+			default:
+				break;
+			}
+			if (notifyReady && inst->ivars->action) {
+			        inst->ServiceNotificationReady(inst->ivars->action);
+			}
+			return kIOReturnSuccess;
+		});
 		if (interest) {
 		        IOLockLock(inst->ivars->lock);
 		        inst->ivars->interestNotifiers->setObject((const OSSymbol *) newService, interest);
@@ -1987,7 +1914,6 @@
 		for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
 			OSSafeReleaseNULL(ivars->pending[idx]);
 		}
-		OSSafeReleaseNULL(ivars->action);
 		if (ivars->lock) {
 			IOLockFree(ivars->lock);
 			ivars->lock = NULL;
@@ -2311,21 +2237,6 @@
 }
 
 kern_return_t
-IOUserServer::Panic_Impl(const char * reason)
-{
-	if (isPlatformDriver()) {
-		if (strnlen(reason, kIOUserServrMaxPanicReasonLength) == kIOUserServrMaxPanicReasonLength) {
-			// Invalid panic message, panic anyways
-			panic("%s: dext requested panic", getName());
-		} else {
-			panic("%s: dext requested panic: \"%s\"", getName(), reason);
-		}
-		return kIOReturnSuccess;
-	}
-	return kIOReturnNotPermitted;
-}
-
-kern_return_t
 IOUserServer::RegisterService_Impl()
 {
 	kern_return_t ret = IOService::RegisterService_Impl();
@@ -2391,10 +2302,8 @@
 	if (MACH_PORT_NULL != ivars->serverPort) {
 		return kIOReturnNotReady;
 	}
-	ivars->serverPort = ipc_port_copy_send_mqueue(port);
-	if (ivars->serverPort == MACH_PORT_NULL) {
-		return kIOReturnBadArgument;
-	}
+
+	ivars->serverPort = port;
 	return kIOReturnSuccess;
 }
 
@@ -2444,7 +2353,7 @@
 	IORPCMessage    * message;
 
 	assert(rpc.sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
-	message = rpc.kernelContent;
+	message = IORPCMessageFromMach(rpc.message, false);
 	if (!message) {
 		return kIOReturnIPCError;
 	}
@@ -2614,19 +2523,16 @@
 	fStatistics = statistics;
 }
 
-IOReturn
+void
 IOUserServer::setCheckInToken(IOUserServerCheckInToken *token)
 {
-	IOReturn ret = kIOReturnError;
 	if (token != NULL && fCheckInToken == NULL) {
 		token->retain();
 		fCheckInToken = token;
-		ret = fCheckInToken->complete();
 		iokit_clear_registered_ports(fOwningTask);
 	} else {
 		printf("%s: failed to set check in token. token=%p, fCheckInToken=%p\n", __FUNCTION__, token, fCheckInToken);
 	}
-	return ret;
 }
 
 bool
@@ -2634,6 +2540,9 @@
 {
 	if (token != NULL) {
 		bool result = token == fCheckInToken;
+		if (result) {
+			fCheckInToken->complete();
+		}
 		return result;
 	} else {
 		printf("%s: null check in token\n", __FUNCTION__);
@@ -2671,7 +2580,7 @@
 		}
 	}
 
-	bool allPresent __block = false;
+	bool allPresent __block;
 	prop->iterateObjects(^bool (OSObject * object) {
 		allPresent = false;
 		object->iterateObjects(^bool (OSObject * object) {
@@ -2701,12 +2610,6 @@
 }
 
 bool
-IOUserServer::checkEntitlements(OSObject * prop, IOService * provider, IOService * dext)
-{
-	return checkEntitlements(fEntitlements, prop, provider, dext);
-}
-
-bool
 IOUserServer::checkEntitlements(IOService * provider, IOService * dext)
 {
 	OSObject     * prop;
@@ -2735,7 +2638,7 @@
 IOReturn
 IOUserServer::exit(const char * reason)
 {
-	DKLOG(DKS "::exit(%s)\n", DKN(this), reason);
+	DKLOG("%s::exit(%s)\n", getName(), reason);
 	Exit(reason);
 	return kIOReturnSuccess;
 }
@@ -2745,30 +2648,11 @@
 {
 	IOReturn ret = kIOReturnError;
 	if (fOwningTask != NULL) {
-		DKLOG(DKS"::kill(%s)\n", DKN(this), reason);
-		proc_t unsafe_proc = (proc_t)get_bsdtask_info(fOwningTask);
-		proc_t p = proc_ref_nowait(unsafe_proc);
-		if (p) {
-			taskbsd_kill_and_release(p);
-		}
+		DKLOG("%s::kill(%s)\n", getName(), reason);
+		task_bsdtask_kill(fOwningTask);
 		ret = kIOReturnSuccess;
 	}
 	return ret;
-}
-
-void
-IOUserServer::emergencyPanicCoreDumpEnable()
-{
-#if DEVELOPMENT || DEBUG
-	if (isPlatformDriver()) {
-		// Enable coredump for the first party dext that is causing an imminent panic
-		// This is enabled on non-release without requiring an entitlement,
-		// so this coredump has only a generic name
-		char core_name[MACH_CORE_FILEHEADER_NAMELEN];
-		snprintf(core_name, sizeof(core_name), "dext-%d", pid_from_task(fOwningTask));
-		kern_register_userspace_coredump(fOwningTask, core_name, TRUE);
-	}
-#endif /* DEVELOPMENT || DEBUG */
 }
 
 OSObjectUserVars *
@@ -2925,7 +2809,6 @@
 	OSObjectUserVars * uvars;
 	uint32_t           idx;
 	ipc_port_t         sendPort;
-	bool               serviceInactive;
 
 	OSObject_Instantiate_Rpl_Content * reply;
 	IODispatchQueue ** unboundedQueueArray = NULL;
@@ -2946,14 +2829,7 @@
 		resultFlags |= kOSObjectRPCKernel;
 		resultFlags |= kOSObjectRPCRemote;
 	} else {
-		serviceInactive = false;
-		if (service->lockForArbitration()) {
-			if (service->isInactive() && (service->__state[1] & kIOServiceStartState) == 0) {
-				serviceInactive = true;
-			}
-			service->unlockForArbitration();
-		}
-		if (serviceInactive) {
+		if (service->isInactive()) {
 			DKLOG(DKS "::instantiate inactive\n", DKN(service));
 			return kIOReturnOffline;
 		}
@@ -2973,7 +2849,6 @@
 				return kIOReturnError;
 			}
 			IOLockLock(service->reserved->uvars->userServer->fLock);
-			service->reserved->uvars->instantiated = true;
 			userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str);
 			IOLockUnlock(service->reserved->uvars->userServer->fLock);
 		}
@@ -3123,7 +2998,7 @@
 	machReply->msgh.msgh_size                  = replySize;
 	machReply->msgh_body.msgh_descriptor_count = queueCount;
 
-	reply = (typeof(reply))IORPCMessageFromMachReply(machReply);
+	reply = (typeof(reply))IORPCMessageFromMach(machReply, true);
 	if (!reply) {
 		return kIOReturnIPCError;
 	}
@@ -3151,7 +3026,7 @@
 	IOReturn       ret;
 	IORPCMessage * message;
 
-	message = rpc.kernelContent;
+	message = IORPCMessageFromMach(rpc.message, false);
 	if (!message) {
 		return kIOReturnIPCError;
 	}
@@ -3159,15 +3034,15 @@
 	if (OSObject_Instantiate_ID == message->msgid) {
 		ret = objectInstantiate(obj, rpc, message);
 		if (kIOReturnSuccess != ret) {
-			DKLOG(DKS ": %s: instantiate failed 0x%x\n", DKN(this), obj->getMetaClass()->getClassName(), ret);
+			DKLOG("%s: instantiate failed 0x%x\n", obj->getMetaClass()->getClassName(), ret);
 		}
 	} else {
 		if (kIODKLogIPC & gIODKDebug) {
-			DKLOG(DKS ": %s::Dispatch kernel 0x%qx\n", DKN(this), obj->getMetaClass()->getClassName(), message->msgid);
+			DKLOG("%s::Dispatch kernel 0x%qx\n", obj->getMetaClass()->getClassName(), message->msgid);
 		}
 		ret = obj->Dispatch(rpc);
 		if (kIODKLogIPC & gIODKDebug) {
-			DKLOG(DKS ": %s::Dispatch kernel 0x%qx result 0x%x\n", DKN(this), obj->getMetaClass()->getClassName(), message->msgid, ret);
+			DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj->getMetaClass()->getClassName(), message->msgid, ret);
 		}
 	}
 
@@ -3223,10 +3098,7 @@
 		OSSafeReleaseNULL(object);
 		return KERN_INVALID_NAME;
 	}
-
-	IORPCMessage * message = (typeof(message))ikm_udata_from_header(requestkmsg);
-
-	ret = server->server(requestkmsg, message, pReply);
+	ret = server->server(requestkmsg, pReply);
 	object->release();
 
 	return ret;
@@ -3240,12 +3112,13 @@
 static_assert(MAX_UEXT_REPLY_SIZE + MAX_TRAILER_SIZE <= KALLOC_SAFE_ALLOC_SIZE);
 
 kern_return_t
-IOUserServer::server(ipc_kmsg_t requestkmsg, IORPCMessage * message, ipc_kmsg_t * pReply)
+IOUserServer::server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
 {
 	kern_return_t      ret;
 	mach_msg_size_t    replyAlloc;
 	ipc_kmsg_t         replykmsg;
 	IORPCMessageMach * msgin;
+	IORPCMessage     * message;
 	IORPCMessageMach * msgout;
 	IORPCMessage     * reply;
 	uint32_t           replySize;
@@ -3269,6 +3142,7 @@
 	if (!(MACH_MSGH_BITS_COMPLEX & msgin->msgh.msgh_bits)) {
 		msgin->msgh_body.msgh_descriptor_count = 0;
 	}
+	message = IORPCMessageFromMach(msgin, false);
 	if (!message) {
 		return kIOReturnIPCError;
 	}
@@ -3280,9 +3154,6 @@
 		if (kIODKLogIPC & gIODKDebug) {
 			DKLOG("UEXT copyin(0x%x) %x\n", ret, msgin->msgh.msgh_id);
 		}
-		// release objects and ports
-		consumeObjects(msgin, message, msgin->msgh.msgh_size);
-		copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
 		return KERN_NOT_SUPPORTED;
 	}
 
@@ -3303,22 +3174,18 @@
 	assert(oneway || (MACH_PORT_NULL != msgin->msgh.msgh_local_port));
 
 	replyAlloc = oneway ? 0 : MAX_UEXT_REPLY_SIZE;
-
-
-
-
 	if (replyAlloc) {
 		/*
 		 * Same as:
-		 *    ipc_kmsg_alloc(MAX_UEXT_REPLY_SIZE_MACH, MAX_UEXT_REPLY_SIZE_MESSAGE,
+		 *    ipc_kmsg_alloc(replyAlloc, 0,
 		 *        IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO | IPC_KMSG_ALLOC_LINEAR |
 		 *        IPC_KMSG_ALLOC_NOFAIL);
 		 */
-		replykmsg = ipc_kmsg_alloc_uext_reply(MAX_UEXT_REPLY_SIZE);
+		replykmsg = ipc_kmsg_alloc_uext_reply(replyAlloc);
 		msgout = (typeof(msgout))ikm_header(replykmsg);
 	}
 
-	IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc, .kernelContent = message };
+	IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc };
 
 	if (object) {
 		kern_allocation_name_t prior;
@@ -3339,7 +3206,7 @@
 	}
 
 	// release objects
-	consumeObjects(msgin, message, msgin->msgh.msgh_size);
+	consumeObjects(message, msgin->msgh.msgh_size);
 
 	// release ports
 	copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
@@ -3347,7 +3214,7 @@
 	if (!oneway) {
 		if (kIOReturnSuccess == ret) {
 			replySize = msgout->msgh.msgh_size;
-			reply = IORPCMessageFromMachReply(msgout);
+			reply = IORPCMessageFromMach(msgout, true);
 			if (!reply) {
 				ret = kIOReturnIPCError;
 			} else {
@@ -3359,7 +3226,7 @@
 
 			msgout->msgh_body.msgh_descriptor_count = 0;
 			msgout->msgh.msgh_id                    = kIORPCVersionCurrentReply;
-			errorMsg = (typeof(errorMsg))IORPCMessageFromMachReply(msgout);
+			errorMsg = (typeof(errorMsg))IORPCMessageFromMach(msgout, true);
 			errorMsg->hdr.msgid      = message->msgid;
 			errorMsg->hdr.flags      = kIORPCMessageOneway | kIORPCMessageError;
 			errorMsg->hdr.objectRefs = 0;
@@ -3384,24 +3251,8 @@
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-static inline uint32_t
-MAX_OBJECT_COUNT(IORPCMessageMach *mach, size_t size, IORPCMessage *message __unused)
-{
-	assert(mach->msgh.msgh_size == size);
-	size_t used_size;
-	size_t remaining_size;
-	if (os_mul_and_add_overflow(
-		    mach->msgh_body.msgh_descriptor_count,
-		    sizeof(mach_msg_port_descriptor_t),
-		    sizeof(mach->msgh) + sizeof(mach->msgh_body) + offsetof(IORPCMessage, objects[0]),
-		    &used_size)) {
-		return 0;
-	}
-	if (os_sub_overflow(size, used_size, &remaining_size)) {
-		return 0;
-	}
-	return (uint32_t)(remaining_size / sizeof(OSObjectRef));
-}
+#define MAX_OBJECT_COUNT(mach, size, message) \
+	((uint32_t)(((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))))
 
 #pragma pack(push, 4)
 struct UEXTTrapReply {
@@ -3483,7 +3334,6 @@
 	rpc.sendSize  = mach->msgh.msgh_size;
 	rpc.reply     = (IORPCMessageMach *) (p + inSize);
 	rpc.replySize = ((uint32_t) (sizeof(buffer.buffer) - inSize));    // inSize was checked
-	rpc.kernelContent = message;
 
 	message->objects[0] = 0;
 	if ((action = OSDynamicCast(OSAction, object))) {
@@ -3525,7 +3375,7 @@
 			if (rpc.reply->msgh_body.msgh_descriptor_count) {
 				return kIOReturnIPCError;
 			}
-			reply = IORPCMessageFromMachReply(rpc.reply);
+			reply = IORPCMessageFromMach(rpc.reply, rpc.reply->msgh.msgh_size);
 			if (!reply) {
 				return kIOReturnIPCError;
 			}
@@ -3576,7 +3426,7 @@
 
 	assert(sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
 
-	message = rpc.kernelContent;
+	message = IORPCMessageFromMach(mach, false);
 	if (!message) {
 		return kIOReturnIPCError;
 	}
@@ -3620,7 +3470,8 @@
 
 	if (oneway) {
 		ret = kernel_mach_msg_send(&mach->msgh, sendSize,
-		    MACH_SEND_KERNEL_DEFAULT, 0, &message_moved);
+		    MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_NOIMPORTANCE,
+		    0, &message_moved);
 	} else {
 		assert(replySize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
 		ret = kernel_mach_msg_rpc(&mach->msgh, sendSize, replySize, FALSE, &message_moved);
@@ -3648,7 +3499,7 @@
 			if (!(MACH_MSGH_BITS_COMPLEX & mach->msgh.msgh_bits)) {
 				mach->msgh_body.msgh_descriptor_count = 0;
 			}
-			message = IORPCMessageFromMachReply(mach);
+			message = IORPCMessageFromMach(mach, true);
 			if (!message) {
 				ret = kIOReturnIPCError;
 			} else if (message->msgid != msgid) {
@@ -3661,10 +3512,6 @@
 					if (kIODKLogIPC & gIODKDebug) {
 						DKLOG("rpc copyin(0x%x) %x\n", ret, mach->msgh.msgh_id);
 					}
-					if (!isError) {
-						consumeObjects(mach, message, replySize);
-						copyInObjects(mach, message, replySize, false, true);
-					}
 					return KERN_NOT_SUPPORTED;
 				}
 				if (isError) {
@@ -3680,15 +3527,14 @@
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-static IORPCMessage *
-IORPCMessageFromMachReply(IORPCMessageMach * msg)
+IORPCMessage *
+IORPCMessageFromMach(IORPCMessageMach * msg, bool reply)
 {
 	mach_msg_size_t              idx, count;
 	mach_msg_port_descriptor_t * desc;
 	mach_msg_port_descriptor_t * maxDesc;
 	size_t                       size, msgsize;
 	bool                         upgrade;
-	bool                         reply = true;
 
 	msgsize = msg->msgh.msgh_size;
 	count   = msg->msgh_body.msgh_descriptor_count;
@@ -3723,13 +3569,24 @@
 ipc_port_t
 IOUserServer::copySendRightForObject(OSObject * object, ipc_kobject_type_t type)
 {
-	return iokit_port_make_send_for_object(object, type);
+	ipc_port_t port;
+	ipc_port_t sendPort = NULL;
+
+	port = iokit_port_for_object(object, type);
+	if (port) {
+		sendPort = ipc_kobject_make_send(port, (ipc_kobject_t)object, type);
+		iokit_release_port(port);
+	}
+
+	return sendPort;
 }
 
 OSObject *
 IOUserServer::copyObjectForSendRight(ipc_port_t port, ipc_kobject_type_t type)
 {
-	return iokit_lookup_io_object(port, type);
+	OSObject * object;
+	object = iokit_lookup_io_object(port, type);
+	return object;
 }
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -3929,14 +3786,8 @@
 		return kIOReturnBadArgument;
 	}
 
+	desc = &mach->objects[0];
 	for (idx = 0; idx < refs; idx++) {
-		message->objects[idx] = (OSObjectRef) NULL;
-	}
-
-	desc = &mach->objects[0];
-	for (idx = 0; idx < mach->msgh_body.msgh_descriptor_count; idx++) {
-		bool isObjectPort = idx < refs;
-
 		switch (desc->type) {
 		case MACH_MSG_PORT_DESCRIPTOR:
 			descsize = sizeof(mach_msg_port_descriptor_t);
@@ -3944,7 +3795,7 @@
 			object = NULL;
 			port = desc->name;
 			if (port) {
-				if (isObjectPort && copyObjects) {
+				if (copyObjects) {
 					object = copyObjectForSendRight(port, IKOT_UEXT_OBJECT);
 					if (!object) {
 						descsize = -1UL;
@@ -3953,7 +3804,6 @@
 				}
 				if (consumePorts) {
 					ipc_port_release_send(port);
-					desc->name = MACH_PORT_NULL;
 				}
 			}
 			break;
@@ -3963,7 +3813,7 @@
 			ool = (typeof(ool))desc;
 
 			object = NULL;
-			if (isObjectPort && copyObjects && ool->size && ool->address) {
+			if (copyObjects && ool->size && ool->address) {
 				kr = vm_map_copyout(kernel_map, &copyoutdata, (vm_map_copy_t) ool->address);
 				if (KERN_SUCCESS == kr) {
 					object = OSUnserializeXML((const char *) copyoutdata, ool->size);
@@ -3987,7 +3837,7 @@
 		if (-1UL == descsize) {
 			break;
 		}
-		if (isObjectPort && copyObjects) {
+		if (copyObjects) {
 			message->objects[idx] = (OSObjectRef) object;
 		}
 		desc = (typeof(desc))(((uintptr_t) desc) + descsize);
@@ -4007,20 +3857,12 @@
 }
 
 IOReturn
-IOUserServer::consumeObjects(IORPCMessageMach *mach, IORPCMessage * message, size_t messageSize)
+IOUserServer::consumeObjects(IORPCMessage * message, size_t messageSize)
 {
 	uint64_t    refs, idx;
 	OSObject  * object;
 
 	refs   = message->objectRefs;
-	uint32_t maxObjectCount = MAX_OBJECT_COUNT(mach, messageSize, message);
-	if (refs > mach->msgh_body.msgh_descriptor_count) {
-		return kIOReturnBadArgument;
-	}
-	if (refs > maxObjectCount) {
-		return kIOReturnBadArgument;
-	}
-
 	for (idx = 0; idx < refs; idx++) {
 		object = (OSObject *) message->objects[idx];
 		if (object) {
@@ -4034,8 +3876,18 @@
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-static kern_return_t
-acknowledgeSetPowerState(IOService * service);
+static void
+reboot_kernel_async_helper(thread_call_param_t p0 __unused, thread_call_param_t p1 __unused)
+{
+	reboot_kernel(RB_AUTOBOOT, NULL);
+}
+
+static void
+reboot_kernel_async()
+{
+	thread_call_t reboot_call = thread_call_allocate(reboot_kernel_async_helper, NULL);
+	thread_call_enter(reboot_call);
+}
 
 bool
 IOUserServer::finalize(IOOptionBits options)
@@ -4043,7 +3895,7 @@
 	OSArray   * services;
 
 	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG(DKS "::finalize(%p)\n", DKN(this), this);
+		DKLOG("%s::finalize(%p)\n", getName(), this);
 	}
 
 	IOLockLock(gIOUserServerLock);
@@ -4063,11 +3915,11 @@
 		if (can_rematch) {
 			terminateFlags |= kIOServiceTerminateWithRematchCurrentDext;
 		} else {
-			DKLOG(DKS "::finalize(%p) dext was replaced, do not rematch current dext\n", DKN(this), this);
+			DKLOG("%s::finalize(%p) dext was replaced, do not rematch current dext\n", getName(), this);
 		}
 	} else {
 		terminateFlags |= kIOServiceTerminateWithRematchCurrentDext;
-		DKLOG(DKS "::finalize(%p) could not find fCheckInToken\n", DKN(this), this);
+		DKLOG("%s::finalize(%p) could not find fCheckInToken\n", getName(), this);
 	}
 
 	if (services) {
@@ -4076,11 +3928,10 @@
 			IOService * nextService;
 			IOService * provider;
 			bool        started = false;
-			bool        instantiated = false;
 
 			nextService = (IOService *) obj;
 			if (kIODKLogSetup & gIODKDebug) {
-			        DKLOG(DKS "::terminate(" DKS ")\n", DKN(this), DKN(nextService));
+			        DKLOG("%s::terminate(" DKS ")\n", getName(), DKN(nextService));
 			}
 			if (nextService->reserved->uvars) {
 			        IOUserClient * nextUserClient = OSDynamicCast(IOUserClient, nextService);
@@ -4088,9 +3939,7 @@
 			        if (nextUserClient) {
 			                nextUserClient->setTerminateDefer(provider, false);
 				}
-			        (void)::acknowledgeSetPowerState(nextService);
 			        started = nextService->reserved->uvars->started;
-			        instantiated = nextService->reserved->uvars->instantiated;
 			        nextService->reserved->uvars->serverDied = true;
 
 			        serviceDidStop(nextService, provider);
@@ -4098,22 +3947,11 @@
 			                provider->resetRematchProperties();
 				}
 			        if (started) {
-			                IOService * provider = nextService;
-			                while ((provider = provider->getProvider())) {
-			                        if (-1U != services->getNextIndexOfObject(provider, 0)) {
-			                                break;
-						}
-					}
-			                if (!provider) {
-			                        // this service is the root of the set, so only terminate it
-			                        nextService->terminate(terminateFlags);
-					}
+			                nextService->terminate(terminateFlags);
 				}
 			}
-			if (!started || !instantiated) {
-			        DKLOG(DKS "::terminate(" DKS ") server exit before start() instantiated %d\n", DKN(this), DKN(nextService), instantiated);
-			        // Override started since we are forcing serviceStop to happen
-			        nextService->reserved->uvars->started = true;
+			if (!started) {
+			        DKLOG("%s::terminate(" DKS ") server exit before start()\n", getName(), DKN(nextService));
 			        serviceStop(nextService, NULL);
 			}
 			return false;
@@ -4203,7 +4041,6 @@
 	if (csproc_get_validation_category(current_proc(), &inst->fCSValidationCategory) != KERN_SUCCESS) {
 		inst->fCSValidationCategory = CS_VALIDATION_CATEGORY_INVALID;
 	}
-	inst->fWorkLoop = IOWorkLoop::workLoop();
 
 	inst->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue);
 	inst->setProperty(kIOUserClientDefaultLockingSetPropertiesKey, kOSBooleanTrue);
@@ -4278,15 +4115,18 @@
 {
 	OSArray   * services;
 	bool __block unexpectedExit = false;
+	bool powerManagementFailed = false;
 
 	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG(DKS "::clientClose(%p)\n", DKN(this), this);
-	}
+		DKLOG("%s::clientClose(%p)\n", getName(), this);
+	}
+
 	services = NULL;
 	IOLockLock(fLock);
 	if (fServices) {
 		services = OSArray::withArray(fServices);
 	}
+	powerManagementFailed = fPowerManagementFailed;
 	IOLockUnlock(fLock);
 
 	// if this was a an expected exit, termination and stop should have detached at this
@@ -4311,9 +4151,6 @@
 			        if (kIODKLogSetup & gIODKDebug) {
 			                DKLOG(DKS "::ClientCrashed(" DKS ")\n", DKN(provider), DKN(nextService));
 				}
-			        if (unexpectedExit) {
-			                provider->unregisterAllInterrupts();
-				}
 			        provider->ClientCrashed(nextService, 0);
 			}
 			return false;
@@ -4323,25 +4160,20 @@
 
 	if (unexpectedExit &&
 	    !gInUserspaceReboot &&
-	    (fTaskCrashReason != OS_REASON_NULL && fTaskCrashReason->osr_namespace != OS_REASON_JETSAM && fTaskCrashReason->osr_namespace != OS_REASON_RUNNINGBOARD) &&
+	    !powerManagementFailed &&
+	    (fTaskCrashReason == OS_REASON_NULL || (fTaskCrashReason->osr_namespace != OS_REASON_JETSAM && fTaskCrashReason->osr_namespace != OS_REASON_RUNNINGBOARD)) &&
 	    fStatistics != NULL) {
 		OSDextCrashPolicy policy = fStatistics->recordCrash();
-		bool allowPanic;
+		bool allowReboot;
 #if DEVELOPMENT || DEBUG
-		allowPanic = !restore_boot && fPlatformDriver && fEntitlements->getObject(gIODriverKitTestDriverEntitlementKey) != kOSBooleanTrue && !disable_dext_crash_reboot;
+		allowReboot = fPlatformDriver && fEntitlements->getObject(gIODriverKitTestDriverEntitlementKey) != kOSBooleanTrue && !disable_dext_crash_reboot;
 #else
-		allowPanic = !restore_boot && fPlatformDriver;
+		allowReboot = fPlatformDriver;
 #endif /* DEVELOPMENT || DEBUG */
 
-		if (policy == kOSDextCrashPolicyReboot && allowPanic) {
-			emergencyPanicCoreDumpEnable();
-			panic("Driver %s has crashed too many times (reason %u:%llu)\n",
-			    getName(), fTaskCrashReason->osr_namespace, fTaskCrashReason->osr_code);
-		}
-
-		IOPMrootDomain *rootDomain = IOService::getPMRootDomain();
-		if (rootDomain) {
-			rootDomain->requestRunMode(kIOPMRunModeFullWake);
+		if (policy == kOSDextCrashPolicyReboot && allowReboot) {
+			IOLog("Driver %s has crashed too many times. Rebooting.\n", getName());
+			reboot_kernel_async();
 		}
 	}
 
@@ -4373,12 +4205,6 @@
 	if (fInterruptLock) {
 		IOSimpleLockFree(fInterruptLock);
 	}
-}
-
-IOWorkLoop *
-IOUserServer::getWorkLoop() const
-{
-	return fWorkLoop;
 }
 
 void
@@ -4404,7 +4230,6 @@
 	if (fTaskCrashReason != OS_REASON_NULL) {
 		os_reason_free(fTaskCrashReason);
 	}
-	OSSafeReleaseNULL(fWorkLoop);
 	IOUserClient::free();
 }
 
@@ -4424,7 +4249,7 @@
 	}
 
 	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG(DKS "::registerClass %s, %d, %d\n", DKN(this), desc->name, desc->queueNamesSize, desc->methodNamesSize);
+		DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc->name, desc->queueNamesSize, desc->methodNamesSize);
 	}
 
 	if (desc->descriptionSize != size) {
@@ -4606,8 +4431,7 @@
 IOReturn
 IOUserServer::externalMethodStart(OSObject * target, void * reference, IOExternalMethodArguments * args)
 {
-	mach_port_name_t portname = 0;
-	IOReturn ret = kIOReturnSuccess;
+	mach_port_name_t portname;
 
 	IOUserServer * me = (typeof(me))target;
 
@@ -4616,18 +4440,17 @@
 		OSObject * obj = iokit_lookup_object_with_port_name(checkInPortName, IKOT_IOKIT_IDENT, me->fOwningTask);
 		IOUserServerCheckInToken * retrievedToken = OSDynamicCast(IOUserServerCheckInToken, obj);
 		if (retrievedToken != NULL) {
-			ret = me->setCheckInToken(retrievedToken);
+			me->setCheckInToken(retrievedToken);
 		} else {
-			ret = kIOReturnBadArgument;
+			OSSafeReleaseNULL(obj);
+			return kIOReturnBadArgument;
 		}
 		OSSafeReleaseNULL(obj);
 	}
-	if (ret == kIOReturnSuccess) {
-		portname = iokit_make_send_right(me->fOwningTask, me, IKOT_UEXT_OBJECT);
-		assert(portname);
-	}
+	portname = iokit_make_send_right(me->fOwningTask, me, IKOT_UEXT_OBJECT);
+	assert(portname);
 	args->scalarOutput[0] = portname;
-	return ret;
+	return kIOReturnSuccess;
 }
 IOExternalTrap *
 IOUserServer::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
@@ -4643,12 +4466,6 @@
 }
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-void
-IOUserServer::pageout()
-{
-	fPageout = 1;
-}
 
 IOReturn
 IOUserServer::serviceAttach(IOService * service, IOService * provider)
@@ -4666,7 +4483,6 @@
 	vars->userServer = this;
 	vars->userServer->retain();
 	vars->uvarsLock = IOLockAlloc();
-	vars->originalProperties = service->dictionaryWithProperties();
 	IOLockLock(fLock);
 	if (-1U == fServices->getNextIndexOfObject(service, 0)) {
 		fServices->setObject(service);
@@ -4726,21 +4542,20 @@
 		if (ok) {
 			ret = LoadModule(execPath);
 			if (kIODKLogSetup & gIODKDebug) {
-				DKLOG(DKS "::LoadModule 0x%x %s\n", DKN(this), ret, execPath);
+				DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret, execPath);
 			}
 		}
 	}
 	OSSafeReleaseNULL(prop);
 
 	ret = kIOReturnSuccess;
-	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG(DKS "::serviceAttach(" DKS ", " DKS ")\n", DKN(this), DKN(service), DKN(provider));
-	}
 
 	return ret;
 }
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
 
 IOReturn
 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
@@ -4771,18 +4586,15 @@
 
 	*handler = NULL;
 	ret = service->_NewUserClient(type, entitlements, &uc);
-	if (kIOReturnSuccess != ret || uc == NULL) {
-		OSSafeReleaseNULL(uc);
+	if (kIOReturnSuccess != ret) {
 		OSSafeReleaseNULL(entitlements);
 		return ret;
 	}
 	userUC = OSDynamicCast(IOUserUserClient, uc);
 	if (!userUC) {
-		if (uc) {
-			uc->terminate(kIOServiceTerminateNeedWillTerminate);
-			uc->setTerminateDefer(service, false);
-			OSSafeReleaseNULL(uc);
-		}
+		uc->terminate(kIOServiceTerminateNeedWillTerminate);
+		uc->setTerminateDefer(service, false);
+		OSSafeReleaseNULL(uc);
 		OSSafeReleaseNULL(entitlements);
 		return kIOReturnUnsupported;
 	}
@@ -4907,17 +4719,13 @@
 	    .outputPowerCharacter   = kIOPMLowPower,
 	    .inputPowerRequirement  = kIOPMLowPower},
 	{   .version                = kIOPMPowerStateVersion1,
-	    .capabilityFlags        = kIOPMAOTPower,
-	    .outputPowerCharacter   = kIOPMAOTPower,
-	    .inputPowerRequirement  = kIOPMAOTPower},
-	{   .version                = kIOPMPowerStateVersion1,
 	    .capabilityFlags        = kIOPMPowerOn,
 	    .outputPowerCharacter   = kIOPMPowerOn,
 	    .inputPowerRequirement  = kIOPMPowerOn},
 };
 
 enum {
-	kUserServerMaxPowerState    = 3
+	kUserServerMaxPowerState    = 2
 };
 
 IOReturn
@@ -4947,10 +4755,6 @@
 			if (props->getObject(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
 				service->setProperty(kIOPMResetPowerStateOnWakeKey, kOSBooleanTrue);
 			}
-			fAOTAllow |= (NULL != props->getObject(kIOPMAOTAllowKey));
-			if (!(kIODKDisableIOPMSystemOffPhase2Allow & gIODKDebug)) {
-				fSystemOffPhase2Allow |= (NULL != props->getObject(kIOPMSystemOffPhase2AllowKey));
-			}
 			OSSafeReleaseNULL(props);
 		}
 		service->PMinit();
@@ -5016,6 +4820,13 @@
 	return kIOPMAckImplied;
 }
 
+void
+IOUserServer::setPowerManagementFailed(bool failed)
+{
+	IOLockLock(fLock);
+	fPowerManagementFailed = failed;
+	IOLockUnlock(fLock);
+}
 
 IOReturn
 IOUserServer::serviceSetPowerState(IOService * controllingDriver, IOService * service, IOPMPowerFlags flags, unsigned long state)
@@ -5025,7 +4836,25 @@
 
 	IOLockLock(fLock);
 	if (service->reserved->uvars) {
-		if (!fSystemOff && !(kIODKDisablePM & gIODKDebug)) {
+		if (!fSystemOff && !fPowerManagementFailed && !(kIODKDisablePM & gIODKDebug)) {
+			OSDictionary * wakeDescription;
+			OSObject     * prop;
+			char           wakeReasonString[128];
+
+			wakeDescription = OSDictionary::withCapacity(4);
+			if (wakeDescription) {
+				wakeReasonString[0] = 0;
+				getPMRootDomain()->copyWakeReasonString(wakeReasonString, sizeof(wakeReasonString));
+
+				if (wakeReasonString[0]) {
+					prop = OSString::withCString(&wakeReasonString[0]);
+					wakeDescription->setObject(gIOSystemStateWakeDescriptionWakeReasonKey, prop);
+					OSSafeReleaseNULL(prop);
+				}
+				getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateWakeDescriptionKey, wakeDescription);
+				OSSafeReleaseNULL(wakeDescription);
+			}
+
 			service->reserved->uvars->willPower = true;
 			service->reserved->uvars->willPowerState = state;
 			service->reserved->uvars->controllingDriver = controllingDriver;
@@ -5037,31 +4866,10 @@
 	IOLockUnlock(fLock);
 
 	if (sendIt) {
-		uint32_t driverFlags = (uint32_t) flags;
 		if (kIODKLogPM & gIODKDebug) {
-			DKLOG(DKS "::serviceSetPowerState(%ld, 0x%x) %d\n", DKN(service), state, driverFlags, fSystemPowerAck);
-		}
-#if DEBUG || DEVELOPMENT
-		bool pageout = false;
-		uint64_t pageincount = 0;
-		if (gLPWFlags) {
-			pageout = fPageout;
-			if (pageout) {
-				fPageout = false;
-				DKLOG(DKS " pageout\n", DKN(service));
-				pageincount = vm_task_evict_shared_cache(fOwningTask);
-			}
-		}
-#endif /* DEBUG || DEVELOPMENT */
-
-		ret = service->SetPowerState(driverFlags);
-
-#if DEBUG || DEVELOPMENT
-		if (pageout) {
-			DKLOG(DKS " state %ld pageins %qd\n", DKN(service), state, vm_task_pageins(fOwningTask) - pageincount);
-		}
-#endif /* DEBUG || DEVELOPMENT */
-
+			DKLOG(DKS "::serviceSetPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
+		}
+		ret = service->SetPowerState((uint32_t) flags);
 		if (kIOReturnSuccess == ret) {
 			return 20 * 1000 * 1000;
 		} else {
@@ -5117,135 +4925,10 @@
 	IOLockUnlock(fLock);
 
 	if (pmAck) {
-		serverAck();
+		IOServicePH::serverAck(this);
 	}
 
 	return kIOPMAckImplied;
-}
-
-bool
-IOUserServer::checkPMReady()
-{
-	bool __block ready = true;
-
-	IOLockLock(fLock);
-	// Check if any services have not completely joined the PM tree (i.e.
-	// addPowerChild has not compeleted).
-	fServices->iterateObjects(^bool (OSObject * obj) {
-		IOPowerConnection *conn;
-		IOService *service = (IOService *) obj;
-		IORegistryEntry *parent = service->getParentEntry(gIOPowerPlane);
-		if ((conn = OSDynamicCast(IOPowerConnection, parent))) {
-		        if (!conn->getReadyFlag()) {
-		                ready = false;
-		                return true;
-			}
-		}
-		return false;
-	});
-	IOLockUnlock(fLock);
-
-	return ready;
-}
-
-IOReturn
-IOUserServer::serviceCreatePMAssertion(IOService * service, uint32_t assertionBits, uint64_t * assertionID, bool synced)
-{
-	IOReturn ret = kIOReturnSuccess;
-
-	*assertionID = kIOPMUndefinedDriverAssertionID;
-
-	if (!service->reserved->uvars || service->reserved->uvars->userServer != this) {
-		return kIOReturnError;
-	}
-
-	if (!service->reserved->uvars->userServerPM) {
-		// Cannot create PM assertion unless joined PM tree
-		return kIOReturnNotReady;
-	}
-
-	// Check to make sure the bits are allowed
-	uint32_t userAllowedBits = kIOPMDriverAssertionCPUBit |
-	    kIOPMDriverAssertionForceFullWakeupBit;
-	if (synced) {
-		userAllowedBits = kIOPMDriverAssertionCPUBit;
-	}
-	if (0 == (assertionBits & ~userAllowedBits)) {
-		if (synced) {
-			ret = getPMRootDomain()->acquireDriverKitSyncedAssertion(service, assertionID);
-			assert(ret != kIOReturnSuccess || *assertionID != kIOPMUndefinedDriverAssertionID);
-		} else {
-			*assertionID = getPMRootDomain()->createPMAssertion(assertionBits,
-			    kIOPMDriverAssertionLevelOn,
-			    getPMRootDomain(),
-			    service->getName());
-			if (!*assertionID) {
-				ret = kIOReturnInternalError;
-			}
-		}
-	} else {
-		ret = kIOReturnBadArgument;
-	}
-	if (*assertionID != kIOPMUndefinedDriverAssertionID) {
-		IOLockLock(fLock);
-		OSNumber * assertionIDNumber = OSNumber::withNumber(*assertionID, 64);
-		OSArray ** pmAssertions = (synced ? &service->reserved->uvars->pmAssertionsSynced : &service->reserved->uvars->pmAssertions);
-		if (!*pmAssertions) {
-			*pmAssertions = OSArray::withCapacity(1);
-		}
-		(*pmAssertions)->setObject(assertionIDNumber);
-		assertionIDNumber->release();
-		IOLockUnlock(fLock);
-	}
-
-	return ret;
-}
-
-IOReturn
-IOUserServer::serviceReleasePMAssertion(IOService * service, IOPMDriverAssertionID assertionID)
-{
-	kern_return_t ret = kIOReturnSuccess;
-	bool synced = false;
-
-	bool (^findAndRemoveAssertionID)(OSArray *) = ^(OSArray * assertions) {
-		unsigned index;
-		if (!assertions) {
-			return false;
-		}
-		for (index = 0; index < assertions->getCount(); index++) {
-			OSNumber * theID = (OSNumber *)assertions->getObject(index);
-			if (theID->unsigned64BitValue() == assertionID) {
-				break;
-			}
-		}
-		if (index == assertions->getCount()) {
-			return false;
-		}
-		assertions->removeObject(index);
-		return true;
-	};
-
-	if (!service->reserved->uvars || !service->reserved->uvars->userServer) {
-		return kIOReturnError;
-	}
-
-	IOLockLock(fLock);
-	if (findAndRemoveAssertionID(service->reserved->uvars->pmAssertionsSynced)) {
-		synced = true;
-	} else if (!findAndRemoveAssertionID(service->reserved->uvars->pmAssertions)) {
-		ret = kIOReturnNotFound;
-	}
-	IOLockUnlock(fLock);
-
-	if (ret == kIOReturnSuccess) {
-		if (synced) {
-			getPMRootDomain()->releaseDriverKitSyncedAssertion(assertionID);
-		} else {
-			getPMRootDomain()->releasePMAssertion(assertionID);
-		}
-	}
-
-	return ret;
 }
 
 kern_return_t
@@ -5257,23 +4940,6 @@
 	return reserved->uvars->userServer->serviceJoinPMTree(this);
 }
 
-static kern_return_t
-acknowledgeSetPowerState(IOService * service)
-{
-	if (service->reserved->uvars
-	    && service->reserved->uvars->userServer
-	    && service->reserved->uvars->willPower) {
-		IOReturn ret;
-		service->reserved->uvars->willPower = false;
-		ret = service->reserved->uvars->controllingDriver->setPowerState(service->reserved->uvars->willPowerState, service);
-		if (kIOPMAckImplied == ret) {
-			service->acknowledgeSetPowerState();
-		}
-		return kIOReturnSuccess;
-	}
-	return kIOReturnNotReady;
-}
-
 kern_return_t
 IOService::SetPowerState_Impl(
 	uint32_t powerFlags)
@@ -5281,7 +4947,18 @@
 	if (kIODKLogPM & gIODKDebug) {
 		DKLOG(DKS "::SetPowerState(%d), %d\n", DKN(this), powerFlags, reserved->uvars->willPower);
 	}
-	return ::acknowledgeSetPowerState(this);
+	if (reserved->uvars
+	    && reserved->uvars->userServer
+	    && reserved->uvars->willPower) {
+		IOReturn ret;
+		reserved->uvars->willPower = false;
+		ret = reserved->uvars->controllingDriver->setPowerState(reserved->uvars->willPowerState, this);
+		if (kIOPMAckImplied == ret) {
+			acknowledgeSetPowerState();
+		}
+		return kIOReturnSuccess;
+	}
+	return kIOReturnNotReady;
 }
 
 kern_return_t
@@ -5296,28 +4973,13 @@
 		changePowerStateToPriv(1);
 		break;
 	case kIOServicePowerCapabilityOn:
-		changePowerStateToPriv(kUserServerMaxPowerState);
+		changePowerStateToPriv(2);
 		break;
 	default:
 		return kIOReturnBadArgument;
 	}
 
 	return kIOReturnSuccess;
-}
-
-kern_return_t
-IOService::SetPowerOverride_Impl(
-	bool enable)
-{
-	kern_return_t ret;
-
-	if (enable) {
-		ret = powerOverrideOnPriv();
-	} else {
-		ret = powerOverrideOffPriv();
-	}
-
-	return ret == IOPMNoErr ? kIOReturnSuccess : kIOReturnError;
 }
 
 kern_return_t
@@ -5362,19 +5024,12 @@
 	if (provider != this) {
 		return kIOReturnUnsupported;
 	}
-	if (reserved == NULL || reserved->uvars == NULL) {
-		return kIOReturnUnsupported;
-	}
 
 	ret = kIOReturnUnsupported;
 	inst = NULL;
 	service = NULL;
 
-	prop = reserved->uvars->originalProperties->getObject(propertiesKey);
-	if (!prop) {
-		return kIOReturnBadArgument;
-	}
-	prop->retain();
+	prop = copyProperty(propertiesKey);
 	properties = OSDynamicCast(OSDictionary, prop);
 	if (!properties) {
 		ret = kIOReturnBadArgument;
@@ -5494,7 +5149,7 @@
 				}
 				return kIOReturnSuccess;
 			});
-			if (object || !(kIORegistryIterateParents & regOptions)) {
+			if (object || !(kIORegistryIterateParents & options)) {
 				break;
 			}
 		}
@@ -5617,77 +5272,15 @@
 	return kIOReturnSuccess;
 }
 
-kern_return_t
-IOService::CreatePMAssertion_Impl(uint32_t assertionBits, uint64_t * assertionID, bool synced)
-{
-	*assertionID = kIOPMUndefinedDriverAssertionID;
-
-	if (!reserved->uvars || !reserved->uvars->userServer) {
-		return kIOReturnError;
-	}
-
-	return reserved->uvars->userServer->serviceCreatePMAssertion(this, assertionBits, assertionID, synced);
-}
-
-kern_return_t
-IOService::ReleasePMAssertion_Impl(uint64_t assertionID)
-{
-	if (!reserved->uvars || !reserved->uvars->userServer) {
-		return kIOReturnError;
-	}
-
-	return reserved->uvars->userServer->serviceReleasePMAssertion(this, assertionID);
-}
-
 void
-IOUserServer::serverAck(void)
-{
-	IOServicePH::serverAck(this);
-}
-
-OSArray *
-IOUserServer::servicesWithPowerState(bool state)
-{
-	OSArray * result = OSArray::withCapacity(1);
-	if (!result) {
-		return NULL;
-	}
-	IOLockLock(fLock);
-	fServices->iterateObjects(^(OSObject * object) {
-		IOService * service = OSDynamicCast(IOService, object);
-		if (service && service->reserved->uvars->powerState == state) {
-		        result->setObject(service);
-		}
-		return false;
-	});
-	IOLockUnlock(fLock);
-	if (!result->getCount()) {
-		OSSafeReleaseNULL(result);
-	}
-	return result;
-}
-
-void
-IOUserServer::systemSuspend()
-{
-	if (fSystemOff && !fSuspended) {
-		KDBG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_SUSPEND_DRIVERKIT_USERSPACE) | DBG_FUNC_START,
-		    task_pid(fOwningTask));
-		task_suspend_internal(fOwningTask);
-		DKLOG(DKS " did task_suspend_internal\n", DKN(this));
-		fSuspended = true;
-	}
-}
-
-void
-IOUserServer::systemPower(uint8_t systemState, bool hibernate)
+IOUserServer::systemPower(bool powerOff)
 {
 	OSArray * services;
 	{
 		OSDictionary * sleepDescription;
 		OSObject     * prop;
 
-		sleepDescription = OSDictionary::withCapacity(3);
+		sleepDescription = OSDictionary::withCapacity(4);
 		if (sleepDescription) {
 			prop = getPMRootDomain()->copyProperty(kRootDomainSleepReasonKey);
 			if (prop) {
@@ -5699,43 +5292,18 @@
 				sleepDescription->setObject(gIOSystemStateSleepDescriptionHibernateStateKey, prop);
 				OSSafeReleaseNULL(prop);
 			}
-			if (hibernate) {
-				uint32_t correctHibernateState = kIOSystemStateSleepDescriptionHibernateStateHibernating;
-				OSData *correctHibernateStateData = OSData::withValue(correctHibernateState);
-				assert(correctHibernateStateData != NULL);
-				sleepDescription->setObject(gIOSystemStateSleepDescriptionHibernateStateKey, correctHibernateStateData);
-				OSSafeReleaseNULL(correctHibernateStateData);
-			}
 			getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateSleepDescriptionKey, sleepDescription);
 			OSSafeReleaseNULL(sleepDescription);
 		}
 	}
-	if (!IsIOServiceSystemStateOff(systemState)) {
-		OSDictionary * wakeDescription;
-		OSObject     * prop;
-		char           wakeReasonString[128];
-
-		wakeDescription = OSDictionary::withCapacity(2);
-		if (wakeDescription) {
-			wakeReasonString[0] = 0;
-			getPMRootDomain()->copyWakeReasonString(wakeReasonString, sizeof(wakeReasonString));
-
-			if (wakeReasonString[0]) {
-				prop = OSString::withCString(&wakeReasonString[0]);
-				wakeDescription->setObject(gIOSystemStateWakeDescriptionWakeReasonKey, prop);
-				OSSafeReleaseNULL(prop);
-			}
-#if defined(__arm__) || defined(__arm64__)
-			prop = OSNumber::withNumber(ml_get_conttime_offset(), sizeof(uint64_t) * CHAR_BIT);
-			wakeDescription->setObject(gIOSystemStateWakeDescriptionContinuousTimeOffsetKey, prop);
-			OSSafeReleaseNULL(prop);
-#endif /* defined(__arm__) || defined(__arm64__) */
-			getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateWakeDescriptionKey, wakeDescription);
-			OSSafeReleaseNULL(wakeDescription);
-		}
-	}
 
 	IOLockLock(fLock);
+
+	if (fPowerManagementFailed && !powerOff) {
+		IOLockUnlock(fLock);
+		kill("Power Management Failed");
+		return;
+	}
 
 	services = OSArray::withArray(fServices);
 
@@ -5750,17 +5318,11 @@
 		return allPowerStates;
 	});
 
-	// figure what phase this DK server process will be suspended in,
-	// and make sure its power changes complete before suspension
-
-	bool effectiveOff = IsIOServiceSystemStateOff(systemState) && !allPowerStates;
-	effectiveOff |= ((kIOServiceSystemStateOffPhase1 == systemState) && !fSystemOffPhase2Allow);
-	effectiveOff |= (kIOServiceSystemStateOffPhase2 == systemState);
-	effectiveOff |= ((kIOServiceSystemStateAOT == systemState) && !fAOTAllow);
-
-	DKLOG(DKS "::systemPower(0x%x) effective %d current %d\n", DKN(this), systemState, !effectiveOff, allPowerStates != 0);
-
-	if (effectiveOff) {
+	if (kIODKLogPM & gIODKDebug) {
+		DKLOG("%s::powerOff(%d) %d\n", getName(), powerOff, allPowerStates);
+	}
+
+	if (powerOff) {
 		fSystemPowerAck = allPowerStates;
 		if (!fSystemPowerAck) {
 			fSystemOff = true;
@@ -5768,7 +5330,7 @@
 		IOLockUnlock(fLock);
 
 		if (!fSystemPowerAck) {
-			serverAck();
+			IOServicePH::serverAck(this);
 		} else {
 			if (services) {
 				services->iterateObjects(^bool (OSObject * obj) {
@@ -5784,17 +5346,8 @@
 				});
 			}
 		}
-	} else if (fSystemOff) {
+	} else {
 		fSystemOff = false;
-
-		if (fSuspended) {
-			KDBG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_SUSPEND_DRIVERKIT_USERSPACE) | DBG_FUNC_END,
-			    task_pid(fOwningTask));
-			task_resume_internal(fOwningTask);
-			DKLOG(DKS " did task_resume_internal\n", DKN(this));
-			fSuspended = false;
-		}
-
 		IOLockUnlock(fLock);
 		if (services) {
 			services->iterateObjects(^bool (OSObject * obj) {
@@ -5813,12 +5366,10 @@
 				return false;
 			});
 		}
-	} else {
-		IOLockUnlock(fLock);
-		serverAck();
 	}
 	OSSafeReleaseNULL(services);
 }
+
 
 void
 IOUserServer::systemHalt(int howto)
@@ -5826,7 +5377,7 @@
 	OSArray * services;
 
 	if (true || (kIODKLogPM & gIODKDebug)) {
-		DKLOG(DKS "::systemHalt()\n", DKN(this));
+		DKLOG("%s::systemHalt()\n", getName());
 	}
 
 	{
@@ -5876,15 +5427,9 @@
 			if (!root) {
 			        return false;
 			}
-			if (nextService->reserved && nextService->reserved->uvars) {
-			        if (nextService->reserved->uvars->started) {
-			                terminateOptions = kIOServiceRequired | kIOServiceTerminateNeedWillTerminate;
-			                if (!nextService->terminate(terminateOptions)) {
-			                        IOLog("failed to terminate service %s-0x%llx\n", nextService->getName(), nextService->getRegistryEntryID());
-					}
-				} else {
-			                IOLog("service %s-0x%llx not started, skipped termination\n", nextService->getName(), nextService->getRegistryEntryID());
-				}
+			terminateOptions = kIOServiceRequired | kIOServiceTerminateNeedWillTerminate;
+			if (!nextService->terminate(terminateOptions)) {
+			        IOLog("failed to terminate service %s-0x%llx\n", nextService->getName(), nextService->getRegistryEntryID());
 			}
 			return false;
 		});
@@ -5911,42 +5456,20 @@
 IOUserServer::serviceStarted(IOService * service, IOService * provider, bool result)
 {
 	IOReturn    ret;
-	bool        needStop = false;
 
 	DKLOG(DKS "::start(" DKS ") %s\n", DKN(service), DKN(provider), result ? "ok" : "fail");
 
 	if (!result) {
-		if (!service->reserved->uvars->instantiated && provider) {
-			// Object instantiation did not happen. This can happen if,
-			// 1. Dext crashed, in which case the user server has been terminated when the task is marked as corpse
-			// 2. Kernel IOService failed start, and it did not attempt Start
-			// A rematch should be attempted for 1, not 2
-			bool shouldReRegister = true;
-			if (lockForArbitration()) {
-				shouldReRegister = (__state[0] & kIOServiceInactiveState);
-				unlockForArbitration();
-			}
-			if (shouldReRegister) {
-				provider->registerService(kIOServiceAsynchronous);
-			}
-		}
 		ret = kIOReturnSuccess;
 		return ret;
 	}
 
 	ret = serviceJoinPMTree(service);
 
-	IOLockLock(service->reserved->uvars->uvarsLock);
 	service->reserved->uvars->started = true;
-	needStop = service->reserved->uvars->needStop;
-	IOLockUnlock(service->reserved->uvars->uvarsLock);
-	if (needStop) {
-		serviceStop(service, provider);
-		return kIOReturnSuccess;
-	}
 
 	if (service->reserved->uvars->deferredRegisterService) {
-		service->registerService(kIOServiceAsynchronous | kIOServiceDextRequirePowerForMatching);
+		service->registerService(kIOServiceAsynchronous);
 		service->reserved->uvars->deferredRegisterService = false;
 	}
 
@@ -6006,34 +5529,19 @@
 
 finish:
 	IOLockUnlock(client->reserved->uvars->uvarsLock);
-	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG(DKS "::serviceClose(" DKS ", " DKS ") -> %x\n", DKN(this), DKN(provider), DKN(client), ret);
-	}
 
 	return ret;
 }
 
 
 IOReturn
-IOUserServer::serviceStop(IOService * service, IOService *provider)
+IOUserServer::serviceStop(IOService * service, IOService *)
 {
 	IOReturn           ret;
-	uint32_t           idx;
+	uint32_t           idx, queueAlloc;
 	bool               pmAck;
-	bool               deferred = false;
-	OSObjectUserVars * uvars = service->reserved->uvars;
-
-	IOLockLock(uvars->uvarsLock);
-	if (!uvars->started) {
-		// started will be set, at a later point
-		uvars->needStop = true;
-		deferred = true;
-	}
-	IOLockUnlock(uvars->uvarsLock);
-	if (deferred) {
-		return kIOReturnSuccess;
-	}
-
+	OSObjectUserVars * uvars;
+	IODispatchQueue ** unboundedQueueArray = NULL;
 	pmAck = false;
 	IOLockLock(fLock);
 	idx = fServices->getNextIndexOfObject(service, 0);
@@ -6060,6 +5568,7 @@
 		OSSafeReleaseNULL(serviceArray);
 		OSSafeReleaseNULL(serviceArrayObj);
 
+		uvars = service->reserved->uvars;
 		uvars->stopped = true;
 		uvars->powerState = 0;
 
@@ -6081,55 +5590,13 @@
 	}
 	IOLockUnlock(fLock);
 	if (pmAck) {
-		serverAck();
+		IOServicePH::serverAck(this);
 	}
 
 	if (-1U == idx) {
-		if (kIODKLogSetup & gIODKDebug) {
-			DKLOG(DKS "::serviceStop(" DKS ", " DKS "): could not find service\n", DKN(this), DKN(service), DKN(provider));
-		}
 		return kIOReturnSuccess;
 	}
 
-	(void) service->deRegisterInterestedDriver(this);
-	if (uvars->userServerPM) {
-		IOPMrootDomain * rootDomain = getPMRootDomain();
-		service->PMstop();
-		service->acknowledgeSetPowerState();
-		if (uvars->pmAssertions) {
-			uvars->pmAssertions->iterateObjects(^(OSObject * obj) {
-				rootDomain->releasePMAssertion(((OSNumber *)obj)->unsigned64BitValue());
-				return false;
-			});
-			OSSafeReleaseNULL(uvars->pmAssertions);
-		}
-		if (uvars->pmAssertionsSynced) {
-			uvars->pmAssertionsSynced->iterateObjects(^(OSObject * obj) {
-				rootDomain->releaseDriverKitSyncedAssertion(((OSNumber *)obj)->unsigned64BitValue());
-				return false;
-			});
-			OSSafeReleaseNULL(uvars->pmAssertionsSynced);
-		}
-	}
-	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG(DKS "::serviceStop(" DKS ", " DKS ")\n", DKN(this), DKN(service), DKN(provider));
-	}
-
-	ret = kIOReturnSuccess;
-	return ret;
-}
-
-void
-IOUserServer::serviceFree(IOService * service)
-{
-	OSObjectUserVars * uvars;
-	uint32_t idx, queueAlloc;
-	IODispatchQueue ** unboundedQueueArray = NULL;
-
-	uvars = service->reserved->uvars;
-	if (!uvars) {
-		return;
-	}
 	if (uvars->queueArray && uvars->userMeta) {
 		queueAlloc = 1;
 		if (uvars->userMeta->queueNames) {
@@ -6142,9 +5609,27 @@
 		IOSafeDeleteNULL(unboundedQueueArray, IODispatchQueue *, queueAlloc);
 		uvars->queueArray = OSBoundedArrayRef<IODispatchQueue *>();
 	}
+
+	(void) service->deRegisterInterestedDriver(this);
+	if (uvars->userServerPM) {
+		service->PMstop();
+	}
+
+	ret = kIOReturnSuccess;
+	return ret;
+}
+
+void
+IOUserServer::serviceFree(IOService * service)
+{
+	OSObjectUserVars * uvars;
+
+	uvars = service->reserved->uvars;
+	if (!uvars) {
+		return;
+	}
 	OSSafeReleaseNULL(uvars->userServer);
 	IOLockFree(uvars->uvarsLock);
-	OSSafeReleaseNULL(service->reserved->uvars->originalProperties);
 	IOFreeType(service->reserved->uvars, OSObjectUserVars);
 }
 
@@ -6162,25 +5647,13 @@
 		willTerminate = true;
 	}
 	IOLockUnlock(client->reserved->uvars->uvarsLock);
-	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG("serviceWillTerminate(" DKS ", " DKS ")\n", DKN(client), DKN(provider));
-	}
 
 	if (willTerminate) {
 		if (provider->isInactive() || IOServicePH::serverSlept()) {
-			if (kIODKLogIPC & gIODKDebug) {
-				DKLOG(DKS "->Stop_async(" DKS ")\n", DKN(client), DKN(provider));
-			}
 			client->Stop_async(provider);
 			ret = kIOReturnOffline;
 		} else {
-			if (kIODKLogIPC & gIODKDebug) {
-				DKLOG(DKS "->Stop(" DKS ")\n", DKN(client), DKN(provider));
-			}
 			ret = client->Stop(provider);
-			if (kIODKLogIPC & gIODKDebug) {
-				DKLOG(DKS "->Stop(" DKS ") returned %x\n", DKN(client), DKN(provider), ret);
-			}
 		}
 		if (kIOReturnSuccess != ret) {
 			IOUserServer::serviceDidStop(client, provider);
@@ -6199,9 +5672,6 @@
 		*defer = true;
 	}
 	IOLockUnlock(client->reserved->uvars->uvarsLock);
-	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG("serviceDidTerminate(" DKS ", " DKS ") -> defer %d\n", DKN(client), DKN(provider), *defer);
-	}
 }
 
 void
@@ -6226,10 +5696,6 @@
 		client->reserved->uvars->openProviders = NULL;
 	}
 	IOLockUnlock(client->reserved->uvars->uvarsLock);
-
-	if (kIODKLogSetup & gIODKDebug) {
-		DKLOG("serviceDidStop(" DKS ", " DKS ") -> complete %d\n", DKN(client), DKN(provider), complete);
-	}
 
 	if (closeArray) {
 		closeArray->iterateObjects(^bool (OSObject * obj) {
@@ -6359,6 +5825,7 @@
 	user_addr_t userObjectName = (user_addr_t)p1;
 	mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
 	mach_port_t port = MACH_PORT_NULL;
+	ipc_kobject_type_t portType;
 	char eventlinkName[kIOEventLinkMaxNameLength + 1] = {0};
 	size_t eventLinkNameLen;
 	OSString * eventlinkNameStr = NULL; // must release
@@ -6394,8 +5861,15 @@
 		goto finish;
 	}
 
-	ret = iokit_lookup_raw_current_task(portName, IKOT_EVENTLINK, &port);
-	if (ret != kIOReturnSuccess) {
+	port = iokit_lookup_raw_current_task(portName, &portType);
+
+	if (port == NULL) {
+		ret = kIOReturnNotFound;
+		goto finish;
+	}
+
+	if (portType != IKOT_EVENTLINK) {
+		ret = kIOReturnBadArgument;
 		goto finish;
 	}
 
@@ -6424,6 +5898,7 @@
 	user_addr_t userObjectName = (user_addr_t)p1;
 	mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
 	mach_port_t port = MACH_PORT_NULL;
+	ipc_kobject_type_t portType;
 	char workgroupName[kIOWorkGroupMaxNameLength + 1] = {0};
 	size_t workgroupNameLen;
 	OSString * workgroupNameStr = NULL; // must release
@@ -6459,8 +5934,15 @@
 		goto finish;
 	}
 
-	ret = iokit_lookup_raw_current_task(portName, IKOT_WORK_INTERVAL, &port);
-	if (ret != kIOReturnSuccess) {
+	port = iokit_lookup_raw_current_task(portName, &portType);
+
+	if (port == NULL) {
+		ret = kIOReturnNotFound;
+		goto finish;
+	}
+
+	if (portType != IKOT_WORK_INTERVAL) {
+		ret = kIOReturnBadArgument;
 		goto finish;
 	}
 
@@ -6654,26 +6136,6 @@
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-/*
- * IOUserServerCheckInToken state machine
- *
- *         token
- *        creation
- *            |
- *            |
- *            v            dext
- *      +-----------+    check-in    +-----------+
- *      |  Pending  +--------------->| Complete  |
- *      +-----+-----+                +-----+-----+
- *            |                            |
- * dext crash |                            |  dext crash
- *   before   |                            | before server
- *  check-in  |                            | registration
- *            |      +-----------+         |
- *            +----->| Canceled  |<--------+
- *                   +-----------+
- */
-
 extern IORecursiveLock               * gDriverKitLaunchLock;
 extern OSSet                         * gDriverKitLaunches;
 
@@ -6687,6 +6149,8 @@
 	}
 
 	IORecursiveLockLock(gDriverKitLaunchLock);
+
+	assert(fState != kIOUserServerCheckInComplete);
 
 	if (fState == kIOUserServerCheckInCanceled) {
 		// Send cancel notification if we set the handler after this was canceled
@@ -6716,12 +6180,8 @@
 {
 	IORecursiveLockLock(gDriverKitLaunchLock);
 
-	if (fState != kIOUserServerCheckInCanceled) {
-		// Move the state to canceled even if the token has completed
-		// This is to cover the gap between dext check-in and the registration of user server
-		// Cancellation listeners must be informed of a crash in between
+	if (fState == kIOUserServerCheckInPending) {
 		fState = kIOUserServerCheckInCanceled;
-
 		if (gDriverKitLaunches != NULL) {
 			// Remove pending launch from list, if we have not shut down yet.
 			gDriverKitLaunches->removeObject(this);
@@ -6740,30 +6200,23 @@
 	IORecursiveLockUnlock(gDriverKitLaunchLock);
 }
 
-IOReturn
+void
 IOUserServerCheckInToken::complete()
 {
-	IOReturn ret;
 	IORecursiveLockLock(gDriverKitLaunchLock);
 
-	if (fState == kIOUserServerCheckInCanceled) {
-		ret = kIOReturnError;
-	} else {
-		ret = kIOReturnSuccess;
-	}
-
-	if (fState == kIOUserServerCheckInPending) {
+	if (fState == kIOUserServerCheckInPending && --fPendingCount == 0) {
 		fState = kIOUserServerCheckInComplete;
 		if (gDriverKitLaunches != NULL) {
 			// Remove pending launch from list, if we have not shut down yet.
 			gDriverKitLaunches->removeObject(this);
 		}
 
-		// Do not flush the cancellation handlers, as we might still trigger them
+		// No need to hold on to the cancellation handlers
+		fHandlers->flushCollection();
 	}
 
 	IORecursiveLockUnlock(gDriverKitLaunchLock);
-	return ret;
 }
 
 bool
@@ -6791,19 +6244,12 @@
 	}
 
 	fState = kIOUserServerCheckInPending;
+	fPendingCount = 1;
 
 	fKextBundleID = NULL;
 	fNeedDextDec = false;
 
-	fExecutableName = NULL;
-
 	if (driverKext) {
-		fExecutableName = OSDynamicCast(OSSymbol, driverKext->getBundleExecutable());
-
-		if (fExecutableName) {
-			fExecutableName->retain();
-		}
-
 		/*
 		 * We need to keep track of how many dexts we have started.
 		 * For every new dext we are going to create a new token, and
@@ -6859,7 +6305,6 @@
 {
 	OSSafeReleaseNULL(fServerName);
 	OSSafeReleaseNULL(fServerTag);
-	OSSafeReleaseNULL(fExecutableName);
 	OSSafeReleaseNULL(fHandlers);
 	if (fKextBundleID != NULL) {
 		dextTerminate();
@@ -6883,66 +6328,15 @@
 	return fServerTag;
 }
 
-/*
- * Wait for a IOUserServer to check in
- */
-
-static
-__attribute__((noinline, not_tail_called))
 IOUserServer *
-__WAITING_FOR_USER_SERVER__(IOUserServerCheckInToken * token, uint64_t * timeoutMS)
-{
-	IOUserServer * result = NULL;
-	IOService * server = NULL;
-	const OSSymbol * serverName = token->copyServerName();
-	OSNumber       * serverTag = token->copyServerTag();
-	OSDictionary   * matching = IOService::serviceMatching(gIOUserServerClassKey);
-	uint64_t         startTime = 0, endTime = 0;
-
-	if (!matching || !serverName || !serverTag) {
-		goto finish;
-	}
-	IOService::propertyMatching(gIOUserServerNameKey, serverName, matching);
-	if (!(kIODKDisableDextTag & gIODKDebug)) {
-		IOService::propertyMatching(gIOUserServerTagKey, serverTag, matching);
-	}
-
-	absolutetime_to_nanoseconds(mach_absolute_time(), &startTime);
-	startTime /= NSEC_PER_MSEC;
-	server = IOService::waitForMatchingServiceWithToken(matching, (*timeoutMS) * NSEC_PER_MSEC, token);
-	result = OSDynamicCast(IOUserServer, server);
-	if (!result) {
-		// Calculate the remaining timeout if the server isn't registered
-		OSSafeReleaseNULL(server);
-		token->cancel();
-		absolutetime_to_nanoseconds(mach_absolute_time(), &endTime);
-		endTime /= NSEC_PER_MSEC;
-		if (endTime > startTime) {
-			if (os_sub_overflow(*timeoutMS, endTime - startTime, timeoutMS)) {
-				*timeoutMS = 0;
-			}
-		}
-	}
-
-finish:
-	OSSafeReleaseNULL(matching);
-	OSSafeReleaseNULL(serverName);
-	OSSafeReleaseNULL(serverTag);
-
-	return result;
-}
-
-IOUserServer *
-IOUserServer::launchUserServer(IOService * provider, IOService * service, OSString * bundleID, const OSSymbol * serverName, OSNumber * serverTag, bool reuseIfExists, OSData *serverDUI)
-{
-	IOUserServer *me = NULL, *providerServer = NULL;
+IOUserServer::launchUserServer(OSString * bundleID, const OSSymbol * serverName, OSNumber * serverTag, bool reuseIfExists, IOUserServerCheckInToken ** resultToken, OSData *serverDUI)
+{
+	IOUserServer *me = NULL;
 	IOUserServerCheckInToken * token = NULL;
 	OSDictionary * matching = NULL;  // must release
 	OSKext * driverKext = NULL; // must release
 	OSDextStatistics * driverStatistics = NULL; // must release
 	bool reslide = false;
-	uint32_t retries = kIOUserServerCheckInMaxRetry;
-	uint64_t timeRemainingMS = kIOUserServerCheckInTimeoutMSecs;
 
 	/* TODO: Check we are looking for same dextID
 	 * and if it is not the same
@@ -6958,7 +6352,15 @@
 		reslide = driverStatistics->getCrashCount() > 0;
 	} else {
 		DKLOG("Could not find OSKext for %s\n", bundleID->getCStringNoCopy());
+		*resultToken = NULL;
 		return NULL;
+	}
+
+	IORecursiveLockLock(gDriverKitLaunchLock);
+
+	if (gDriverKitLaunches == NULL) {
+		// About to shut down, don't launch anything
+		goto finish;
 	}
 
 	if (reuseIfExists) {
@@ -6975,136 +6377,65 @@
 		}
 	}
 
+	// Find existing server
 	if (reuseIfExists) {
-		// Check provider's user server, if exists
-		if (provider->reserved && provider->reserved->uvars && (providerServer = provider->reserved->uvars->userServer) != NULL) {
-			OSString * providerServerName = OSDynamicCast(OSString, providerServer->getProperty(gIOUserServerNameKey));
-			if (providerServerName && providerServerName->isEqualTo(serverName)) {
-				// Reuse is required
-
-				DKLOG("using existing server " DKS " from provider " DKS "\n", DKN(providerServer), DKN(provider));
-
-				// If provider has the user server that we are supposed to reuse, and it has become inactive
-				// start of this service should simply fail
-				// If the user server become inactive after this check, start should fail at a later stage
-				if (!providerServer->isInactive()) {
-					providerServer->retain();
-					me = providerServer;
-				} else {
-					DKLOG(DKS " cannot reuse inactive server\n", DKN(service));
-					// Must not create a token as reuse is required
-				}
+		token = IOUserServerCheckInToken::findExistingToken(serverName);
+		if (token) {
+			// Launch in progress, return token
+			goto finish;
+		} else {
+			// Check if launch completed
+			matching = IOService::serviceMatching(gIOUserServerClassKey);
+			if (!matching) {
 				goto finish;
 			}
-		}
-	}
-
-	do {
-		const OSSymbol * tokenServerName;
-		OSNumber * tokenServerTag;
-
-		IORecursiveLockLock(gDriverKitLaunchLock);
-
-		if (gDriverKitLaunches == NULL) {
-			// About to shut down, don't launch anything
-			IORecursiveLockUnlock(gDriverKitLaunchLock);
-			goto finish;
-		}
-
-		// Find existing server
-		if (reuseIfExists) {
-			token = IOUserServerCheckInToken::findExistingToken(serverName);
-			if (!token) {
-				// Check if launch completed
-
-				matching = IOService::serviceMatching(gIOUserServerClassKey);
-				if (!matching) {
-					IORecursiveLockUnlock(gDriverKitLaunchLock);
-					goto finish;
-				}
-				IOService::propertyMatching(gIOUserServerNameKey, serverName, matching);
-				IOService * service = IOService::copyMatchingService(matching);
-				IOUserServer * userServer = OSDynamicCast(IOUserServer, service);
-				if (userServer) {
-					// found existing user server
-					me = userServer;
-					IORecursiveLockUnlock(gDriverKitLaunchLock);
-					goto finish;
-				} else {
-					OSSafeReleaseNULL(service);
-				}
-			}
-		}
-
-		if (!token) {
-			// No existing server, request launch
-			token = new IOUserServerCheckInToken;
-			if (!token) {
-				IORecursiveLockUnlock(gDriverKitLaunchLock);
+			IOService::propertyMatching(gIOUserServerNameKey, serverName, matching);
+			IOService * service = IOService::copyMatchingService(matching);
+			IOUserServer * userServer = OSDynamicCast(IOUserServer, service);
+			if (userServer) {
+				// found existing user server
+				me = userServer;
 				goto finish;
-			}
-
-			/*
-			 * TODO: If the init fails because the personalities are not up to date
-			 * restart the whole matching process.
-			 */
-			if (token && !token->init(serverName, serverTag, driverKext, serverDUI)) {
-				DKLOG(DKS " could not initialize token\n", DKN(service));
-				IORecursiveLockUnlock(gDriverKitLaunchLock);
-				OSSafeReleaseNULL(token);
-				goto finish;
-			}
-
-			/*
-			 * If the launch fails at any point terminate() will
-			 * be called on this IOUserServer.
-			 */
-			gDriverKitLaunches->setObject(token);
-			OSKext::requestDaemonLaunch(bundleID, (OSString *)serverName, serverTag, reslide ? kOSBooleanTrue : kOSBooleanFalse, token, serverDUI);
-		}
-
-		IORecursiveLockUnlock(gDriverKitLaunchLock);
-
-		tokenServerName = token->copyServerName();
-		tokenServerTag = token->copyServerTag();
-		assert(tokenServerName && tokenServerTag);
-		DKLOG(DKS " waiting for server %s-%llx\n", DKN(service), tokenServerName->getCStringNoCopy(), tokenServerTag->unsigned64BitValue());
-
-		me = __WAITING_FOR_USER_SERVER__(token, &timeRemainingMS);
-		if (me) {
-			OSSafeReleaseNULL(tokenServerName);
-			OSSafeReleaseNULL(tokenServerTag);
-			break;
-		}
-		DKLOG(DKS " failed to find server %s-%llx, remaining %llums, retries %u\n", DKN(service),
-		    tokenServerName->getCStringNoCopy(), tokenServerTag->unsigned64BitValue(), timeRemainingMS, retries - 1);
-		OSSafeReleaseNULL(tokenServerName);
-		OSSafeReleaseNULL(tokenServerTag);
+			} else {
+				OSSafeReleaseNULL(service);
+			}
+		}
+	}
+
+	// No existing server, request launch
+	token = new IOUserServerCheckInToken;
+	if (!token) {
+		goto finish;
+	}
+
+	/*
+	 * TODO: If the init fails because the personalities are not up to date
+	 * restart the whole matching process.
+	 */
+	if (token && !token->init(serverName, serverTag, driverKext, serverDUI)) {
+		IOLog("Could not initialize token\n");
 		OSSafeReleaseNULL(token);
-		// If the loop continues it means the dext has been killed
-		// We don't record a crash since start never happened. No client code has run
-	} while (--retries && timeRemainingMS && !gInUserspaceReboot);
-
-	if (me) {
-		DKLOG(DKS " server launched, validating\n", DKN(service));
-		if (token && !(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
-			if (!me->serviceMatchesCheckInToken(token)) {
-				DKLOG(DKS " server does not match token\n", DKN(service));
-				me->exit("Check In Token verification failed");
-				OSSafeReleaseNULL(me);
-			}
-		}
-	} else {
-#if DEVELOPMENT || DEBUG
-		driverkit_checkin_timed_out = mach_absolute_time();
-#endif
-	}
+		goto finish;
+	}
+
+	/*
+	 * If the launch fails at any point terminate() will
+	 * be called on this IOUserServer.
+	 */
+	gDriverKitLaunches->setObject(token);
+	OSKext::requestDaemonLaunch(bundleID, (OSString *)serverName, serverTag, reslide ? kOSBooleanTrue : kOSBooleanFalse, token, serverDUI);
 
 finish:
+	IORecursiveLockUnlock(gDriverKitLaunchLock);
 	OSSafeReleaseNULL(matching);
 	OSSafeReleaseNULL(driverStatistics);
 	OSSafeReleaseNULL(driverKext);
-	OSSafeReleaseNULL(token);
+
+	if (resultToken) {
+		*resultToken = token;
+	} else {
+		OSSafeReleaseNULL(token);
+	}
 
 	return me;
 }
@@ -7149,6 +6480,7 @@
 		        const OSSymbol * tokenServerName = token->fServerName;
 		        if (tokenServerName->isEqualTo(serverName)) {
 		                assert(token->fState == kIOUserServerCheckInPending);
+		                token->fPendingCount++;
 		                result = token;
 		                result->retain();
 			}
@@ -7457,6 +6789,7 @@
 public:
 	virtual bool init() override;
 
+	OSDictionary * fSchema;
 	OSDictionary * fValue;
 	OSSet        * fListeners;
 };
@@ -7527,21 +6860,9 @@
 
 		gIOSystemStateWakeDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionKey);
 		gIOSystemStateWakeDescriptionWakeReasonKey = OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionWakeReasonKey);
-		gIOSystemStateWakeDescriptionContinuousTimeOffsetKey = OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionContinuousTimeOffsetKey);
-
-#if defined(__arm__) || defined(__arm64__)
-		// Make ml_get_conttime_offset available before systemPower
-		OSDictionary * wakeDescription = OSDictionary::withCapacity(1);
-		OSObject * prop = OSNumber::withNumber(ml_get_conttime_offset(), sizeof(uint64_t) * CHAR_BIT);
-		wakeDescription->setObject(gIOSystemStateWakeDescriptionContinuousTimeOffsetKey, prop);
-		ret = me->StateNotificationItemCreate(gIOSystemStateWakeDescriptionKey, wakeDescription);
-		OSSafeReleaseNULL(prop);
-		OSSafeReleaseNULL(wakeDescription);
-		assert(kIOReturnSuccess == ret);
-#else /* !defined(__arm__) && !defined(__arm64__) */
+
 		ret = me->StateNotificationItemCreate(gIOSystemStateWakeDescriptionKey, NULL);
 		assert(kIOReturnSuccess == ret);
-#endif /* defined(__arm__) || defined(__arm64__) */
 
 		gIOSystemStateHaltDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionKey);
 		gIOSystemStateHaltDescriptionHaltStateKey = OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionHaltStateKey);
@@ -7593,6 +6914,7 @@
 {
 	kern_return_t  kr;
 	OSDictionary * dict;
+	OSDictionary * schema;
 	OSDictionary * value;
 	OSString     * itemName;
 
@@ -7605,12 +6927,9 @@
 		return kIOReturnNotPermitted;
 	}
 
-	if ((value = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemCreateKey)))) {
-		itemName = OSDynamicCast(OSString, value->getObject(kIOStateNotificationNameKey));
-		itemName->retain();
-		value->removeObject(kIOStateNotificationNameKey);
-		kr = StateNotificationItemCreate(itemName, value);
-		itemName->release();
+	if ((schema = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemCreateKey)))) {
+		itemName = OSDynamicCast(OSString, schema->getObject(kIOStateNotificationNameKey));
+		kr = StateNotificationItemCreate(itemName, schema);
 	} else if ((value = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemSetKey)))) {
 		itemName = OSDynamicCast(OSString, value->getObject(kIOStateNotificationNameKey));
 		itemName->retain();
@@ -7637,7 +6956,7 @@
 }
 
 IOStateNotificationItem *
-IOService::stateNotificationItemCopy(OSString * itemName, OSDictionary * initialValue)
+IOService::stateNotificationItemCopy(OSString * itemName, OSDictionary * schema)
 {
 	IOServiceStateChangeVars * ivars = reserved->svars;
 
@@ -7654,10 +6973,13 @@
 		item->init();
 		item->fListeners = OSSet::withCapacity(16);
 
-		if (initialValue) {
-			initialValue->retain();
-			item->fValue = initialValue;
-		}
+		if (schema) {
+			schema->retain();
+		} else {
+			schema = OSDictionary::withCapacity(8);
+		}
+		schema->setObject(kIOStateNotificationNameKey, name);
+		item->fSchema = schema;
 		ivars->fItems->setObject(name, item);
 	}
 	IOLockUnlock(ivars->fLock);
@@ -7668,11 +6990,11 @@
 }
 
 kern_return_t
-IOService::StateNotificationItemCreate_Impl(OSString * itemName, OSDictionary * value)
+IOService::StateNotificationItemCreate_Impl(OSString * itemName, OSDictionary * schema)
 {
 	IOStateNotificationItem * item;
 
-	item = stateNotificationItemCopy(itemName, value);
+	item = stateNotificationItemCopy(itemName, schema);
 	if (!item) {
 		return kIOReturnNoMemory;
 	}
@@ -7684,27 +7006,20 @@
 kern_return_t
 IOService::StateNotificationItemSet_Impl(OSString * itemName, OSDictionary * value)
 {
-	kern_return_t              ret = kIOReturnSuccess;
 	IOServiceStateChangeVars * ivars = reserved->svars;
 
-	OSSet                    * listeners = NULL;
-	IOStateNotificationItem  * item;
+	OSSet                   * listeners;
+	IOStateNotificationItem * item;
 
 	value->retain();
 	IOLockLock(ivars->fLock);
-	do {
-		item = (typeof(item))ivars->fItems->getObject(itemName);
-		if (!item) {
-			ret = kIOReturnNotFound;
-			value->release();
-			break;
-		}
-		OSSafeReleaseNULL(item->fValue);
-		item->fValue = value;
-		if (item->fListeners->getCount()) {
-			listeners = OSSet::withSet(item->fListeners);
-		}
-	} while (false);
+	item = (typeof(item))ivars->fItems->getObject(itemName);
+	OSSafeReleaseNULL(item->fValue);
+	item->fValue = value;
+	listeners = NULL;
+	if (item->fListeners->getCount()) {
+		listeners = OSSet::withSet(item->fListeners);
+	}
 	IOLockUnlock(ivars->fLock);
 
 	if (listeners) {
@@ -7718,7 +7033,7 @@
 		OSSafeReleaseNULL(listeners);
 	}
 
-	return ret;
+	return kIOReturnSuccess;
 }
 
 kern_return_t