xref: /xnu-11215/iokit/Kernel/IOUserServer.cpp (revision bb611c8f)
1 /*
2  * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <IOKit/IORPC.h>
30 #include <IOKit/IOKitServer.h>
31 #include <IOKit/IOKitKeysPrivate.h>
32 #include <IOKit/IOUserClient.h>
33 #include <IOKit/IOService.h>
34 #include <IOKit/IORegistryEntry.h>
35 #include <IOKit/IOCatalogue.h>
36 #include <IOKit/IOMemoryDescriptor.h>
37 #include <IOKit/IOBufferMemoryDescriptor.h>
38 #include <IOKit/IOSubMemoryDescriptor.h>
39 #include <IOKit/IOMultiMemoryDescriptor.h>
40 #include <IOKit/IOMapper.h>
41 #include <IOKit/IOLib.h>
42 #include <IOKit/IOBSD.h>
43 #include <IOKit/system.h>
44 #include <IOKit/IOUserServer.h>
45 #include <IOKit/IOInterruptEventSource.h>
46 #include <IOKit/IOTimerEventSource.h>
47 #include <IOKit/pwr_mgt/RootDomain.h>
48 #include <libkern/c++/OSKext.h>
49 #include <libkern/c++/OSSharedPtr.h>
50 #include <libkern/OSDebug.h>
51 #include <libkern/Block.h>
52 #include <sys/proc.h>
53 #include "IOKitKernelInternal.h"
54 
55 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
56 
57 #include <DriverKit/IODispatchQueue.h>
58 #include <DriverKit/OSObject.h>
59 #include <DriverKit/OSAction.h>
60 #include <DriverKit/IODispatchSource.h>
61 #include <DriverKit/IOInterruptDispatchSource.h>
62 #include <DriverKit/IOService.h>
63 #include <DriverKit/IOMemoryDescriptor.h>
64 #include <DriverKit/IOBufferMemoryDescriptor.h>
65 #include <DriverKit/IOMemoryMap.h>
66 #include <DriverKit/IODataQueueDispatchSource.h>
67 #include <DriverKit/IOServiceNotificationDispatchSource.h>
68 #include <DriverKit/IOUserServer.h>
69 
70 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
71 
72 #include <System/IODataQueueDispatchSourceShared.h>
73 
74 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75 
76 SECURITY_READ_ONLY_LATE(SInt64)    gIODKDebug = kIODKEnable;
77 
78 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
79 
80 struct IOPStrings;
81 
82 class OSUserMetaClass : public OSObject
83 {
84 	OSDeclareDefaultStructors(OSUserMetaClass);
85 public:
86 	const OSSymbol    * name;
87 	const OSMetaClass * meta;
88 	OSUserMetaClass   * superMeta;
89 
90 	queue_chain_t       link;
91 
92 	OSClassDescription * description;
93 	IOPStrings * queueNames;
94 	uint32_t     methodCount;
95 	uint64_t   * methods;
96 
97 	virtual void free() override;
98 	virtual kern_return_t Dispatch(const IORPC rpc) APPLE_KEXT_OVERRIDE;
99 };
100 OSDefineMetaClassAndStructors(OSUserMetaClass, OSObject);
101 
102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
103 
104 class IOUserService : public IOService
105 {
106 	friend class IOService;
107 
108 	OSDeclareDefaultStructors(IOUserService)
109 
110 	virtual bool
111 	start(IOService * provider) APPLE_KEXT_OVERRIDE;
112 };
113 
114 OSDefineMetaClassAndStructors(IOUserService, IOService)
115 
116 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
117 
118 class IOUserUserClient : public IOUserClient
119 {
120 	OSDeclareDefaultStructors(IOUserUserClient);
121 public:
122 	task_t          fTask;
123 
124 	IOReturn                   setTask(task_t task);
125 	virtual void           stop(IOService * provider) APPLE_KEXT_OVERRIDE;
126 	virtual IOReturn       clientClose(void) APPLE_KEXT_OVERRIDE;
127 	virtual IOReturn       setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
128 	virtual IOReturn       externalMethod(uint32_t selector, IOExternalMethodArguments * args,
129 	    IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) APPLE_KEXT_OVERRIDE;
130 	virtual IOReturn           clientMemoryForType(UInt32 type,
131 	    IOOptionBits * options,
132 	    IOMemoryDescriptor ** memory) APPLE_KEXT_OVERRIDE;
133 };
134 
135 OSDefineMetaClassAndStructors(IOUserServerCheckInToken, OSObject);
136 
137 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
138 
139 
140 bool
141 IOUserService::start(IOService * provider)
142 {
143 	bool     ok = true;
144 	IOReturn ret;
145 
146 	ret = Start(provider);
147 	if (kIOReturnSuccess != ret) {
148 		return false;
149 	}
150 
151 	return ok;
152 }
153 
154 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
155 
156 #undef super
157 
158 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
159 
160 struct IODispatchQueue_IVars {
161 	IOUserServer * userServer;
162 	IODispatchQueue   * queue;
163 	queue_chain_t  link;
164 	uint64_t       tid;
165 
166 	mach_port_t    serverPort;
167 };
168 
169 struct OSAction_IVars {
170 	OSObject             * target;
171 	uint64_t               targetmsgid;
172 	uint64_t               msgid;
173 	OSActionAbortedHandler abortedHandler;
174 	size_t                 referenceSize;
175 	OSString             * typeName;
176 	void                 * reference[0];
177 };
178 
179 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
180 
181 kern_return_t
182 IOService::GetRegistryEntryID_Impl(
183 	uint64_t * registryEntryID)
184 {
185 	IOReturn ret = kIOReturnSuccess;
186 
187 	*registryEntryID = getRegistryEntryID();
188 
189 	return ret;
190 }
191 
192 kern_return_t
193 IOService::SetName_Impl(
194 	const char * name)
195 {
196 	IOReturn ret = kIOReturnSuccess;
197 
198 	setName(name);
199 
200 	return ret;
201 }
202 
203 kern_return_t
204 IOService::Start_Impl(
205 	IOService * provider)
206 {
207 	IOReturn ret = kIOReturnSuccess;
208 	return ret;
209 }
210 
211 kern_return_t
212 IOService::RegisterService_Impl()
213 {
214 	IOReturn ret = kIOReturnSuccess;
215 
216 	registerService();
217 
218 	return ret;
219 }
220 
221 kern_return_t
222 IOService::CopyDispatchQueue_Impl(
223 	const char * name,
224 	IODispatchQueue ** queue)
225 {
226 	IODispatchQueue * result;
227 	IOService  * service;
228 	IOReturn     ret;
229 	uint32_t index;
230 
231 	if (!reserved->uvars) {
232 		return kIOReturnError;
233 	}
234 
235 	ret = kIOReturnNotFound;
236 	index = -1U;
237 	if (!strcmp("Default", name)) {
238 		index = 0;
239 	} else if (reserved->uvars->userMeta
240 	    && reserved->uvars->userMeta->queueNames) {
241 		index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
242 		if (index != -1U) {
243 			index++;
244 		}
245 	}
246 	if (index == -1U) {
247 		if ((service = getProvider())) {
248 			ret = service->CopyDispatchQueue(name, queue);
249 		}
250 	} else {
251 		result = reserved->uvars->queueArray[index];
252 		if (result) {
253 			result->retain();
254 			*queue = result;
255 			ret = kIOReturnSuccess;
256 		}
257 	}
258 
259 	return ret;
260 }
261 
262 kern_return_t
263 IOService::SetDispatchQueue_Impl(
264 	const char * name,
265 	IODispatchQueue * queue)
266 {
267 	IOReturn ret = kIOReturnSuccess;
268 	uint32_t index;
269 
270 	if (!reserved->uvars) {
271 		return kIOReturnError;
272 	}
273 
274 	if (kIODKLogSetup & gIODKDebug) {
275 		DKLOG(DKS "::SetDispatchQueue(%s)\n", DKN(this), name);
276 	}
277 	queue->ivars->userServer = reserved->uvars->userServer;
278 	index = -1U;
279 	if (!strcmp("Default", name)) {
280 		index = 0;
281 	} else if (reserved->uvars->userMeta
282 	    && reserved->uvars->userMeta->queueNames) {
283 		index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
284 		if (index != -1U) {
285 			index++;
286 		}
287 	}
288 	if (index == -1U) {
289 		ret = kIOReturnBadArgument;
290 	} else {
291 		reserved->uvars->queueArray[index] = queue;
292 		queue->retain();
293 	}
294 
295 	return ret;
296 }
297 
298 kern_return_t
299 IOService::SetProperties_Impl(
300 	OSDictionary * properties)
301 {
302 	IOUserServer   * us;
303 	OSDictionary   * dict;
304 	IOReturn         ret;
305 
306 	ret = setProperties(properties);
307 
308 	if (kIOReturnUnsupported == ret) {
309 		dict = OSDynamicCast(OSDictionary, properties);
310 		us = (typeof(us))thread_iokit_tls_get(0);
311 		if (dict && reserved->uvars && (reserved->uvars->userServer == us)) {
312 			ret = runPropertyActionBlock(^IOReturn (void) {
313 				OSDictionary   * userProps;
314 				IOReturn         ret;
315 
316 				userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
317 				if (userProps) {
318 				        userProps = (typeof(userProps))userProps->copyCollection();
319 				} else {
320 				        userProps = OSDictionary::withCapacity(4);
321 				}
322 				if (!userProps) {
323 				        ret = kIOReturnNoMemory;
324 				} else {
325 				        bool ok = userProps->merge(dict);
326 				        if (ok) {
327 				                ok = setProperty(gIOUserServicePropertiesKey, userProps);
328 					}
329 				        OSSafeReleaseNULL(userProps);
330 				        ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
331 				}
332 				return ret;
333 			});
334 		}
335 	}
336 
337 	return ret;
338 }
339 
340 kern_return_t
341 IOService::CopyProperties_Impl(
342 	OSDictionary ** properties)
343 {
344 	IOReturn ret = kIOReturnSuccess;
345 	*properties = dictionaryWithProperties();
346 	return ret;
347 }
348 
349 kern_return_t
350 IOService::RequireMaxBusStall_Impl(
351 	uint64_t u64ns)
352 {
353 	IOReturn ret;
354 	UInt32   ns;
355 
356 	if (os_convert_overflow(u64ns, &ns)) {
357 		return kIOReturnBadArgument;
358 	}
359 	ret = requireMaxBusStall(ns);
360 
361 	return kIOReturnSuccess;
362 }
363 
364 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
365 
366 kern_return_t
367 IOMemoryDescriptor::_CopyState_Impl(
368 	_IOMDPrivateState * state)
369 {
370 	IOReturn ret;
371 
372 	state->length = _length;
373 	state->options = _flags;
374 
375 	ret = kIOReturnSuccess;
376 
377 	return ret;
378 }
379 
380 kern_return_t
381 IOMemoryDescriptor::GetLength(uint64_t * returnLength)
382 {
383 	*returnLength = getLength();
384 
385 	return kIOReturnSuccess;
386 }
387 
388 kern_return_t
389 IOMemoryDescriptor::CreateMapping_Impl(
390 	uint64_t options,
391 	uint64_t address,
392 	uint64_t offset,
393 	uint64_t length,
394 	uint64_t alignment,
395 	IOMemoryMap ** map)
396 {
397 	IOReturn          ret;
398 	IOMemoryMap     * resultMap;
399 	IOOptionBits      koptions;
400 	mach_vm_address_t atAddress;
401 
402 	ret       = kIOReturnSuccess;
403 	koptions  = 0;
404 	resultMap = NULL;
405 
406 	if (kIOMemoryMapFixedAddress & options) {
407 		atAddress   = address;
408 		koptions    = 0;
409 	} else {
410 		atAddress   = 0;
411 		koptions   |= kIOMapAnywhere;
412 	}
413 
414 	if (kIOMemoryMapReadOnly & options || (kIODirectionOut == getDirection())) {
415 		if (!reserved || (current_task() != reserved->creator)) {
416 			koptions   |= kIOMapReadOnly;
417 		}
418 	}
419 
420 	switch (0xFF00 & options) {
421 	case kIOMemoryMapCacheModeDefault:
422 		koptions |= kIOMapDefaultCache;
423 		break;
424 	case kIOMemoryMapCacheModeInhibit:
425 		koptions |= kIOMapInhibitCache;
426 		break;
427 	case kIOMemoryMapCacheModeCopyback:
428 		koptions |= kIOMapCopybackCache;
429 		break;
430 	case kIOMemoryMapCacheModeWriteThrough:
431 		koptions |= kIOMapWriteThruCache;
432 		break;
433 	default:
434 		ret = kIOReturnBadArgument;
435 	}
436 
437 	if (kIOReturnSuccess == ret) {
438 		resultMap = createMappingInTask(current_task(), atAddress, koptions, offset, length);
439 		if (!resultMap) {
440 			ret = kIOReturnError;
441 		}
442 	}
443 
444 	*map = resultMap;
445 
446 	return ret;
447 }
448 
449 kern_return_t
450 IOMemoryDescriptor::CreateSubMemoryDescriptor_Impl(
451 	uint64_t memoryDescriptorCreateOptions,
452 	uint64_t offset,
453 	uint64_t length,
454 	IOMemoryDescriptor * ofDescriptor,
455 	IOMemoryDescriptor ** memory)
456 {
457 	IOReturn             ret;
458 	IOMemoryDescriptor * iomd;
459 	IOByteCount          mdOffset;
460 	IOByteCount          mdLength;
461 	IOByteCount          mdEnd;
462 
463 	if (!ofDescriptor) {
464 		return kIOReturnBadArgument;
465 	}
466 	if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
467 		return kIOReturnBadArgument;
468 	}
469 	if (os_convert_overflow(offset, &mdOffset)) {
470 		return kIOReturnBadArgument;
471 	}
472 	if (os_convert_overflow(length, &mdLength)) {
473 		return kIOReturnBadArgument;
474 	}
475 	if (os_add_overflow(mdOffset, mdLength, &mdEnd)) {
476 		return kIOReturnBadArgument;
477 	}
478 	if (mdEnd > ofDescriptor->getLength()) {
479 		return kIOReturnBadArgument;
480 	}
481 
482 	iomd = IOSubMemoryDescriptor::withSubRange(
483 		ofDescriptor, mdOffset, mdLength, (IOOptionBits) memoryDescriptorCreateOptions);
484 
485 	if (iomd) {
486 		ret = kIOReturnSuccess;
487 		*memory = iomd;
488 	} else {
489 		ret = kIOReturnNoMemory;
490 		*memory = NULL;
491 	}
492 
493 	return ret;
494 }
495 
496 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
497 
498 kern_return_t
499 IOMemoryDescriptor::CreateWithMemoryDescriptors_Impl(
500 	uint64_t memoryDescriptorCreateOptions,
501 	uint32_t withDescriptorsCount,
502 	IOMemoryDescriptor ** const withDescriptors,
503 	IOMemoryDescriptor ** memory)
504 {
505 	IOReturn             ret;
506 	IOMemoryDescriptor * iomd;
507 
508 	if (!withDescriptors) {
509 		return kIOReturnBadArgument;
510 	}
511 	if (!withDescriptorsCount) {
512 		return kIOReturnBadArgument;
513 	}
514 	if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
515 		return kIOReturnBadArgument;
516 	}
517 
518 	for (unsigned int idx = 0; idx < withDescriptorsCount; idx++) {
519 		if (NULL == withDescriptors[idx]) {
520 			return kIOReturnBadArgument;
521 		}
522 	}
523 
524 	iomd = IOMultiMemoryDescriptor::withDescriptors(withDescriptors, withDescriptorsCount,
525 	    (IODirection) memoryDescriptorCreateOptions, false);
526 
527 	if (iomd) {
528 		ret = kIOReturnSuccess;
529 		*memory = iomd;
530 	} else {
531 		ret = kIOReturnNoMemory;
532 		*memory = NULL;
533 	}
534 
535 	return ret;
536 }
537 
538 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * * * * * * * * * * */
539 
540 kern_return_t
541 IOUserClient::CreateMemoryDescriptorFromClient_Impl(
542 	uint64_t memoryDescriptorCreateOptions,
543 	uint32_t segmentsCount,
544 	const IOAddressSegment segments[32],
545 	IOMemoryDescriptor ** memory)
546 {
547 	IOReturn             ret;
548 	IOMemoryDescriptor * iomd;
549 	IOOptionBits         mdOptions;
550 	IOUserUserClient   * me;
551 	IOAddressRange     * ranges;
552 
553 	me = OSDynamicCast(IOUserUserClient, this);
554 	if (!me) {
555 		return kIOReturnBadArgument;
556 	}
557 
558 	mdOptions = 0;
559 	if (kIOMemoryDirectionOut & memoryDescriptorCreateOptions) {
560 		mdOptions |= kIODirectionOut;
561 	}
562 	if (kIOMemoryDirectionIn & memoryDescriptorCreateOptions) {
563 		mdOptions |= kIODirectionIn;
564 	}
565 	if (!(kIOMemoryDisableCopyOnWrite & memoryDescriptorCreateOptions)) {
566 		mdOptions |= kIOMemoryMapCopyOnWrite;
567 	}
568 
569 	static_assert(sizeof(IOAddressRange) == sizeof(IOAddressSegment));
570 	ranges = __DECONST(IOAddressRange *, &segments[0]);
571 
572 	iomd = IOMemoryDescriptor::withAddressRanges(
573 		ranges, segmentsCount,
574 		mdOptions, me->fTask);
575 
576 	if (iomd) {
577 		ret = kIOReturnSuccess;
578 		*memory = iomd;
579 	} else {
580 		ret = kIOReturnNoMemory;
581 		*memory = NULL;
582 	}
583 
584 	return ret;
585 }
586 
587 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
588 
589 kern_return_t
590 IOMemoryMap::_CopyState_Impl(
591 	_IOMemoryMapPrivateState * state)
592 {
593 	IOReturn ret;
594 
595 	state->offset  = fOffset;
596 	state->length  = getLength();
597 	state->address = getAddress();
598 	state->options = getMapOptions();
599 
600 	ret = kIOReturnSuccess;
601 
602 	return ret;
603 }
604 
605 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
606 
607 kern_return_t
608 IOBufferMemoryDescriptor::Create_Impl(
609 	uint64_t options,
610 	uint64_t capacity,
611 	uint64_t alignment,
612 	IOBufferMemoryDescriptor ** memory)
613 {
614 	IOReturn ret;
615 	IOOptionBits                 bmdOptions;
616 	IOBufferMemoryDescriptor   * bmd;
617 	IOMemoryDescriptorReserved * reserved;
618 
619 	if (options & ~((uint64_t) kIOMemoryDirectionOutIn)) {
620 		// no other options currently defined
621 		return kIOReturnBadArgument;
622 	}
623 	bmdOptions = (options & kIOMemoryDirectionOutIn) | kIOMemoryKernelUserShared;
624 	bmd = IOBufferMemoryDescriptor::inTaskWithOptions(
625 		kernel_task, bmdOptions, capacity, alignment);
626 
627 	*memory = bmd;
628 
629 	if (!bmd) {
630 		return kIOReturnNoMemory;
631 	}
632 
633 	reserved = bmd->getKernelReserved();
634 	reserved->creator = current_task();
635 	task_reference(reserved->creator);
636 
637 	ret = kIOReturnSuccess;
638 
639 	return ret;
640 }
641 
642 kern_return_t
643 IOBufferMemoryDescriptor::SetLength_Impl(
644 	uint64_t length)
645 {
646 	setLength(length);
647 	return kIOReturnSuccess;
648 }
649 
650 
651 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
652 
653 kern_return_t
654 IODMACommand::Create_Impl(
655 	IOService * device,
656 	uint64_t options,
657 	const IODMACommandSpecification * specification,
658 	IODMACommand ** command)
659 {
660 	IOReturn ret;
661 	IODMACommand   * dma;
662 	IODMACommand::SegmentOptions segmentOptions;
663 	IOMapper             * mapper;
664 
665 	if (options & ~((uint64_t) kIODMACommandCreateNoOptions)) {
666 		// no other options currently defined
667 		return kIOReturnBadArgument;
668 	}
669 
670 	if (os_convert_overflow(specification->maxAddressBits, &segmentOptions.fNumAddressBits)) {
671 		return kIOReturnBadArgument;
672 	}
673 	segmentOptions.fMaxSegmentSize            = 0;
674 	segmentOptions.fMaxTransferSize           = 0;
675 	segmentOptions.fAlignment                 = 1;
676 	segmentOptions.fAlignmentLength           = 1;
677 	segmentOptions.fAlignmentInternalSegments = 1;
678 	segmentOptions.fStructSize                = sizeof(segmentOptions);
679 
680 	mapper = IOMapper::copyMapperForDevice(device);
681 
682 	dma = IODMACommand::withSpecification(
683 		kIODMACommandOutputHost64,
684 		&segmentOptions,
685 		kIODMAMapOptionMapped,
686 		mapper,
687 		NULL);
688 
689 	OSSafeReleaseNULL(mapper);
690 	*command = dma;
691 
692 	if (!dma) {
693 		return kIOReturnNoMemory;
694 	}
695 	ret = kIOReturnSuccess;
696 
697 	return ret;
698 }
699 
700 kern_return_t
701 IODMACommand::PrepareForDMA_Impl(
702 	uint64_t options,
703 	IOMemoryDescriptor * memory,
704 	uint64_t offset,
705 	uint64_t length,
706 	uint64_t * flags,
707 	uint32_t * segmentsCount,
708 	IOAddressSegment * segments)
709 {
710 	IOReturn ret;
711 	uint64_t lflags, mdFlags;
712 	UInt32   numSegments;
713 	UInt64   genOffset;
714 
715 	if (options & ~((uint64_t) kIODMACommandPrepareForDMANoOptions)) {
716 		// no other options currently defined
717 		return kIOReturnBadArgument;
718 	}
719 
720 	// uses IOMD direction
721 	ret = memory->prepare();
722 	if (kIOReturnSuccess != ret) {
723 		return ret;
724 	}
725 
726 	ret = setMemoryDescriptor(memory, false);
727 	if (kIOReturnSuccess != ret) {
728 		memory->complete();
729 		return ret;
730 	}
731 
732 	ret = prepare(offset, length);
733 	if (kIOReturnSuccess != ret) {
734 		clearMemoryDescriptor(false);
735 		memory->complete();
736 		return ret;
737 	}
738 
739 	static_assert(sizeof(IODMACommand::Segment64) == sizeof(IOAddressSegment));
740 
741 	numSegments = *segmentsCount;
742 	genOffset   = offset;
743 	ret = genIOVMSegments(&genOffset, segments, &numSegments);
744 
745 	if (kIOReturnSuccess == ret) {
746 		mdFlags = fMemory->getFlags();
747 		lflags  = 0;
748 		if (kIODirectionOut & mdFlags) {
749 			lflags |= kIOMemoryDirectionOut;
750 		}
751 		if (kIODirectionIn & mdFlags) {
752 			lflags |= kIOMemoryDirectionIn;
753 		}
754 		*flags = lflags;
755 		*segmentsCount = numSegments;
756 	}
757 
758 	return ret;
759 }
760 
761 kern_return_t
762 IODMACommand::CompleteDMA_Impl(
763 	uint64_t options)
764 {
765 	IOReturn ret, completeRet;
766 	IOMemoryDescriptor * md;
767 
768 	if (options & ~((uint64_t) kIODMACommandCompleteDMANoOptions)) {
769 		// no other options currently defined
770 		return kIOReturnBadArgument;
771 	}
772 	if (!fActive) {
773 		return kIOReturnNotReady;
774 	}
775 
776 	md = __DECONST(IOMemoryDescriptor *, fMemory);
777 	if (md) {
778 		md->retain();
779 	}
780 
781 	ret = clearMemoryDescriptor(true);
782 
783 	if (md) {
784 		completeRet = md->complete();
785 		OSSafeReleaseNULL(md);
786 		if (kIOReturnSuccess == ret) {
787 			ret = completeRet;
788 		}
789 	}
790 
791 	return ret;
792 }
793 
794 kern_return_t
795 IODMACommand::GetPreparation_Impl(
796 	uint64_t * offset,
797 	uint64_t * length,
798 	IOMemoryDescriptor ** memory)
799 {
800 	IOReturn ret;
801 	IOMemoryDescriptor * md;
802 
803 	if (!fActive) {
804 		return kIOReturnNotReady;
805 	}
806 
807 	ret = getPreparedOffsetAndLength(offset, length);
808 	if (kIOReturnSuccess != ret) {
809 		return ret;
810 	}
811 
812 	if (memory) {
813 		md = __DECONST(IOMemoryDescriptor *, fMemory);
814 		*memory = md;
815 		if (!md) {
816 			ret = kIOReturnNotReady;
817 		} else {
818 			md->retain();
819 		}
820 	}
821 	return ret;
822 }
823 
824 kern_return_t
825 IODMACommand::PerformOperation_Impl(
826 	uint64_t options,
827 	uint64_t dmaOffset,
828 	uint64_t length,
829 	uint64_t dataOffset,
830 	IOMemoryDescriptor * data)
831 {
832 	IOReturn ret;
833 	void * buffer;
834 	UInt64 copiedDMA;
835 	IOByteCount mdOffset, mdLength, copied;
836 
837 	if (options & ~((uint64_t)
838 	    (kIODMACommandPerformOperationOptionRead
839 	    | kIODMACommandPerformOperationOptionWrite
840 	    | kIODMACommandPerformOperationOptionZero))) {
841 		// no other options currently defined
842 		return kIOReturnBadArgument;
843 	}
844 
845 	if (!fActive) {
846 		return kIOReturnNotReady;
847 	}
848 	if (os_convert_overflow(dataOffset, &mdOffset)) {
849 		return kIOReturnBadArgument;
850 	}
851 	if (os_convert_overflow(length, &mdLength)) {
852 		return kIOReturnBadArgument;
853 	}
854 	if (length > fMemory->getLength()) {
855 		return kIOReturnBadArgument;
856 	}
857 	buffer = IONew(uint8_t, length);
858 	if (NULL == buffer) {
859 		return kIOReturnNoMemory;
860 	}
861 
862 	switch (options) {
863 	case kIODMACommandPerformOperationOptionZero:
864 		bzero(buffer, length);
865 		copiedDMA = writeBytes(dmaOffset, buffer, length);
866 		if (copiedDMA != length) {
867 			ret = kIOReturnUnderrun;
868 			break;
869 		}
870 		ret = kIOReturnSuccess;
871 		break;
872 
873 	case kIODMACommandPerformOperationOptionRead:
874 	case kIODMACommandPerformOperationOptionWrite:
875 
876 		if (!data) {
877 			ret = kIOReturnBadArgument;
878 			break;
879 		}
880 		if (length > data->getLength()) {
881 			ret = kIOReturnBadArgument;
882 			break;
883 		}
884 		if (kIODMACommandPerformOperationOptionWrite == options) {
885 			copied = data->readBytes(mdOffset, buffer, mdLength);
886 			if (copied != mdLength) {
887 				ret = kIOReturnUnderrun;
888 				break;
889 			}
890 			copiedDMA = writeBytes(dmaOffset, buffer, length);
891 			if (copiedDMA != length) {
892 				ret = kIOReturnUnderrun;
893 				break;
894 			}
895 		} else {       /* kIODMACommandPerformOperationOptionRead */
896 			copiedDMA = readBytes(dmaOffset, buffer, length);
897 			if (copiedDMA != length) {
898 				ret = kIOReturnUnderrun;
899 				break;
900 			}
901 			copied = data->writeBytes(mdOffset, buffer, mdLength);
902 			if (copied != mdLength) {
903 				ret = kIOReturnUnderrun;
904 				break;
905 			}
906 		}
907 		ret = kIOReturnSuccess;
908 		break;
909 	default:
910 		ret = kIOReturnBadArgument;
911 		break;
912 	}
913 
914 	IODelete(buffer, uint8_t, length);
915 
916 	return ret;
917 }
918 
919 
920 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
921 
922 static kern_return_t
923 OSActionCreateWithTypeNameInternal(OSObject * target, uint64_t targetmsgid, uint64_t msgid, size_t referenceSize, OSString * typeName, bool fromKernel, OSAction ** action)
924 {
925 	OSAction * inst = NULL;
926 	vm_size_t  allocsize;
927 	const OSSymbol *sym = NULL; // must release
928 	OSObject *obj = NULL; // must release
929 	const OSMetaClass *actionMetaClass = NULL; // do not release
930 	kern_return_t ret;
931 
932 	if (os_add_overflow(referenceSize, sizeof(OSAction_IVars), &allocsize)) {
933 		ret = kIOReturnBadArgument;
934 		goto finish;
935 	}
936 
937 	if (fromKernel && typeName) {
938 		/* The action is being constructed in the kernel with a type name */
939 		sym = OSSymbol::withString(typeName);
940 		actionMetaClass = OSMetaClass::getMetaClassWithName(sym);
941 		if (actionMetaClass && actionMetaClass->getSuperClass() == OSTypeID(OSAction)) {
942 			obj = actionMetaClass->alloc();
943 			if (!obj) {
944 				ret = kIOReturnNoMemory;
945 				goto finish;
946 			}
947 			inst = OSDynamicCast(OSAction, obj);
948 			obj = NULL; // prevent release
949 			assert(inst); // obj is a subclass of OSAction so the dynamic cast should always work
950 		} else {
951 			DKLOG("Attempted to create action object with type \"%s\" which does not inherit from OSAction\n", typeName->getCStringNoCopy());
952 			ret = kIOReturnBadArgument;
953 			goto finish;
954 		}
955 	} else {
956 		inst = OSTypeAlloc(OSAction);
957 		if (!inst) {
958 			ret = kIOReturnNoMemory;
959 			goto finish;
960 		}
961 	}
962 
963 	inst->ivars = (typeof(inst->ivars))(uintptr_t) IONewZero(uint8_t, allocsize);
964 	if (!inst->ivars) {
965 		ret = kIOReturnNoMemory;
966 		goto finish;
967 	}
968 	target->retain();
969 	inst->ivars->target        = target;
970 	inst->ivars->targetmsgid   = targetmsgid;
971 	inst->ivars->msgid         = msgid;
972 	inst->ivars->referenceSize = referenceSize;
973 	if (typeName) {
974 		typeName->retain();
975 	}
976 	inst->ivars->typeName      = typeName;
977 
978 	*action = inst;
979 	inst = NULL; // prevent release
980 	ret = kIOReturnSuccess;
981 
982 finish:
983 	OSSafeReleaseNULL(obj);
984 	OSSafeReleaseNULL(sym);
985 	OSSafeReleaseNULL(inst);
986 
987 	return ret;
988 }
989 
990 kern_return_t
991 OSAction::Create(OSAction_Create_Args)
992 {
993 	return OSAction::CreateWithTypeName(target, targetmsgid, msgid, referenceSize, NULL, action);
994 }
995 
996 kern_return_t
997 OSAction::CreateWithTypeName(OSAction_CreateWithTypeName_Args)
998 {
999 	return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, true, action);
1000 }
1001 
1002 kern_return_t
1003 OSAction::Create_Impl(
1004 	OSObject * target,
1005 	uint64_t targetmsgid,
1006 	uint64_t msgid,
1007 	size_t referenceSize,
1008 	OSAction ** action)
1009 {
1010 	return OSAction::CreateWithTypeName_Impl(target, targetmsgid, msgid, referenceSize, NULL, action);
1011 }
1012 
1013 kern_return_t
1014 OSAction::CreateWithTypeName_Impl(
1015 	OSObject * target,
1016 	uint64_t targetmsgid,
1017 	uint64_t msgid,
1018 	size_t referenceSize,
1019 	OSString * typeName,
1020 	OSAction ** action)
1021 {
1022 	return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, false, action);
1023 }
1024 
1025 void
1026 OSAction::free()
1027 {
1028 	if (ivars) {
1029 		if (ivars->abortedHandler) {
1030 			Block_release(ivars->abortedHandler);
1031 			ivars->abortedHandler = NULL;
1032 		}
1033 		OSSafeReleaseNULL(ivars->target);
1034 		OSSafeReleaseNULL(ivars->typeName);
1035 		IOSafeDeleteNULL(ivars, uint8_t, ivars->referenceSize + sizeof(OSAction_IVars));
1036 	}
1037 	return super::free();
1038 }
1039 
1040 void *
1041 OSAction::GetReference()
1042 {
1043 	assert(ivars && ivars->referenceSize);
1044 	return &ivars->reference[0];
1045 }
1046 
1047 kern_return_t
1048 OSAction::SetAbortedHandler(OSActionAbortedHandler handler)
1049 {
1050 	ivars->abortedHandler = Block_copy(handler);
1051 	return kIOReturnSuccess;
1052 }
1053 
1054 void
1055 OSAction::Aborted_Impl(void)
1056 {
1057 	if (ivars->abortedHandler) {
1058 		ivars->abortedHandler();
1059 	}
1060 }
1061 
1062 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1063 
1064 struct IODispatchSource_IVars {
1065 	queue_chain_t           link;
1066 	IODispatchSource      * source;
1067 	IOUserServer          * server;
1068 	IODispatchQueue_IVars * queue;
1069 	bool                    enabled;
1070 };
1071 
1072 bool
1073 IODispatchSource::init()
1074 {
1075 	if (!super::init()) {
1076 		return false;
1077 	}
1078 
1079 	ivars = IONewZero(IODispatchSource_IVars, 1);
1080 
1081 	ivars->source = this;
1082 
1083 	return true;
1084 }
1085 
1086 void
1087 IODispatchSource::free()
1088 {
1089 	IOSafeDeleteNULL(ivars, IODispatchSource_IVars, 1);
1090 	super::free();
1091 }
1092 
1093 kern_return_t
1094 IODispatchSource::SetEnable_Impl(
1095 	bool enable)
1096 {
1097 	return SetEnableWithCompletion(enable, NULL);
1098 }
1099 
1100 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1101 
1102 struct IOInterruptDispatchSource_IVars {
1103 	IOService    * provider;
1104 	uint32_t       intIndex;
1105 	int            interruptType;
1106 	IOSimpleLock * lock;
1107 	thread_t       waiter;
1108 	uint64_t       count;
1109 	uint64_t       time;
1110 	OSAction     * action;
1111 	bool           enable;
1112 };
1113 
1114 static void
1115 IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
1116     IOService * nub, int source )
1117 {
1118 	IOInterruptDispatchSource_IVars * ivars = (typeof(ivars))refCon;
1119 	IOInterruptState is;
1120 
1121 	is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1122 	ivars->count++;
1123 	if (ivars->waiter) {
1124 		ivars->time = mach_absolute_time();
1125 		thread_wakeup_thread((event_t) ivars, ivars->waiter);
1126 		ivars->waiter = NULL;
1127 	}
1128 	if (kIOInterruptTypeLevel & ivars->interruptType) {
1129 		ivars->provider->disableInterrupt(ivars->intIndex);
1130 	}
1131 	IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1132 }
1133 
1134 kern_return_t
1135 IOInterruptDispatchSource::Create_Impl(
1136 	IOService * provider,
1137 	uint32_t index,
1138 	IODispatchQueue * queue,
1139 	IOInterruptDispatchSource ** source)
1140 {
1141 	IOReturn ret;
1142 	IOInterruptDispatchSource * inst;
1143 
1144 	inst = OSTypeAlloc(IOInterruptDispatchSource);
1145 	if (!inst->init()) {
1146 		inst->free();
1147 		return kIOReturnNoMemory;
1148 	}
1149 
1150 	inst->ivars->lock = IOSimpleLockAlloc();
1151 
1152 	ret = provider->getInterruptType(index, &inst->ivars->interruptType);
1153 	if (kIOReturnSuccess != ret) {
1154 		OSSafeReleaseNULL(inst);
1155 		return ret;
1156 	}
1157 	ret = provider->registerInterrupt(index, inst, IOInterruptDispatchSourceInterrupt, inst->ivars);
1158 	if (kIOReturnSuccess == ret) {
1159 		inst->ivars->intIndex = index;
1160 		inst->ivars->provider = provider;
1161 		inst->ivars->provider->retain();
1162 		*source = inst;
1163 	}
1164 	return ret;
1165 }
1166 
1167 kern_return_t
1168 IOInterruptDispatchSource::GetInterruptType_Impl(
1169 	IOService * provider,
1170 	uint32_t index,
1171 	uint64_t * interruptType)
1172 {
1173 	IOReturn ret;
1174 	int      type;
1175 
1176 	*interruptType = 0;
1177 	ret = provider->getInterruptType(index, &type);
1178 	if (kIOReturnSuccess == ret) {
1179 		*interruptType = type;
1180 	}
1181 
1182 	return ret;
1183 }
1184 
1185 bool
1186 IOInterruptDispatchSource::init()
1187 {
1188 	if (!super::init()) {
1189 		return false;
1190 	}
1191 	ivars = IONewZero(IOInterruptDispatchSource_IVars, 1);
1192 	if (!ivars) {
1193 		return false;
1194 	}
1195 
1196 	return true;
1197 }
1198 
1199 void
1200 IOInterruptDispatchSource::free()
1201 {
1202 	IOReturn ret;
1203 
1204 	if (ivars && ivars->provider) {
1205 		ret = ivars->provider->unregisterInterrupt(ivars->intIndex);
1206 		assert(kIOReturnSuccess == ret);
1207 		ivars->provider->release();
1208 	}
1209 
1210 	if (ivars && ivars->lock) {
1211 		IOSimpleLockFree(ivars->lock);
1212 	}
1213 
1214 	IOSafeDeleteNULL(ivars, IOInterruptDispatchSource_IVars, 1);
1215 
1216 	super::free();
1217 }
1218 
1219 kern_return_t
1220 IOInterruptDispatchSource::SetHandler_Impl(
1221 	OSAction * action)
1222 {
1223 	IOReturn ret;
1224 	OSAction * oldAction;
1225 
1226 	oldAction = (typeof(oldAction))ivars->action;
1227 	if (oldAction && OSCompareAndSwapPtr(oldAction, NULL, &ivars->action)) {
1228 		oldAction->release();
1229 	}
1230 	action->retain();
1231 	ivars->action = action;
1232 
1233 	ret = kIOReturnSuccess;
1234 
1235 	return ret;
1236 }
1237 
1238 kern_return_t
1239 IOInterruptDispatchSource::SetEnableWithCompletion_Impl(
1240 	bool enable,
1241 	IODispatchSourceCancelHandler handler)
1242 {
1243 	IOReturn ret;
1244 	IOInterruptState is;
1245 
1246 	if (enable == ivars->enable) {
1247 		return kIOReturnSuccess;
1248 	}
1249 
1250 	if (enable) {
1251 		is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1252 		ivars->enable = enable;
1253 		IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1254 		ret = ivars->provider->enableInterrupt(ivars->intIndex);
1255 	} else {
1256 		ret = ivars->provider->disableInterrupt(ivars->intIndex);
1257 		is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1258 		ivars->enable = enable;
1259 		IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1260 	}
1261 
1262 	return ret;
1263 }
1264 
1265 kern_return_t
1266 IOInterruptDispatchSource::Cancel_Impl(
1267 	IODispatchSourceCancelHandler handler)
1268 {
1269 	return kIOReturnUnsupported;
1270 }
1271 
1272 kern_return_t
1273 IOInterruptDispatchSource::CheckForWork_Impl(
1274 	const IORPC rpc,
1275 	bool synchronous)
1276 {
1277 	IOReturn         ret = kIOReturnNotReady;
1278 	IOInterruptState is;
1279 	bool             willWait;
1280 	wait_result_t    waitResult;
1281 	uint64_t         icount;
1282 	uint64_t         itime;
1283 	thread_t         self;
1284 
1285 	self = current_thread();
1286 	icount = 0;
1287 	do {
1288 		is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1289 		if ((icount = ivars->count)) {
1290 			itime = ivars->time;
1291 			ivars->count = 0;
1292 			waitResult = THREAD_AWAKENED;
1293 		} else if (synchronous) {
1294 			assert(NULL == ivars->waiter);
1295 			ivars->waiter = self;
1296 			waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
1297 		}
1298 		willWait = (synchronous && (waitResult == THREAD_WAITING));
1299 		if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
1300 			ivars->provider->enableInterrupt(ivars->intIndex);
1301 		}
1302 		IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1303 		if (willWait) {
1304 			waitResult = thread_block(THREAD_CONTINUE_NULL);
1305 			if (THREAD_INTERRUPTED == waitResult) {
1306 				is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1307 				ivars->waiter = NULL;
1308 				IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1309 				break;
1310 			}
1311 		}
1312 	} while (synchronous && !icount);
1313 
1314 	if (icount && ivars->action) {
1315 		ret = InterruptOccurred(rpc, ivars->action, icount, itime);
1316 	}
1317 
1318 	return ret;
1319 }
1320 
1321 void
1322 IOInterruptDispatchSource::InterruptOccurred_Impl(
1323 	OSAction * action,
1324 	uint64_t count,
1325 	uint64_t time)
1326 {
1327 }
1328 
1329 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1330 
1331 enum {
1332 	kIOServiceNotificationTypeCount = kIOServiceNotificationTypeLast + 1,
1333 };
1334 
1335 struct IOServiceNotificationDispatchSource_IVars {
1336 	OSObject     * serverName;
1337 	OSAction     * action;
1338 	IOLock       * lock;
1339 	IONotifier   * notifier;
1340 	OSDictionary * interestNotifiers;
1341 	OSArray      * pending[kIOServiceNotificationTypeCount];
1342 	bool           enable;
1343 };
1344 
1345 kern_return_t
1346 IOServiceNotificationDispatchSource::Create_Impl(
1347 	OSDictionary * matching,
1348 	uint64_t options,
1349 	IODispatchQueue * queue,
1350 	IOServiceNotificationDispatchSource ** notification)
1351 {
1352 	IOUserServer * us;
1353 	IOReturn       ret;
1354 	IOServiceNotificationDispatchSource * inst;
1355 
1356 	inst = OSTypeAlloc(IOServiceNotificationDispatchSource);
1357 	if (!inst->init()) {
1358 		OSSafeReleaseNULL(inst);
1359 		return kIOReturnNoMemory;
1360 	}
1361 
1362 	us = (typeof(us))thread_iokit_tls_get(0);
1363 	assert(OSDynamicCast(IOUserServer, us));
1364 	if (!us) {
1365 		OSSafeReleaseNULL(inst);
1366 		return kIOReturnError;
1367 	}
1368 	inst->ivars->serverName = us->copyProperty(gIOUserServerNameKey);
1369 	if (!inst->ivars->serverName) {
1370 		OSSafeReleaseNULL(inst);
1371 		return kIOReturnNoMemory;
1372 	}
1373 
1374 	inst->ivars->lock    = IOLockAlloc();
1375 	if (!inst->ivars->lock) {
1376 		OSSafeReleaseNULL(inst);
1377 		return kIOReturnNoMemory;
1378 	}
1379 	for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1380 		inst->ivars->pending[idx] = OSArray::withCapacity(4);
1381 		if (!inst->ivars->pending[idx]) {
1382 			OSSafeReleaseNULL(inst);
1383 			return kIOReturnNoMemory;
1384 		}
1385 	}
1386 	inst->ivars->interestNotifiers = OSDictionary::withCapacity(4);
1387 	if (!inst->ivars->interestNotifiers) {
1388 		OSSafeReleaseNULL(inst);
1389 		return kIOReturnNoMemory;
1390 	}
1391 
1392 	inst->ivars->notifier = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0 /*priority*/,
1393 	    ^bool (IOService * newService, IONotifier * notifier) {
1394 		bool         notifyReady = false;
1395 		IONotifier * interest;
1396 		OSObject   * serverName;
1397 		bool         okToUse;
1398 
1399 		serverName = newService->copyProperty(gIOUserServerNameKey);
1400 		okToUse = (serverName && inst->ivars->serverName->isEqualTo(serverName));
1401 		OSSafeReleaseNULL(serverName);
1402 		if (!okToUse) {
1403 		        return false;
1404 		}
1405 
1406 		IOLockLock(inst->ivars->lock);
1407 		notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeMatched]->getCount());
1408 		inst->ivars->pending[kIOServiceNotificationTypeMatched]->setObject(newService);
1409 		IOLockUnlock(inst->ivars->lock);
1410 
1411 		interest = newService->registerInterest(gIOGeneralInterest,
1412 		^IOReturn (uint32_t messageType, IOService * provider,
1413 		void * messageArgument, size_t argSize) {
1414 			IONotifier * interest;
1415 			bool         notifyReady = false;
1416 
1417 			switch (messageType) {
1418 			case kIOMessageServiceIsTerminated:
1419 				IOLockLock(inst->ivars->lock);
1420 				notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeTerminated]->getCount());
1421 				inst->ivars->pending[kIOServiceNotificationTypeTerminated]->setObject(provider);
1422 				interest = (typeof(interest))inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService);
1423 				assert(interest);
1424 				interest->remove();
1425 				inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
1426 				IOLockUnlock(inst->ivars->lock);
1427 				break;
1428 			default:
1429 				break;
1430 			}
1431 			if (notifyReady && inst->ivars->action) {
1432 			        inst->ServiceNotificationReady(inst->ivars->action);
1433 			}
1434 			return kIOReturnSuccess;
1435 		});
1436 		if (interest) {
1437 		        IOLockLock(inst->ivars->lock);
1438 		        inst->ivars->interestNotifiers->setObject((const OSSymbol *) newService, interest);
1439 		        IOLockUnlock(inst->ivars->lock);
1440 		}
1441 		if (notifyReady) {
1442 		        if (inst->ivars->action) {
1443 		                inst->ServiceNotificationReady(inst->ivars->action);
1444 			}
1445 		}
1446 		return false;
1447 	});
1448 
1449 	if (!inst->ivars->notifier) {
1450 		OSSafeReleaseNULL(inst);
1451 		ret = kIOReturnError;
1452 	}
1453 
1454 	*notification = inst;
1455 	ret = kIOReturnSuccess;
1456 
1457 	return ret;
1458 }
1459 
1460 kern_return_t
1461 IOServiceNotificationDispatchSource::CopyNextNotification_Impl(
1462 	uint64_t * type,
1463 	IOService ** service,
1464 	uint64_t * options)
1465 {
1466 	IOService * next;
1467 	uint32_t    idx;
1468 
1469 	IOLockLock(ivars->lock);
1470 	for (idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1471 		next = (IOService *) ivars->pending[idx]->getObject(0);
1472 		if (next) {
1473 			next->retain();
1474 			ivars->pending[idx]->removeObject(0);
1475 			break;
1476 		}
1477 	}
1478 	IOLockUnlock(ivars->lock);
1479 
1480 	if (idx == kIOServiceNotificationTypeCount) {
1481 		idx = kIOServiceNotificationTypeNone;
1482 	}
1483 	*type    = idx;
1484 	*service = next;
1485 	*options = 0;
1486 
1487 	return kIOReturnSuccess;
1488 }
1489 
1490 bool
1491 IOServiceNotificationDispatchSource::init()
1492 {
1493 	if (!super::init()) {
1494 		return false;
1495 	}
1496 	ivars = IONewZero(IOServiceNotificationDispatchSource_IVars, 1);
1497 	if (!ivars) {
1498 		return false;
1499 	}
1500 
1501 	return true;
1502 }
1503 
1504 void
1505 IOServiceNotificationDispatchSource::free()
1506 {
1507 	if (ivars) {
1508 		OSSafeReleaseNULL(ivars->serverName);
1509 		if (ivars->interestNotifiers) {
1510 			ivars->interestNotifiers->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
1511 				IONotifier * interest = (typeof(interest))object;
1512 				interest->remove();
1513 				return false;
1514 			});
1515 			OSSafeReleaseNULL(ivars->interestNotifiers);
1516 		}
1517 		for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1518 			OSSafeReleaseNULL(ivars->pending[idx]);
1519 		}
1520 		if (ivars->lock) {
1521 			IOLockFree(ivars->lock);
1522 			ivars->lock = NULL;
1523 		}
1524 		if (ivars->notifier) {
1525 			ivars->notifier->remove();
1526 			ivars->notifier = NULL;
1527 		}
1528 		IOSafeDeleteNULL(ivars, IOServiceNotificationDispatchSource_IVars, 1);
1529 	}
1530 
1531 	super::free();
1532 }
1533 
1534 kern_return_t
1535 IOServiceNotificationDispatchSource::SetHandler_Impl(
1536 	OSAction * action)
1537 {
1538 	IOReturn ret;
1539 	bool     notifyReady;
1540 
1541 	notifyReady = false;
1542 
1543 	IOLockLock(ivars->lock);
1544 	OSSafeReleaseNULL(ivars->action);
1545 	action->retain();
1546 	ivars->action = action;
1547 	if (action) {
1548 		for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1549 			notifyReady = (ivars->pending[idx]->getCount());
1550 			if (notifyReady) {
1551 				break;
1552 			}
1553 		}
1554 	}
1555 	IOLockUnlock(ivars->lock);
1556 
1557 	if (notifyReady) {
1558 		ServiceNotificationReady(action);
1559 	}
1560 	ret = kIOReturnSuccess;
1561 
1562 	return ret;
1563 }
1564 
1565 kern_return_t
1566 IOServiceNotificationDispatchSource::SetEnableWithCompletion_Impl(
1567 	bool enable,
1568 	IODispatchSourceCancelHandler handler)
1569 {
1570 	if (enable == ivars->enable) {
1571 		return kIOReturnSuccess;
1572 	}
1573 
1574 	IOLockLock(ivars->lock);
1575 	ivars->enable = enable;
1576 	IOLockUnlock(ivars->lock);
1577 
1578 	return kIOReturnSuccess;
1579 }
1580 
1581 kern_return_t
1582 IOServiceNotificationDispatchSource::Cancel_Impl(
1583 	IODispatchSourceCancelHandler handler)
1584 {
1585 	return kIOReturnUnsupported;
1586 }
1587 
1588 kern_return_t
1589 IOServiceNotificationDispatchSource::CheckForWork_Impl(
1590 	const IORPC rpc,
1591 	bool synchronous)
1592 {
1593 	return kIOReturnNotReady;
1594 }
1595 
1596 kern_return_t
1597 IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block)
1598 {
1599 	return kIOReturnUnsupported;
1600 }
1601 
1602 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1603 
1604 kern_return_t
1605 IOUserServer::waitInterruptTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
1606 {
1607 	IOReturn         ret = kIOReturnBadArgument;
1608 	IOInterruptState is;
1609 	IOInterruptDispatchSource * interrupt;
1610 	IOInterruptDispatchSource_IVars * ivars;
1611 	IOInterruptDispatchSourcePayload payload;
1612 
1613 	bool             willWait;
1614 	wait_result_t    waitResult;
1615 	thread_t         self;
1616 
1617 	OSObject * object;
1618 
1619 	object = iokit_lookup_object_with_port_name((mach_port_name_t)(uintptr_t)p1, IKOT_UEXT_OBJECT, current_task());
1620 
1621 	if (!object) {
1622 		return kIOReturnBadArgument;
1623 	}
1624 	if (!(interrupt = OSDynamicCast(IOInterruptDispatchSource, object))) {
1625 		ret = kIOReturnBadArgument;
1626 	} else {
1627 		self = current_thread();
1628 		ivars = interrupt->ivars;
1629 		payload.count = 0;
1630 		do {
1631 			is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1632 			if ((payload.count = ivars->count)) {
1633 				payload.time = ivars->time;
1634 				ivars->count = 0;
1635 				waitResult = THREAD_AWAKENED;
1636 			} else {
1637 				assert(NULL == ivars->waiter);
1638 				ivars->waiter = self;
1639 				waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
1640 			}
1641 			willWait = (waitResult == THREAD_WAITING);
1642 			if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
1643 				ivars->provider->enableInterrupt(ivars->intIndex);
1644 			}
1645 			IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1646 			if (willWait) {
1647 				waitResult = thread_block(THREAD_CONTINUE_NULL);
1648 				if (THREAD_INTERRUPTED == waitResult) {
1649 					is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1650 					ivars->waiter = NULL;
1651 					IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1652 					break;
1653 				}
1654 			}
1655 		} while (!payload.count);
1656 		ret = (payload.count ? kIOReturnSuccess : kIOReturnAborted);
1657 	}
1658 
1659 	if (kIOReturnSuccess == ret) {
1660 		int copyerr = copyout(&payload, (user_addr_t) p2, sizeof(payload));
1661 		if (copyerr) {
1662 			ret = kIOReturnVMError;
1663 		}
1664 	}
1665 
1666 	object->release();
1667 
1668 	return ret;
1669 }
1670 
1671 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1672 
1673 kern_return_t
1674 IOUserServer::Create_Impl(
1675 	const char * name,
1676 	uint64_t tag,
1677 	uint64_t options,
1678 	IOUserServer ** server)
1679 {
1680 	IOReturn          ret;
1681 	IOUserServer    * us;
1682 	const OSSymbol  * sym;
1683 	OSNumber        * serverTag;
1684 	io_name_t         rname;
1685 
1686 	us = (typeof(us))thread_iokit_tls_get(0);
1687 	assert(OSDynamicCast(IOUserServer, us));
1688 	if (kIODKLogSetup & gIODKDebug) {
1689 		DKLOG(DKS "::Create(" DKS ") %p\n", DKN(us), name, tag, us);
1690 	}
1691 	if (!us) {
1692 		return kIOReturnError;
1693 	}
1694 
1695 	sym       = OSSymbol::withCString(name);
1696 	serverTag = OSNumber::withNumber(tag, 64);
1697 
1698 	us->setProperty(gIOUserServerNameKey, (OSObject *) sym);
1699 	us->setProperty(gIOUserServerTagKey, serverTag);
1700 
1701 	serverTag->release();
1702 	OSSafeReleaseNULL(sym);
1703 
1704 	snprintf(rname, sizeof(rname), "IOUserServer(%s-0x%qx)", name, tag);
1705 	us->setName(rname);
1706 
1707 	us->retain();
1708 	*server = us;
1709 	ret = kIOReturnSuccess;
1710 
1711 	return ret;
1712 }
1713 
1714 kern_return_t
1715 IOUserServer::Exit_Impl(
1716 	const char * reason)
1717 {
1718 	return kIOReturnUnsupported;
1719 }
1720 
1721 kern_return_t
1722 IOUserServer::LoadModule_Impl(
1723 	const char * path)
1724 {
1725 	return kIOReturnUnsupported;
1726 }
1727 
1728 
1729 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1730 
1731 kern_return_t
1732 IODispatchQueue::Create_Impl(
1733 	const char * name,
1734 	uint64_t options,
1735 	uint64_t priority,
1736 	IODispatchQueue ** queue)
1737 {
1738 	IODispatchQueue * result;
1739 	IOUserServer    * us;
1740 
1741 	result = OSTypeAlloc(IODispatchQueue);
1742 	if (!result) {
1743 		return kIOReturnNoMemory;
1744 	}
1745 	if (!result->init()) {
1746 		return kIOReturnNoMemory;
1747 	}
1748 
1749 	*queue = result;
1750 
1751 	if (!strcmp("Root", name)) {
1752 		us = (typeof(us))thread_iokit_tls_get(0);
1753 		assert(OSDynamicCast(IOUserServer, us));
1754 		us->setRootQueue(result);
1755 	}
1756 
1757 	if (kIODKLogSetup & gIODKDebug) {
1758 		DKLOG("IODispatchQueue::Create %s %p\n", name, result);
1759 	}
1760 
1761 	return kIOReturnSuccess;
1762 }
1763 
1764 kern_return_t
1765 IODispatchQueue::SetPort_Impl(
1766 	mach_port_t port)
1767 {
1768 	if (MACH_PORT_NULL != ivars->serverPort) {
1769 		return kIOReturnNotReady;
1770 	}
1771 
1772 	ivars->serverPort = port;
1773 	return kIOReturnSuccess;
1774 }
1775 
1776 bool
1777 IODispatchQueue::init()
1778 {
1779 	ivars = IONewZero(IODispatchQueue_IVars, 1);
1780 	if (!ivars) {
1781 		return false;
1782 	}
1783 	ivars->queue = this;
1784 
1785 	return true;
1786 }
1787 
1788 void
1789 IODispatchQueue::free()
1790 {
1791 	if (ivars && ivars->serverPort) {
1792 		ipc_port_release_send(ivars->serverPort);
1793 		ivars->serverPort = MACH_PORT_NULL;
1794 	}
1795 	IOSafeDeleteNULL(ivars, IODispatchQueue_IVars, 1);
1796 	super::free();
1797 }
1798 
1799 bool
1800 IODispatchQueue::OnQueue()
1801 {
1802 	return false;
1803 }
1804 
1805 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1806 
1807 
1808 kern_return_t
1809 OSMetaClassBase::Dispatch(IORPC rpc)
1810 {
1811 	return kIOReturnUnsupported;
1812 }
1813 
1814 kern_return_t
1815 OSMetaClassBase::Invoke(IORPC rpc)
1816 {
1817 	IOReturn          ret = kIOReturnUnsupported;
1818 	OSMetaClassBase * object;
1819 	OSAction        * action;
1820 	IOService       * service;
1821 	IOUserServer    * us;
1822 	IORPCMessage    * message;
1823 
1824 	assert(rpc.sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
1825 	message = IORPCMessageFromMach(rpc.message, false);
1826 	if (!message) {
1827 		return kIOReturnIPCError;
1828 	}
1829 	message->flags |= kIORPCMessageKernel;
1830 
1831 	us = NULL;
1832 	if (!(kIORPCMessageLocalHost & message->flags)) {
1833 		us = OSDynamicCast(IOUserServer, this);
1834 		if (!us) {
1835 			if ((action = OSDynamicCast(OSAction, this))) {
1836 				object = IOUserServer::target(action, message);
1837 			} else {
1838 				object = this;
1839 			}
1840 			if ((service = OSDynamicCast(IOService, object))
1841 			    && service->reserved->uvars) {
1842 				// xxx other classes
1843 				us = service->reserved->uvars->userServer;
1844 			}
1845 		}
1846 	}
1847 	if (us) {
1848 		message->flags |= kIORPCMessageRemote;
1849 		ret = us->rpc(rpc);
1850 		if (kIOReturnSuccess != ret) {
1851 			if (kIODKLogIPC & gIODKDebug) {
1852 				DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret);
1853 			}
1854 		}
1855 	} else {
1856 		if (kIODKLogIPC & gIODKDebug) {
1857 			DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message->msgid);
1858 		}
1859 		ret = Dispatch(rpc);
1860 	}
1861 
1862 	return ret;
1863 }
1864 
1865 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1866 
1867 struct IOPStrings {
1868 	uint32_t     dataSize;
1869 	uint32_t     count;
1870 	const char   strings[0];
1871 };
1872 
1873 kern_return_t
1874 OSUserMetaClass::Dispatch(IORPC rpc)
1875 {
1876 	if (meta) {
1877 		return const_cast<OSMetaClass *>(meta)->Dispatch(rpc);
1878 	} else {
1879 		return kIOReturnUnsupported;
1880 	}
1881 }
1882 
1883 void
1884 OSUserMetaClass::free()
1885 {
1886 	if (queueNames) {
1887 		IOFree(queueNames, sizeof(IOPStrings) + queueNames->dataSize * sizeof(char));
1888 		queueNames = NULL;
1889 	}
1890 	if (description) {
1891 		IOFree(description, description->descriptionSize);
1892 		description = NULL;
1893 	}
1894 	IOSafeDeleteNULL(methods, uint64_t, 2 * methodCount);
1895 	if (meta) {
1896 		meta->releaseMetaClass();
1897 	}
1898 	if (name) {
1899 		name->release();
1900 	}
1901 	OSObject::free();
1902 }
1903 
1904 /*
1905  * Sets the loadTag of the associated OSKext
1906  * in the dext task.
1907  * NOTE: different instances of the same OSKext
1908  * (so same BounleID but different tasks)
1909  * will have the same loadTag.
1910  */
1911 void
1912 IOUserServer::setTaskLoadTag(OSKext *kext)
1913 {
1914 	task_t owningTask;
1915 	uint32_t loadTag, prev_taskloadTag;
1916 
1917 	owningTask = this->fOwningTask;
1918 	if (!owningTask) {
1919 		printf("%s: fOwningTask not found\n", __FUNCTION__);
1920 		return;
1921 	}
1922 
1923 	loadTag = kext->getLoadTag();
1924 	prev_taskloadTag = set_task_loadTag(owningTask, loadTag);
1925 	if (prev_taskloadTag) {
1926 		printf("%s: found the task loadTag already set to %u (set to %u)\n",
1927 		    __FUNCTION__, prev_taskloadTag, loadTag);
1928 	}
1929 }
1930 
1931 /*
1932  * Sets the OSKext uuid as the uuid of the userspace
1933  * dext executable.
1934  */
1935 void
1936 IOUserServer::setDriverKitUUID(OSKext *kext)
1937 {
1938 	task_t task;
1939 	proc_t p;
1940 	uuid_t p_uuid, k_uuid;
1941 	OSData *k_data_uuid;
1942 	OSData *new_uuid;
1943 	uuid_string_t       uuid_string = "";
1944 
1945 	task = this->fOwningTask;
1946 	if (!task) {
1947 		printf("%s: fOwningTask not found\n", __FUNCTION__);
1948 		return;
1949 	}
1950 
1951 	p = (proc_t)(get_bsdtask_info(task));
1952 	if (!p) {
1953 		printf("%s: proc not found\n", __FUNCTION__);
1954 		return;
1955 	}
1956 	proc_getexecutableuuid(p, p_uuid, sizeof(p_uuid));
1957 
1958 	k_data_uuid = kext->copyUUID();
1959 	if (k_data_uuid) {
1960 		memcpy(&k_uuid, k_data_uuid->getBytesNoCopy(), sizeof(k_uuid));
1961 		OSSafeReleaseNULL(k_data_uuid);
1962 		if (uuid_compare(k_uuid, p_uuid) != 0) {
1963 			printf("%s: uuid not matching\n", __FUNCTION__);
1964 		}
1965 		return;
1966 	}
1967 
1968 	uuid_unparse(p_uuid, uuid_string);
1969 	new_uuid = OSData::withBytes(p_uuid, sizeof(p_uuid));
1970 	kext->setDriverKitUUID(new_uuid);
1971 }
1972 
1973 void
1974 IOUserServer::setCheckInToken(IOUserServerCheckInToken *token)
1975 {
1976 	if (token != NULL && fCheckInToken == NULL) {
1977 		token->retain();
1978 		fCheckInToken = token;
1979 	} else {
1980 		printf("%s: failed to set check in token. token=%p, fCheckInToken=%p\n", __FUNCTION__, token, fCheckInToken);
1981 	}
1982 }
1983 
1984 bool
1985 IOUserServer::serviceMatchesCheckInToken(IOUserServerCheckInToken *token)
1986 {
1987 	if (token != NULL) {
1988 		return token == fCheckInToken;
1989 	} else {
1990 		printf("%s: null check in token\n", __FUNCTION__);
1991 		return false;
1992 	}
1993 }
1994 
1995 bool
1996 IOUserServer::checkEntitlements(
1997 	OSDictionary * entitlements, OSObject * prop,
1998 	IOService * provider, IOService * dext)
1999 {
2000 	OSDictionary * matching;
2001 
2002 	if (!prop) {
2003 		return true;
2004 	}
2005 	if (!entitlements) {
2006 		return false;
2007 	}
2008 
2009 	matching = NULL;
2010 	if (dext) {
2011 		matching = dext->dictionaryWithProperties();
2012 		if (!matching) {
2013 			return false;
2014 		}
2015 	}
2016 
2017 	bool allPresent __block;
2018 	prop->iterateObjects(^bool (OSObject * object) {
2019 		allPresent = false;
2020 		object->iterateObjects(^bool (OSObject * object) {
2021 			OSString * string;
2022 			OSObject * value;
2023 			string = OSDynamicCast(OSString, object);
2024 			value = entitlements->getObject(string);
2025 			if (matching && value) {
2026 			        matching->setObject(string, value);
2027 			}
2028 			allPresent = (NULL != value);
2029 			return !allPresent;
2030 		});
2031 		return allPresent;
2032 	});
2033 
2034 	if (allPresent && matching && provider) {
2035 		allPresent = provider->matchPropertyTable(matching);
2036 	}
2037 
2038 	OSSafeReleaseNULL(matching);
2039 	OSSafeReleaseNULL(prop);
2040 
2041 	return allPresent;
2042 }
2043 
2044 bool
2045 IOUserServer::checkEntitlements(IOService * provider, IOService * dext)
2046 {
2047 	OSObject     * prop;
2048 	bool           ok;
2049 
2050 	if (!fOwningTask) {
2051 		return false;
2052 	}
2053 
2054 	prop = provider->copyProperty(gIOServiceDEXTEntitlementsKey);
2055 	ok = checkEntitlements(fEntitlements, prop, provider, dext);
2056 	if (!ok) {
2057 		DKLOG(DKS ": provider entitlements check failed\n", DKN(dext));
2058 	}
2059 	if (ok) {
2060 		prop = dext->copyProperty(gIOServiceDEXTEntitlementsKey);
2061 		ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
2062 		if (!ok) {
2063 			DKLOG(DKS ": family entitlements check failed\n", DKN(dext));
2064 		}
2065 	}
2066 
2067 	return ok;
2068 }
2069 
2070 IOReturn
2071 IOUserServer::exit(const char * reason)
2072 {
2073 	DKLOG("%s::exit(%s)\n", getName(), reason);
2074 	Exit(reason);
2075 	return kIOReturnSuccess;
2076 }
2077 
2078 OSObjectUserVars *
2079 IOUserServer::varsForObject(OSObject * obj)
2080 {
2081 	IOService * service;
2082 
2083 	if ((service = OSDynamicCast(IOService, obj))) {
2084 		return service->reserved->uvars;
2085 	}
2086 
2087 	return NULL;
2088 }
2089 
2090 IOPStrings *
2091 IOUserServer::copyInStringArray(const char * string, uint32_t userSize)
2092 {
2093 	IOPStrings * array;
2094 	vm_size_t    alloc;
2095 	size_t       len;
2096 	const char * cstr;
2097 	const char * end;
2098 
2099 	if (userSize <= 1) {
2100 		return NULL;
2101 	}
2102 
2103 	if (os_add_overflow(sizeof(IOPStrings), userSize, &alloc)) {
2104 		assert(false);
2105 		return NULL;
2106 	}
2107 	if (alloc > 16384) {
2108 		assert(false);
2109 		return NULL;
2110 	}
2111 	array = (typeof(array))IOMalloc(alloc);
2112 	if (!array) {
2113 		return NULL;
2114 	}
2115 	array->dataSize = userSize;
2116 	bcopy(string, (void *) &array->strings[0], userSize);
2117 
2118 	array->count = 0;
2119 	cstr = &array->strings[0];
2120 	end =  &array->strings[array->dataSize];
2121 	while ((len = (unsigned char)cstr[0])) {
2122 		cstr++;
2123 		if ((cstr + len) >= end) {
2124 			break;
2125 		}
2126 		cstr += len;
2127 		array->count++;
2128 	}
2129 	if (len) {
2130 		IOFree(array, alloc);
2131 		array = NULL;
2132 	}
2133 
2134 	return array;
2135 }
2136 
2137 uint32_t
2138 IOUserServer::stringArrayIndex(IOPStrings * array, const char * look)
2139 {
2140 	uint32_t     idx;
2141 	size_t       len, llen;
2142 	const char * cstr;
2143 	const char * end;
2144 
2145 	idx  = 0;
2146 	cstr = &array->strings[0];
2147 	end  =  &array->strings[array->dataSize];
2148 	llen = strlen(look);
2149 	while ((len = (unsigned char)cstr[0])) {
2150 		cstr++;
2151 		if ((cstr + len) >= end) {
2152 			break;
2153 		}
2154 		if ((len == llen) && !strncmp(cstr, look, len)) {
2155 			return idx;
2156 		}
2157 		cstr += len;
2158 		idx++;
2159 	}
2160 
2161 	return -1U;
2162 }
2163 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
2164 
2165 IODispatchQueue *
2166 IOUserServer::queueForObject(OSObject * obj, uint64_t msgid)
2167 {
2168 	IODispatchQueue  * queue;
2169 	OSObjectUserVars * uvars;
2170 	uint64_t           option;
2171 
2172 	uvars = varsForObject(obj);
2173 	if (!uvars) {
2174 		return NULL;
2175 	}
2176 	if (!uvars->queueArray) {
2177 		if (uvars->stopped) {
2178 			return kIODispatchQueueStopped;
2179 		}
2180 		return NULL;
2181 	}
2182 	queue = uvars->queueArray[0];
2183 
2184 	if (uvars->userMeta
2185 	    && uvars->userMeta->methods) {
2186 		uint32_t idx, baseIdx;
2187 		uint32_t lim;
2188 		// bsearch
2189 		for (baseIdx = 0, lim = uvars->userMeta->methodCount; lim; lim >>= 1) {
2190 			idx = baseIdx + (lim >> 1);
2191 			if (msgid == uvars->userMeta->methods[idx]) {
2192 				option = uvars->userMeta->methods[uvars->userMeta->methodCount + idx];
2193 				option &= 0xFF;
2194 				if (option < uvars->userMeta->queueNames->count) {
2195 					queue = uvars->queueArray[option + 1];
2196 				}
2197 				break;
2198 			} else if (msgid > uvars->userMeta->methods[idx]) {
2199 				// move right
2200 				baseIdx += (lim >> 1) + 1;
2201 				lim--;
2202 			}
2203 			// else move left
2204 		}
2205 	}
2206 	return queue;
2207 }
2208 
2209 IOReturn
2210 IOUserServer::objectInstantiate(OSObject * obj, IORPC rpc, IORPCMessage * message)
2211 {
2212 	IOReturn         ret;
2213 	OSString       * str;
2214 	OSObject       * prop;
2215 	IOService      * service;
2216 
2217 	OSAction       * action;
2218 	OSObject       * target;
2219 	uint32_t         queueCount, queueAlloc;
2220 	const char     * resultClassName;
2221 	uint64_t         resultFlags;
2222 
2223 	mach_msg_size_t    replySize;
2224 	uint32_t           methodCount;
2225 	const uint64_t   * methods;
2226 	IODispatchQueue  * queue;
2227 	OSUserMetaClass  * userMeta;
2228 	OSObjectUserVars * uvars;
2229 	uint32_t           idx;
2230 	ipc_port_t         sendPort;
2231 
2232 	OSObject_Instantiate_Rpl_Content * reply;
2233 
2234 	queueCount      = 0;
2235 	methodCount     = 0;
2236 	methods         = NULL;
2237 	str             = NULL;
2238 	prop            = NULL;
2239 	userMeta        = NULL;
2240 	resultClassName = NULL;
2241 	resultFlags     = 0;
2242 	ret = kIOReturnUnsupportedMode;
2243 
2244 	service = OSDynamicCast(IOService, obj);
2245 	action = OSDynamicCast(OSAction, obj);
2246 	if (!service) {
2247 		// xxx other classes hosted
2248 		resultFlags |= kOSObjectRPCKernel;
2249 		resultFlags |= kOSObjectRPCRemote;
2250 	} else {
2251 		if (service->isInactive()) {
2252 			DKLOG(DKS "::instantiate inactive\n", DKN(service));
2253 			return kIOReturnOffline;
2254 		}
2255 		prop = service->copyProperty(gIOUserClassKey);
2256 		str = OSDynamicCast(OSString, prop);
2257 		if (!service->reserved->uvars) {
2258 			resultFlags |= kOSObjectRPCRemote;
2259 			resultFlags |= kOSObjectRPCKernel;
2260 		} else if (this != service->reserved->uvars->userServer) {
2261 			// remote, use base class
2262 			resultFlags |= kOSObjectRPCRemote;
2263 		}
2264 		if (service->reserved->uvars && service->reserved->uvars->userServer) {
2265 			IOLockLock(service->reserved->uvars->userServer->fLock);
2266 			userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str);
2267 			IOLockUnlock(service->reserved->uvars->userServer->fLock);
2268 		}
2269 	}
2270 	if (!str && !userMeta) {
2271 		const OSMetaClass * meta;
2272 		meta = obj->getMetaClass();
2273 		IOLockLock(fLock);
2274 		if (action) {
2275 			str = action->ivars->typeName;
2276 			if (str) {
2277 				userMeta = (typeof(userMeta))fClasses->getObject(str);
2278 			}
2279 		}
2280 		while (meta && !userMeta) {
2281 			str = (OSString *) meta->getClassNameSymbol();
2282 			userMeta = (typeof(userMeta))fClasses->getObject(str);
2283 			if (!userMeta) {
2284 				meta = meta->getSuperClass();
2285 			}
2286 		}
2287 		IOLockUnlock(fLock);
2288 	}
2289 	if (str) {
2290 		if (!userMeta) {
2291 			IOLockLock(fLock);
2292 			userMeta = (typeof(userMeta))fClasses->getObject(str);
2293 			IOLockUnlock(fLock);
2294 		}
2295 		if (kIODKLogSetup & gIODKDebug) {
2296 			DKLOG("userMeta %s %p\n", str->getCStringNoCopy(), userMeta);
2297 		}
2298 		if (userMeta) {
2299 			if (kOSObjectRPCRemote & resultFlags) {
2300 				if (!action) {
2301 					/* Special case: For OSAction subclasses, do not use the superclass */
2302 					while (userMeta && !(kOSClassCanRemote & userMeta->description->flags)) {
2303 						userMeta = userMeta->superMeta;
2304 					}
2305 				}
2306 				if (userMeta) {
2307 					resultClassName = userMeta->description->name;
2308 					ret = kIOReturnSuccess;
2309 				}
2310 			} else {
2311 				service->reserved->uvars->userMeta = userMeta;
2312 				queueAlloc = 1;
2313 				if (userMeta->queueNames) {
2314 					queueAlloc += userMeta->queueNames->count;
2315 				}
2316 				service->reserved->uvars->queueArray =
2317 				    IONewZero(IODispatchQueue *, queueAlloc);
2318 				resultClassName = str->getCStringNoCopy();
2319 				ret = kIOReturnSuccess;
2320 			}
2321 		} else if (kIODKLogSetup & gIODKDebug) {
2322 			DKLOG("userMeta %s was not found in fClasses\n", str->getCStringNoCopy());
2323 			IOLockLock(fLock);
2324 			fClasses->iterateObjects(^bool (const OSSymbol * key, OSObject * val) {
2325 				DKLOG(" fClasses[\"%s\"] => %p\n", key->getCStringNoCopy(), val);
2326 				return false;
2327 			});
2328 			IOLockUnlock(fLock);
2329 		}
2330 	}
2331 	OSSafeReleaseNULL(prop);
2332 
2333 	IORPCMessageMach * machReply = rpc.reply;
2334 	replySize = sizeof(OSObject_Instantiate_Rpl);
2335 
2336 	if ((kIOReturnSuccess == ret) && (kOSObjectRPCRemote & resultFlags)) {
2337 		target = obj;
2338 		if (action) {
2339 			if (action->ivars->referenceSize) {
2340 				resultFlags |= kOSObjectRPCKernel;
2341 			} else {
2342 				resultFlags &= ~kOSObjectRPCKernel;
2343 				target = action->ivars->target;
2344 
2345 				queueCount = 1;
2346 				queue = queueForObject(target, action->ivars->targetmsgid);
2347 				idx = 0;
2348 				sendPort = NULL;
2349 				if (queue && (kIODispatchQueueStopped != queue)) {
2350 					sendPort = ipc_port_copy_send(queue->ivars->serverPort);
2351 				}
2352 				replySize = sizeof(OSObject_Instantiate_Rpl)
2353 				    + queueCount * sizeof(machReply->objects[0])
2354 				    + 2 * methodCount * sizeof(reply->methods[0]);
2355 				if (replySize > rpc.replySize) {
2356 					assert(false);
2357 					return kIOReturnIPCError;
2358 				}
2359 				machReply->objects[idx].type        = MACH_MSG_PORT_DESCRIPTOR;
2360 				machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
2361 				machReply->objects[idx].name        = sendPort;
2362 				machReply->objects[idx].pad2        = 0;
2363 				machReply->objects[idx].pad_end     = 0;
2364 			}
2365 		} else {
2366 			uvars = varsForObject(target);
2367 			if (uvars && uvars->userMeta) {
2368 				queueCount = 1;
2369 				if (uvars->userMeta->queueNames) {
2370 					queueCount += uvars->userMeta->queueNames->count;
2371 				}
2372 				methods = &uvars->userMeta->methods[0];
2373 				methodCount = uvars->userMeta->methodCount;
2374 				replySize = sizeof(OSObject_Instantiate_Rpl)
2375 				    + queueCount * sizeof(machReply->objects[0])
2376 				    + 2 * methodCount * sizeof(reply->methods[0]);
2377 				if (replySize > rpc.replySize) {
2378 					assert(false);
2379 					return kIOReturnIPCError;
2380 				}
2381 				for (idx = 0; idx < queueCount; idx++) {
2382 					queue = uvars->queueArray[idx];
2383 					sendPort = NULL;
2384 					if (queue) {
2385 						sendPort = ipc_port_copy_send(queue->ivars->serverPort);
2386 					}
2387 					machReply->objects[idx].type        = MACH_MSG_PORT_DESCRIPTOR;
2388 					machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
2389 					machReply->objects[idx].name        = sendPort;
2390 					machReply->objects[idx].pad2        = 0;
2391 					machReply->objects[idx].pad_end     = 0;
2392 				}
2393 			}
2394 		}
2395 	}
2396 
2397 	if (kIODKLogIPC & gIODKDebug) {
2398 		DKLOG("instantiate object %s with user class %s\n", obj->getMetaClass()->getClassName(), str ? str->getCStringNoCopy() : "(null)");
2399 	}
2400 
2401 	if (kIOReturnSuccess != ret) {
2402 		DKLOG("%s: no user class found\n", str ? str->getCStringNoCopy() : obj->getMetaClass()->getClassName());
2403 		resultClassName = "unknown";
2404 	}
2405 
2406 	machReply->msgh.msgh_id                    = kIORPCVersionCurrentReply;
2407 	machReply->msgh.msgh_size                  = replySize;
2408 	machReply->msgh_body.msgh_descriptor_count = queueCount;
2409 
2410 	reply = (typeof(reply))IORPCMessageFromMach(machReply, true);
2411 	if (!reply) {
2412 		return kIOReturnIPCError;
2413 	}
2414 	if (methodCount) {
2415 		bcopy(methods, &reply->methods[0], methodCount * 2 * sizeof(reply->methods[0]));
2416 	}
2417 	reply->__hdr.msgid       = OSObject_Instantiate_ID;
2418 	reply->__hdr.flags       = kIORPCMessageOneway;
2419 	reply->__hdr.objectRefs  = 0;
2420 	reply->__pad             = 0;
2421 	reply->flags             = resultFlags;
2422 	strlcpy(reply->classname, resultClassName, sizeof(reply->classname));
2423 	reply->__result          = ret;
2424 
2425 	ret = kIOReturnSuccess;
2426 
2427 	return ret;
2428 }
2429 
2430 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2431 
2432 IOReturn
2433 IOUserServer::kernelDispatch(OSObject * obj, IORPC rpc)
2434 {
2435 	IOReturn       ret;
2436 	IORPCMessage * message;
2437 
2438 	message = IORPCMessageFromMach(rpc.message, false);
2439 	if (!message) {
2440 		return kIOReturnIPCError;
2441 	}
2442 
2443 	if (OSObject_Instantiate_ID == message->msgid) {
2444 		ret = objectInstantiate(obj, rpc, message);
2445 		if (kIOReturnSuccess != ret) {
2446 			DKLOG("%s: instantiate failed 0x%x\n", obj->getMetaClass()->getClassName(), ret);
2447 		}
2448 	} else {
2449 		if (kIODKLogIPC & gIODKDebug) {
2450 			DKLOG("%s::Dispatch kernel 0x%qx\n", obj->getMetaClass()->getClassName(), message->msgid);
2451 		}
2452 		ret = obj->Dispatch(rpc);
2453 		if (kIODKLogIPC & gIODKDebug) {
2454 			DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj->getMetaClass()->getClassName(), message->msgid, ret);
2455 		}
2456 	}
2457 
2458 	return ret;
2459 }
2460 
2461 
2462 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2463 
2464 OSObject *
2465 IOUserServer::target(OSAction * action, IORPCMessage * message)
2466 {
2467 	OSObject * object;
2468 
2469 	if (message->msgid != action->ivars->msgid) {
2470 		return action;
2471 	}
2472 	object              = action->ivars->target;
2473 	message->msgid      = action->ivars->targetmsgid;
2474 	message->objects[0] = (OSObjectRef) object;
2475 	if (kIORPCMessageRemote & message->flags) {
2476 		object->retain();
2477 #ifndef __clang_analyzer__
2478 		// Hide the release of 'action' from the clang static analyzer to suppress
2479 		// an overrelease diagnostic. The analyzer doesn't have a way to express the
2480 		// non-standard contract of this method, which is that it releases 'action' when
2481 		// the message flags have kIORPCMessageRemote set.
2482 		action->release();
2483 #endif
2484 	}
2485 	if (kIODKLogIPC & gIODKDebug) {
2486 		DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid, action->ivars->msgid);
2487 	}
2488 
2489 	return object;
2490 }
2491 
2492 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2493 
2494 kern_return_t
2495 uext_server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
2496 {
2497 	kern_return_t      ret;
2498 	IORPCMessageMach * msgin;
2499 	OSObject         * object;
2500 	IOUserServer     * server;
2501 
2502 	msgin   = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
2503 
2504 	object = IOUserServer::copyObjectForSendRight(msgin->msgh.msgh_remote_port, IKOT_UEXT_OBJECT);
2505 	server = OSDynamicCast(IOUserServer, object);
2506 	if (!server) {
2507 		OSSafeReleaseNULL(object);
2508 		return KERN_INVALID_NAME;
2509 	}
2510 	ret = server->server(requestkmsg, pReply);
2511 	object->release();
2512 
2513 	return ret;
2514 }
2515 
2516 #define MAX_UEXT_REPLY_SIZE     0x17c0
2517 
2518 kern_return_t
2519 IOUserServer::server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
2520 {
2521 	kern_return_t      ret;
2522 	mach_msg_size_t    replyAlloc;
2523 	ipc_kmsg_t         replykmsg;
2524 	IORPCMessageMach * msgin;
2525 	IORPCMessage     * message;
2526 	IORPCMessageMach * msgout;
2527 	IORPCMessage     * reply;
2528 	uint32_t           replySize;
2529 	OSObject         * object;
2530 	OSAction         * action;
2531 	bool               oneway;
2532 	uint64_t           msgid;
2533 
2534 	msgin   = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
2535 	replyAlloc = 0;
2536 	msgout = NULL;
2537 	replykmsg = NULL;
2538 
2539 	if (msgin->msgh.msgh_size < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
2540 		if (kIODKLogIPC & gIODKDebug) {
2541 			DKLOG("UEXT notify %o\n", msgin->msgh.msgh_id);
2542 		}
2543 		return KERN_NOT_SUPPORTED;
2544 	}
2545 
2546 	if (!(MACH_MSGH_BITS_COMPLEX & msgin->msgh.msgh_bits)) {
2547 		msgin->msgh_body.msgh_descriptor_count = 0;
2548 	}
2549 	message = IORPCMessageFromMach(msgin, false);
2550 	if (!message) {
2551 		return kIOReturnIPCError;
2552 	}
2553 	if (message->objectRefs == 0) {
2554 		return kIOReturnIPCError;
2555 	}
2556 	ret = copyInObjects(msgin, message, msgin->msgh.msgh_size, true, false);
2557 	if (kIOReturnSuccess != ret) {
2558 		if (kIODKLogIPC & gIODKDebug) {
2559 			DKLOG("UEXT copyin(0x%x) %x\n", ret, msgin->msgh.msgh_id);
2560 		}
2561 		return KERN_NOT_SUPPORTED;
2562 	}
2563 
2564 	if (msgin->msgh_body.msgh_descriptor_count < 1) {
2565 		return KERN_NOT_SUPPORTED;
2566 	}
2567 	object = (OSObject *) message->objects[0];
2568 	msgid = message->msgid;
2569 	message->flags &= ~kIORPCMessageKernel;
2570 	message->flags |= kIORPCMessageRemote;
2571 
2572 	if ((action = OSDynamicCast(OSAction, object))) {
2573 		object = target(action, message);
2574 		msgid  = message->msgid;
2575 	}
2576 
2577 	oneway = (0 != (kIORPCMessageOneway & message->flags));
2578 	assert(oneway || (MACH_PORT_NULL != msgin->msgh.msgh_local_port));
2579 
2580 	// includes trailer size
2581 	replyAlloc = oneway ? 0 : MAX_UEXT_REPLY_SIZE;
2582 	if (replyAlloc) {
2583 		replykmsg = ipc_kmsg_alloc(replyAlloc);
2584 		if (replykmsg == NULL) {
2585 //			printf("uext_server: dropping request\n");
2586 			//	ipc_kmsg_trace_send(request, option);
2587 			consumeObjects(message, msgin->msgh.msgh_size);
2588 			ipc_kmsg_destroy(requestkmsg);
2589 			return KERN_MEMORY_FAILURE;
2590 		}
2591 
2592 		msgout = (typeof(msgout))ipc_kmsg_msg_header(replykmsg);
2593 		/*
2594 		 * MIG should really assure no data leakage -
2595 		 * but until it does, pessimistically zero the
2596 		 * whole reply buffer.
2597 		 */
2598 		bzero((void *)msgout, replyAlloc);
2599 	}
2600 
2601 	IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc };
2602 
2603 	if (object) {
2604 		thread_iokit_tls_set(0, this);
2605 		ret = kernelDispatch(object, rpc);
2606 		thread_iokit_tls_set(0, NULL);
2607 	} else {
2608 		ret = kIOReturnBadArgument;
2609 	}
2610 
2611 	// release objects
2612 	consumeObjects(message, msgin->msgh.msgh_size);
2613 
2614 	// release ports
2615 	copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
2616 
2617 	if (!oneway) {
2618 		if (kIOReturnSuccess == ret) {
2619 			replySize = msgout->msgh.msgh_size;
2620 			reply = IORPCMessageFromMach(msgout, true);
2621 			if (!reply) {
2622 				ret = kIOReturnIPCError;
2623 			} else {
2624 				ret = copyOutObjects(msgout, reply, replySize, (kIORPCVersionCurrentReply == msgout->msgh.msgh_id) /* =>!InvokeReply */);
2625 			}
2626 		}
2627 		if (kIOReturnSuccess != ret) {
2628 			IORPCMessageErrorReturnContent * errorMsg;
2629 
2630 			msgout->msgh_body.msgh_descriptor_count = 0;
2631 			msgout->msgh.msgh_id                    = kIORPCVersionCurrentReply;
2632 			errorMsg = (typeof(errorMsg))IORPCMessageFromMach(msgout, true);
2633 			errorMsg->hdr.msgid      = message->msgid;
2634 			errorMsg->hdr.flags      = kIORPCMessageOneway | kIORPCMessageError;
2635 			errorMsg->hdr.objectRefs = 0;
2636 			errorMsg->result         = ret;
2637 			errorMsg->pad            = 0;
2638 			replySize                = sizeof(IORPCMessageErrorReturn);
2639 		}
2640 
2641 		msgout->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
2642 		    MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin->msgh.msgh_bits) /*remote*/, 0 /*local*/, 0, 0);
2643 
2644 		msgout->msgh.msgh_remote_port  = msgin->msgh.msgh_local_port;
2645 		msgout->msgh.msgh_local_port   = MACH_PORT_NULL;
2646 		msgout->msgh.msgh_voucher_port = (mach_port_name_t) 0;
2647 		msgout->msgh.msgh_reserved     = 0;
2648 		msgout->msgh.msgh_size         = replySize;
2649 	}
2650 
2651 	*pReply = replykmsg;
2652 
2653 	return oneway ? MIG_NO_REPLY : KERN_SUCCESS;
2654 }
2655 
2656 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2657 
2658 #define MAX_OBJECT_COUNT(mach, size, message) \
2659 	((uint32_t)(((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))))
2660 
2661 kern_return_t
2662 IOUserServerUEXTTrap(OSObject * object, void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
2663 {
2664 	const user_addr_t msg              = (uintptr_t) p1;
2665 	size_t            inSize           = (uintptr_t) p2;
2666 	user_addr_t       out              = (uintptr_t) p3;
2667 	size_t            outSize          = (uintptr_t) p4;
2668 	mach_port_name_t  objectName1      = (mach_port_name_t)(uintptr_t) p5;
2669 	size_t            totalSize;
2670 	OSObject        * objectArg1;
2671 
2672 	IORPCMessageMach *  mach;
2673 	mach_msg_port_descriptor_t * descs;
2674 
2675 #pragma pack(4)
2676 	struct {
2677 		uint32_t                   pad;
2678 		IORPCMessageMach           mach;
2679 		mach_msg_port_descriptor_t objects[2];
2680 		IOTrapMessageBuffer        buffer;
2681 	} buffer;
2682 #pragma pack()
2683 
2684 	IOReturn           ret;
2685 	OSAction         * action;
2686 	int                copyerr;
2687 	IORPCMessage     * message;
2688 	IORPCMessage     * reply;
2689 	IORPC              rpc;
2690 	uint64_t           refs;
2691 	uint32_t           maxObjectCount;
2692 	size_t             copySize;
2693 	uint64_t         * replyHdr;
2694 	uintptr_t          p;
2695 
2696 	bzero(&buffer, sizeof(buffer));
2697 
2698 	p = (typeof(p)) & buffer.buffer[0];
2699 	if (os_add_overflow(inSize, outSize, &totalSize)) {
2700 		return kIOReturnMessageTooLarge;
2701 	}
2702 	if (totalSize > sizeof(buffer.buffer)) {
2703 		return kIOReturnMessageTooLarge;
2704 	}
2705 	if (inSize < sizeof(IORPCMessage)) {
2706 		return kIOReturnIPCError;
2707 	}
2708 	copyerr = copyin(msg, &buffer.buffer[0], inSize);
2709 	if (copyerr) {
2710 		return kIOReturnVMError;
2711 	}
2712 
2713 	message = (typeof(message))p;
2714 	refs    = message->objectRefs;
2715 	if ((refs > 2) || !refs) {
2716 		return kIOReturnUnsupported;
2717 	}
2718 	if (!(kIORPCMessageSimpleReply & message->flags)) {
2719 		return kIOReturnUnsupported;
2720 	}
2721 
2722 	descs = (typeof(descs))(p - refs * sizeof(*descs));
2723 	mach  = (typeof(mach))(p - refs * sizeof(*descs) - sizeof(*mach));
2724 
2725 	mach->msgh.msgh_id   = kIORPCVersionCurrent;
2726 	mach->msgh.msgh_size = (mach_msg_size_t) (sizeof(IORPCMessageMach) + refs * sizeof(*descs) + inSize); // totalSize was checked
2727 	mach->msgh_body.msgh_descriptor_count = ((mach_msg_size_t) refs);
2728 
2729 	rpc.message   = mach;
2730 	rpc.sendSize  = mach->msgh.msgh_size;
2731 	rpc.reply     = (IORPCMessageMach *) (p + inSize);
2732 	rpc.replySize = ((uint32_t) (sizeof(buffer.buffer) - inSize));    // inSize was checked
2733 
2734 	message->objects[0] = 0;
2735 	if ((action = OSDynamicCast(OSAction, object))) {
2736 		maxObjectCount = MAX_OBJECT_COUNT(rpc.message, rpc.sendSize, message);
2737 		if (refs > maxObjectCount) {
2738 			return kIOReturnBadArgument;
2739 		}
2740 		object = IOUserServer::target(action, message);
2741 		message->objects[1] = (OSObjectRef) action;
2742 		if (kIODKLogIPC & gIODKDebug) {
2743 			DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
2744 		}
2745 		ret = object->Dispatch(rpc);
2746 	} else {
2747 		objectArg1 = NULL;
2748 		if (refs > 1) {
2749 			if (objectName1) {
2750 				objectArg1 = iokit_lookup_uext_ref_current_task(objectName1);
2751 				if (!objectArg1) {
2752 					return kIOReturnIPCError;
2753 				}
2754 			}
2755 			message->objects[1] = (OSObjectRef) objectArg1;
2756 		}
2757 		if (kIODKLogIPC & gIODKDebug) {
2758 			DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
2759 		}
2760 		ret = object->Dispatch(rpc);
2761 		if (kIODKLogIPC & gIODKDebug) {
2762 			DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object->getMetaClass()->getClassName(), message->msgid, ret);
2763 		}
2764 		OSSafeReleaseNULL(objectArg1);
2765 
2766 		if (kIOReturnSuccess == ret) {
2767 			if (rpc.reply->msgh_body.msgh_descriptor_count) {
2768 				return kIOReturnIPCError;
2769 			}
2770 			reply = IORPCMessageFromMach(rpc.reply, rpc.reply->msgh.msgh_size);
2771 			if (!reply) {
2772 				return kIOReturnIPCError;
2773 			}
2774 			copySize = rpc.reply->msgh.msgh_size - (((uintptr_t) reply) - ((uintptr_t) rpc.reply)) + sizeof(uint64_t);
2775 			if (copySize > outSize) {
2776 				return kIOReturnIPCError;
2777 			}
2778 			replyHdr = (uint64_t *) reply;
2779 			replyHdr--;
2780 			replyHdr[0] = copySize;
2781 			copyerr = copyout(replyHdr, out, copySize);
2782 			if (copyerr) {
2783 				return kIOReturnVMError;
2784 			}
2785 		}
2786 	}
2787 
2788 	return ret;
2789 }
2790 
2791 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2792 
2793 IOReturn
2794 IOUserServer::rpc(IORPC rpc)
2795 {
2796 	if (isInactive() && !fRootQueue) {
2797 		return kIOReturnOffline;
2798 	}
2799 
2800 	IOReturn           ret;
2801 	IORPCMessage     * message;
2802 	IORPCMessageMach * mach;
2803 	mach_msg_id_t      machid;
2804 	uint32_t           sendSize, replySize;
2805 	bool               oneway;
2806 	uint64_t           msgid;
2807 	IODispatchQueue  * queue;
2808 	IOService        * service;
2809 	ipc_port_t         port;
2810 	ipc_port_t         sendPort;
2811 
2812 	queue    = NULL;
2813 	port     = NULL;
2814 	sendPort = NULL;
2815 
2816 	mach      = rpc.message;
2817 	sendSize  = rpc.sendSize;
2818 	replySize = rpc.replySize;
2819 
2820 	assert(sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2821 
2822 	message = IORPCMessageFromMach(mach, false);
2823 	if (!message) {
2824 		return kIOReturnIPCError;
2825 	}
2826 	msgid   = message->msgid;
2827 	machid  = (msgid >> 32);
2828 
2829 	if (mach->msgh_body.msgh_descriptor_count < 1) {
2830 		return kIOReturnNoMedia;
2831 	}
2832 
2833 	IOLockLock(gIOUserServerLock);
2834 	if ((service = OSDynamicCast(IOService, (OSObject *) message->objects[0]))) {
2835 		queue = queueForObject(service, msgid);
2836 	}
2837 	if (!queue) {
2838 		queue = fRootQueue;
2839 	}
2840 	if (queue && (kIODispatchQueueStopped != queue)) {
2841 		port = queue->ivars->serverPort;
2842 	}
2843 	if (port) {
2844 		sendPort = ipc_port_copy_send(port);
2845 	}
2846 	IOLockUnlock(gIOUserServerLock);
2847 	if (!sendPort) {
2848 		return kIOReturnNotReady;
2849 	}
2850 
2851 	oneway = (0 != (kIORPCMessageOneway & message->flags));
2852 
2853 	ret = copyOutObjects(mach, message, sendSize, false);
2854 
2855 	mach->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
2856 	    MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (oneway ? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE));
2857 	mach->msgh.msgh_remote_port  = sendPort;
2858 	mach->msgh.msgh_local_port   = (oneway ? MACH_PORT_NULL : mig_get_reply_port());
2859 	mach->msgh.msgh_id           = kIORPCVersionCurrent;
2860 	mach->msgh.msgh_reserved     = 0;
2861 
2862 	boolean_t message_moved;
2863 
2864 	if (oneway) {
2865 		ret = kernel_mach_msg_send(&mach->msgh, sendSize,
2866 		    MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_NOIMPORTANCE,
2867 		    0, &message_moved);
2868 	} else {
2869 		assert(replySize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2870 		ret = kernel_mach_msg_rpc(&mach->msgh, sendSize, replySize, FALSE, &message_moved);
2871 	}
2872 
2873 	ipc_port_release_send(sendPort);
2874 
2875 	if (MACH_MSG_SUCCESS != ret) {
2876 		if (kIODKLogIPC & gIODKDebug) {
2877 			DKLOG("mach_msg() failed 0x%x\n", ret);
2878 		}
2879 		if (!message_moved) {
2880 			// release ports
2881 			copyInObjects(mach, message, sendSize, false, true);
2882 		}
2883 	}
2884 
2885 	if ((KERN_SUCCESS == ret) && !oneway) {
2886 		if (kIORPCVersionCurrentReply != mach->msgh.msgh_id) {
2887 			ret = (MACH_NOTIFY_SEND_ONCE == mach->msgh.msgh_id) ? MIG_SERVER_DIED : MIG_REPLY_MISMATCH;
2888 		} else if ((replySize = mach->msgh.msgh_size) < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
2889 //				printf("BAD REPLY SIZE\n");
2890 			ret = MIG_BAD_ARGUMENTS;
2891 		} else {
2892 			if (!(MACH_MSGH_BITS_COMPLEX & mach->msgh.msgh_bits)) {
2893 				mach->msgh_body.msgh_descriptor_count = 0;
2894 			}
2895 			message = IORPCMessageFromMach(mach, true);
2896 			if (!message) {
2897 				ret = kIOReturnIPCError;
2898 			} else if (message->msgid != msgid) {
2899 //					printf("BAD REPLY ID\n");
2900 				ret = MIG_BAD_ARGUMENTS;
2901 			} else {
2902 				bool isError = (0 != (kIORPCMessageError & message->flags));
2903 				ret = copyInObjects(mach, message, replySize, !isError, true);
2904 				if (kIOReturnSuccess != ret) {
2905 					if (kIODKLogIPC & gIODKDebug) {
2906 						DKLOG("rpc copyin(0x%x) %x\n", ret, mach->msgh.msgh_id);
2907 					}
2908 					return KERN_NOT_SUPPORTED;
2909 				}
2910 				if (isError) {
2911 					IORPCMessageErrorReturnContent * errorMsg = (typeof(errorMsg))message;
2912 					ret = errorMsg->result;
2913 				}
2914 			}
2915 		}
2916 	}
2917 
2918 	return ret;
2919 }
2920 
2921 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2922 
2923 IORPCMessage *
2924 IORPCMessageFromMach(IORPCMessageMach * msg, bool reply)
2925 {
2926 	mach_msg_size_t              idx, count;
2927 	mach_msg_port_descriptor_t * desc;
2928 	mach_msg_port_descriptor_t * maxDesc;
2929 	size_t                       size, msgsize;
2930 	bool                         upgrade;
2931 
2932 	msgsize = msg->msgh.msgh_size;
2933 	count   = msg->msgh_body.msgh_descriptor_count;
2934 	desc    = &msg->objects[0];
2935 	maxDesc = (typeof(maxDesc))(((uintptr_t) msg) + msgsize);
2936 	upgrade = (msg->msgh.msgh_id != (reply ? kIORPCVersionCurrentReply : kIORPCVersionCurrent));
2937 
2938 	if (upgrade) {
2939 		OSReportWithBacktrace("obsolete message");
2940 		return NULL;
2941 	}
2942 
2943 	for (idx = 0; idx < count; idx++) {
2944 		if (desc >= maxDesc) {
2945 			return NULL;
2946 		}
2947 		switch (desc->type) {
2948 		case MACH_MSG_PORT_DESCRIPTOR:
2949 			size = sizeof(mach_msg_port_descriptor_t);
2950 			break;
2951 		case MACH_MSG_OOL_DESCRIPTOR:
2952 			size = sizeof(mach_msg_ool_descriptor_t);
2953 			break;
2954 		default:
2955 			return NULL;
2956 		}
2957 		desc = (typeof(desc))(((uintptr_t) desc) + size);
2958 	}
2959 	return (IORPCMessage *)(uintptr_t) desc;
2960 }
2961 
2962 ipc_port_t
2963 IOUserServer::copySendRightForObject(OSObject * object, ipc_kobject_type_t type)
2964 {
2965 	ipc_port_t port;
2966 	ipc_port_t sendPort = NULL;
2967 
2968 	port = iokit_port_for_object(object, type);
2969 	if (port) {
2970 		sendPort = ipc_port_make_send(port);
2971 		iokit_release_port(port);
2972 	}
2973 
2974 	return sendPort;
2975 }
2976 
2977 OSObject *
2978 IOUserServer::copyObjectForSendRight(ipc_port_t port, ipc_kobject_type_t type)
2979 {
2980 	OSObject * object;
2981 	object = iokit_lookup_io_object(port, type);
2982 	return object;
2983 }
2984 
2985 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2986 
2987 // Create a vm_map_copy_t or kalloc'ed data for memory
2988 // to be copied out. ipc will free after the copyout.
2989 
2990 static kern_return_t
2991 copyoutkdata(const void * data, vm_size_t len, void ** buf)
2992 {
2993 	kern_return_t       err;
2994 	vm_map_copy_t       copy;
2995 
2996 	err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
2997 	    false /* src_destroy */, &copy);
2998 
2999 	assert( err == KERN_SUCCESS );
3000 	if (err == KERN_SUCCESS) {
3001 		*buf = (char *) copy;
3002 	}
3003 
3004 	return err;
3005 }
3006 
3007 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3008 
3009 IOReturn
3010 IOUserServer::copyOutObjects(IORPCMessageMach * mach, IORPCMessage * message,
3011     size_t size, bool consume)
3012 {
3013 	uint64_t           refs;
3014 	uint32_t           idx, maxObjectCount;
3015 	ipc_port_t         port;
3016 	OSObject         * object;
3017 	size_t             descsize;
3018 	mach_msg_port_descriptor_t * desc;
3019 	mach_msg_ool_descriptor_t  * ool;
3020 	vm_map_copy_t                copy;
3021 	void                       * address;
3022 	mach_msg_size_t              length;
3023 	kern_return_t                kr;
3024 	OSSerialize                * s;
3025 
3026 	refs           = message->objectRefs;
3027 	maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3028 //	assert(refs <= mach->msgh_body.msgh_descriptor_count);
3029 //	assert(refs <= maxObjectCount);
3030 	if (refs > mach->msgh_body.msgh_descriptor_count) {
3031 		return kIOReturnBadArgument;
3032 	}
3033 	if (refs > maxObjectCount) {
3034 		return kIOReturnBadArgument;
3035 	}
3036 
3037 	desc = &mach->objects[0];
3038 	for (idx = 0; idx < refs; idx++) {
3039 		object = (OSObject *) message->objects[idx];
3040 
3041 		switch (desc->type) {
3042 		case MACH_MSG_PORT_DESCRIPTOR:
3043 			descsize = sizeof(mach_msg_port_descriptor_t);
3044 			port = NULL;
3045 			if (object) {
3046 				port = copySendRightForObject(object, IKOT_UEXT_OBJECT);
3047 				if (!port) {
3048 					break;
3049 				}
3050 				if (consume) {
3051 					object->release();
3052 				}
3053 				message->objects[idx] = 0;
3054 			}
3055 //		    desc->type        = MACH_MSG_PORT_DESCRIPTOR;
3056 			desc->disposition = MACH_MSG_TYPE_MOVE_SEND;
3057 			desc->name        = port;
3058 			desc->pad2        = 0;
3059 			desc->pad_end     = 0;
3060 			break;
3061 
3062 		case MACH_MSG_OOL_DESCRIPTOR:
3063 			descsize = sizeof(mach_msg_ool_descriptor_t);
3064 
3065 			length = 0;
3066 			address = NULL;
3067 			if (object) {
3068 				s = OSSerialize::binaryWithCapacity(4096);
3069 				assert(s);
3070 				if (!s) {
3071 					break;
3072 				}
3073 				s->setIndexed(true);
3074 				if (!object->serialize(s)) {
3075 					assert(false);
3076 					descsize = -1UL;
3077 					s->release();
3078 					break;
3079 				}
3080 				length = s->getLength();
3081 				kr = copyoutkdata(s->text(), length, &address);
3082 				s->release();
3083 				if (KERN_SUCCESS != kr) {
3084 					descsize = -1UL;
3085 					address = NULL;
3086 					length = 0;
3087 				}
3088 				if (consume) {
3089 					object->release();
3090 				}
3091 				message->objects[idx] = 0;
3092 			}
3093 			ool = (typeof(ool))desc;
3094 //		    ool->type        = MACH_MSG_OOL_DESCRIPTOR;
3095 			ool->deallocate  = false;
3096 			ool->copy        = MACH_MSG_PHYSICAL_COPY;
3097 			ool->size        = length;
3098 			ool->address     = address;
3099 			break;
3100 
3101 		default:
3102 			descsize = -1UL;
3103 			break;
3104 		}
3105 		if (-1UL == descsize) {
3106 			break;
3107 		}
3108 		desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3109 	}
3110 
3111 	if (idx >= refs) {
3112 		return kIOReturnSuccess;
3113 	}
3114 
3115 	desc = &mach->objects[0];
3116 	while (idx--) {
3117 		switch (desc->type) {
3118 		case MACH_MSG_PORT_DESCRIPTOR:
3119 			descsize = sizeof(mach_msg_port_descriptor_t);
3120 			port = desc->name;
3121 			if (port) {
3122 				ipc_port_release_send(port);
3123 			}
3124 			break;
3125 
3126 		case MACH_MSG_OOL_DESCRIPTOR:
3127 			descsize = sizeof(mach_msg_ool_descriptor_t);
3128 			ool = (typeof(ool))desc;
3129 			copy = (vm_map_copy_t) ool->address;
3130 			if (copy) {
3131 				vm_map_copy_discard(copy);
3132 			}
3133 			break;
3134 
3135 		default:
3136 			descsize = -1UL;
3137 			break;
3138 		}
3139 		if (-1UL == descsize) {
3140 			break;
3141 		}
3142 		desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3143 	}
3144 
3145 	return kIOReturnBadArgument;
3146 }
3147 
3148 IOReturn
3149 IOUserServer::copyInObjects(IORPCMessageMach * mach, IORPCMessage * message,
3150     size_t size, bool copyObjects, bool consumePorts)
3151 {
3152 	uint64_t           refs;
3153 	uint32_t           idx, maxObjectCount;
3154 	ipc_port_t         port;
3155 	OSObject         * object;
3156 	size_t                       descsize;
3157 	mach_msg_port_descriptor_t * desc;
3158 	mach_msg_ool_descriptor_t  * ool;
3159 	vm_map_address_t             copyoutdata;
3160 	kern_return_t                kr;
3161 
3162 	refs           = message->objectRefs;
3163 	maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3164 //	assert(refs <= mach->msgh_body.msgh_descriptor_count);
3165 //	assert(refs <= maxObjectCount);
3166 	if (refs > mach->msgh_body.msgh_descriptor_count) {
3167 		return kIOReturnBadArgument;
3168 	}
3169 	if (refs > maxObjectCount) {
3170 		return kIOReturnBadArgument;
3171 	}
3172 
3173 	desc = &mach->objects[0];
3174 	for (idx = 0; idx < refs; idx++) {
3175 		switch (desc->type) {
3176 		case MACH_MSG_PORT_DESCRIPTOR:
3177 			descsize = sizeof(mach_msg_port_descriptor_t);
3178 
3179 			object = NULL;
3180 			port = desc->name;
3181 			if (port) {
3182 				if (copyObjects) {
3183 					object = copyObjectForSendRight(port, IKOT_UEXT_OBJECT);
3184 					if (!object) {
3185 						descsize = -1UL;
3186 						break;
3187 					}
3188 				}
3189 				if (consumePorts) {
3190 					ipc_port_release_send(port);
3191 				}
3192 			}
3193 			break;
3194 
3195 		case MACH_MSG_OOL_DESCRIPTOR:
3196 			descsize = sizeof(mach_msg_ool_descriptor_t);
3197 			ool = (typeof(ool))desc;
3198 
3199 			object = NULL;
3200 			if (copyObjects && ool->size && ool->address) {
3201 				kr = vm_map_copyout(kernel_map, &copyoutdata, (vm_map_copy_t) ool->address);
3202 				if (KERN_SUCCESS == kr) {
3203 					object = OSUnserializeXML((const char *) copyoutdata, ool->size);
3204 					// vm_map_copyout() has consumed the vm_map_copy_t in the message
3205 					ool->size = 0;
3206 					ool->address = NULL;
3207 					kr = vm_deallocate(kernel_map, copyoutdata, ool->size);
3208 					assert(KERN_SUCCESS == kr);
3209 				}
3210 				if (!object) {
3211 					descsize = -1UL;
3212 					break;
3213 				}
3214 			}
3215 			break;
3216 
3217 		default:
3218 			descsize = -1UL;
3219 			break;
3220 		}
3221 		if (-1UL == descsize) {
3222 			break;
3223 		}
3224 		if (copyObjects) {
3225 			message->objects[idx] = (OSObjectRef) object;
3226 		}
3227 		desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3228 	}
3229 
3230 	if (idx >= refs) {
3231 		return kIOReturnSuccess;
3232 	}
3233 
3234 	while (idx--) {
3235 		object = (OSObject *) message->objects[idx];
3236 		object->release();
3237 		message->objects[idx] = 0;
3238 	}
3239 
3240 	return kIOReturnBadArgument;
3241 }
3242 
3243 IOReturn
3244 IOUserServer::consumeObjects(IORPCMessage * message, size_t messageSize)
3245 {
3246 	uint64_t    refs, idx;
3247 	OSObject  * object;
3248 
3249 	refs   = message->objectRefs;
3250 	for (idx = 0; idx < refs; idx++) {
3251 		object = (OSObject *) message->objects[idx];
3252 		if (object) {
3253 			object->release();
3254 			message->objects[idx] = 0;
3255 		}
3256 	}
3257 
3258 	return kIOReturnSuccess;
3259 }
3260 
3261 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3262 
3263 bool
3264 IOUserServer::finalize(IOOptionBits options)
3265 {
3266 	OSArray   * services;
3267 
3268 	if (kIODKLogSetup & gIODKDebug) {
3269 		DKLOG("%s::finalize(%p)\n", getName(), this);
3270 	}
3271 
3272 	IOLockLock(gIOUserServerLock);
3273 	OSSafeReleaseNULL(fRootQueue);
3274 	IOLockUnlock(gIOUserServerLock);
3275 
3276 	services = NULL;
3277 	IOLockLock(fLock);
3278 	if (fServices) {
3279 		services = OSArray::withArray(fServices);
3280 	}
3281 	IOLockUnlock(fLock);
3282 
3283 	if (services) {
3284 		services->iterateObjects(^bool (OSObject * obj) {
3285 			IOService * service;
3286 			IOService * provider;
3287 			bool        started = false;
3288 
3289 			service = (IOService *) obj;
3290 			if (kIODKLogSetup & gIODKDebug) {
3291 			        DKLOG("%s::terminate(" DKS ")\n", getName(), DKN(service));
3292 			}
3293 			if (service->reserved->uvars) {
3294 			        started = service->reserved->uvars->started;
3295 			        service->reserved->uvars->serverDied = true;
3296 			        if (started) {
3297 			                provider = service->getProvider();
3298 			                serviceDidStop(service, provider);
3299 			                service->terminate(kIOServiceTerminateNeedWillTerminate | kIOServiceTerminateWithRematch);
3300 				}
3301 			}
3302 			if (!started) {
3303 			        DKLOG("%s::terminate(" DKS ") server exit before start()\n", getName(), DKN(service));
3304 			        serviceStop(service, NULL);
3305 			}
3306 			return false;
3307 		});
3308 		services->release();
3309 	}
3310 
3311 	return IOUserClient::finalize(options);
3312 }
3313 
3314 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3315 
3316 #undef super
3317 #define super IOUserClient
3318 
3319 OSDefineMetaClassAndStructors(IOUserServer, IOUserClient)
3320 
3321 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3322 
3323 IOUserClient * IOUserServer::withTask(task_t owningTask)
3324 {
3325 	IOUserServer * inst;
3326 
3327 	inst = new IOUserServer;
3328 	if (inst && !inst->init()) {
3329 		inst->release();
3330 		inst = NULL;
3331 		return inst;
3332 	}
3333 	inst->PMinit();
3334 
3335 	inst->fOwningTask = current_task();
3336 	inst->fEntitlements = IOUserClient::copyClientEntitlements(inst->fOwningTask);
3337 
3338 	if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
3339 		if (!inst->fEntitlements || !inst->fEntitlements->getObject(gIODriverKitEntitlementKey)) {
3340 			proc_t p;
3341 			pid_t  pid;
3342 
3343 			p = (proc_t)get_bsdtask_info(inst->fOwningTask);
3344 			if (p) {
3345 				pid = proc_pid(p);
3346 				IOLog(kIODriverKitEntitlementKey " entitlement check failed for %s[%d]\n", proc_best_name(p), pid);
3347 			}
3348 			inst->release();
3349 			inst = NULL;
3350 			return inst;
3351 		}
3352 	}
3353 
3354 	/* Mark the current task's space as eligible for uext object ports */
3355 	iokit_label_dext_task(inst->fOwningTask);
3356 
3357 	inst->fLock     = IOLockAlloc();
3358 	inst->fServices = OSArray::withCapacity(4);
3359 	inst->fClasses  = OSDictionary::withCapacity(16);
3360 	inst->fClasses->setOptions(OSCollection::kSort, OSCollection::kSort);
3361 
3362 	return inst;
3363 }
3364 
3365 IOReturn
3366 IOUserServer::clientClose(void)
3367 {
3368 	terminate();
3369 	return kIOReturnSuccess;
3370 }
3371 
3372 IOReturn
3373 IOUserServer::setProperties(OSObject * properties)
3374 {
3375 	IOReturn kr = kIOReturnUnsupported;
3376 	return kr;
3377 }
3378 
3379 void
3380 IOUserServer::stop(IOService * provider)
3381 {
3382 	fOwningTask = TASK_NULL;
3383 
3384 	PMstop();
3385 
3386 	IOServicePH::serverRemove(this);
3387 
3388 	OSSafeReleaseNULL(fRootQueue);
3389 
3390 	if (fInterruptLock) {
3391 		IOSimpleLockFree(fInterruptLock);
3392 	}
3393 }
3394 
3395 void
3396 IOUserServer::free()
3397 {
3398 	OSSafeReleaseNULL(fEntitlements);
3399 	OSSafeReleaseNULL(fClasses);
3400 	if (fLock) {
3401 		IOLockFree(fLock);
3402 	}
3403 	OSSafeReleaseNULL(fServices);
3404 	OSSafeReleaseNULL(fCheckInToken);
3405 	IOUserClient::free();
3406 }
3407 
3408 IOReturn
3409 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSUserMetaClass ** pCls)
3410 {
3411 	OSUserMetaClass * cls;
3412 	const OSSymbol  * sym;
3413 	uint64_t        * methodOptions;
3414 	const char      * queueNames;
3415 	uint32_t          methodOptionsEnd, queueNamesEnd;
3416 	IOReturn          ret = kIOReturnSuccess;
3417 
3418 	if (size < sizeof(OSClassDescription)) {
3419 		assert(false);
3420 		return kIOReturnBadArgument;
3421 	}
3422 
3423 	if (kIODKLogSetup & gIODKDebug) {
3424 		DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc->name, desc->queueNamesSize, desc->methodNamesSize);
3425 	}
3426 
3427 	if (desc->descriptionSize != size) {
3428 		assert(false);
3429 		return kIOReturnBadArgument;
3430 	}
3431 	if (os_add_overflow(desc->queueNamesOffset, desc->queueNamesSize, &queueNamesEnd)) {
3432 		assert(false);
3433 		return kIOReturnBadArgument;
3434 	}
3435 	if (queueNamesEnd > size) {
3436 		assert(false);
3437 		return kIOReturnBadArgument;
3438 	}
3439 	if (os_add_overflow(desc->methodOptionsOffset, desc->methodOptionsSize, &methodOptionsEnd)) {
3440 		assert(false);
3441 		return kIOReturnBadArgument;
3442 	}
3443 	if (methodOptionsEnd > size) {
3444 		assert(false);
3445 		return kIOReturnBadArgument;
3446 	}
3447 	// overlaps?
3448 	if ((desc->queueNamesOffset >= desc->methodOptionsOffset) && (desc->queueNamesOffset < methodOptionsEnd)) {
3449 		assert(false);
3450 		return kIOReturnBadArgument;
3451 	}
3452 	if ((queueNamesEnd >= desc->methodOptionsOffset) && (queueNamesEnd < methodOptionsEnd)) {
3453 		assert(false);
3454 		return kIOReturnBadArgument;
3455 	}
3456 
3457 	if (desc->methodOptionsSize & ((2 * sizeof(uint64_t)) - 1)) {
3458 		assert(false);
3459 		return kIOReturnBadArgument;
3460 	}
3461 	if (sizeof(desc->name) == strnlen(desc->name, sizeof(desc->name))) {
3462 		assert(false);
3463 		return kIOReturnBadArgument;
3464 	}
3465 	if (sizeof(desc->superName) == strnlen(desc->superName, sizeof(desc->superName))) {
3466 		assert(false);
3467 		return kIOReturnBadArgument;
3468 	}
3469 
3470 	cls = OSTypeAlloc(OSUserMetaClass);
3471 	assert(cls);
3472 	if (!cls) {
3473 		return kIOReturnNoMemory;
3474 	}
3475 
3476 	cls->description = (typeof(cls->description))IOMalloc(size);
3477 	assert(cls->description);
3478 	if (!cls->description) {
3479 		assert(false);
3480 		cls->release();
3481 		return kIOReturnNoMemory;
3482 	}
3483 	bcopy(desc, cls->description, size);
3484 
3485 	cls->methodCount = desc->methodOptionsSize / (2 * sizeof(uint64_t));
3486 	cls->methods = IONew(uint64_t, 2 * cls->methodCount);
3487 	if (!cls->methods) {
3488 		assert(false);
3489 		cls->release();
3490 		return kIOReturnNoMemory;
3491 	}
3492 
3493 	methodOptions = (typeof(methodOptions))(((uintptr_t) desc) + desc->methodOptionsOffset);
3494 	bcopy(methodOptions, cls->methods, 2 * cls->methodCount * sizeof(uint64_t));
3495 
3496 	queueNames = (typeof(queueNames))(((uintptr_t) desc) + desc->queueNamesOffset);
3497 	cls->queueNames = copyInStringArray(queueNames, desc->queueNamesSize);
3498 
3499 	sym = OSSymbol::withCString(desc->name);
3500 	assert(sym);
3501 	if (!sym) {
3502 		assert(false);
3503 		cls->release();
3504 		return kIOReturnNoMemory;
3505 	}
3506 
3507 	cls->name = sym;
3508 	cls->meta = OSMetaClass::copyMetaClassWithName(sym);
3509 	IOLockLock(fLock);
3510 	cls->superMeta = OSDynamicCast(OSUserMetaClass, fClasses->getObject(desc->superName));
3511 	if (fClasses->getObject(sym) != NULL) {
3512 		/* class with this name exists */
3513 		ret = kIOReturnBadArgument;
3514 	} else {
3515 		if (fClasses->setObject(sym, cls)) {
3516 			*pCls = cls;
3517 		} else {
3518 			/* could not add class to fClasses */
3519 			ret = kIOReturnNoMemory;
3520 		}
3521 	}
3522 	IOLockUnlock(fLock);
3523 	cls->release();
3524 	return ret;
3525 }
3526 
3527 IOReturn
3528 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSSharedPtr<OSUserMetaClass>& pCls)
3529 {
3530 	OSUserMetaClass* pClsRaw = NULL;
3531 	IOReturn result = registerClass(desc, size, &pClsRaw);
3532 	if (result == kIOReturnSuccess) {
3533 		pCls.reset(pClsRaw, OSRetain);
3534 	}
3535 	return result;
3536 }
3537 
3538 IOReturn
3539 IOUserServer::setRootQueue(IODispatchQueue * queue)
3540 {
3541 	assert(!fRootQueue);
3542 	if (fRootQueue) {
3543 		return kIOReturnStillOpen;
3544 	}
3545 	queue->retain();
3546 	fRootQueue = queue;
3547 
3548 	return kIOReturnSuccess;
3549 }
3550 
3551 IOReturn
3552 IOUserServer::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
3553     IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
3554 {
3555 	IOReturn ret = kIOReturnBadArgument;
3556 	mach_port_name_t portname;
3557 
3558 	switch (selector) {
3559 	case kIOUserServerMethodRegisterClass:
3560 	{
3561 		OSUserMetaClass * cls;
3562 		if (!args->structureInputSize) {
3563 			return kIOReturnBadArgument;
3564 		}
3565 		if (args->scalarOutputCount != 2) {
3566 			return kIOReturnBadArgument;
3567 		}
3568 		ret = registerClass((OSClassDescription *) args->structureInput, args->structureInputSize, &cls);
3569 		if (kIOReturnSuccess == ret) {
3570 			portname = iokit_make_send_right(fOwningTask, cls, IKOT_UEXT_OBJECT);
3571 			assert(portname);
3572 			args->scalarOutput[0] = portname;
3573 			args->scalarOutput[1] = kOSObjectRPCRemote;
3574 		}
3575 		break;
3576 	}
3577 	case kIOUserServerMethodStart:
3578 	{
3579 		if (args->scalarOutputCount != 1) {
3580 			return kIOReturnBadArgument;
3581 		}
3582 		if (!(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
3583 			if (args->scalarInputCount != 1) {
3584 				return kIOReturnBadArgument;
3585 			}
3586 			mach_port_name_t checkInPortName = ((typeof(checkInPortName))args->scalarInput[0]);
3587 			OSObject * obj = iokit_lookup_object_with_port_name(checkInPortName, IKOT_IOKIT_IDENT, fOwningTask);
3588 			IOUserServerCheckInToken * retrievedToken = OSDynamicCast(IOUserServerCheckInToken, obj);
3589 			if (retrievedToken != NULL) {
3590 				setCheckInToken(retrievedToken);
3591 			} else {
3592 				OSSafeReleaseNULL(obj);
3593 				return kIOReturnBadArgument;
3594 			}
3595 			OSSafeReleaseNULL(obj);
3596 		}
3597 		portname = iokit_make_send_right(fOwningTask, this, IKOT_UEXT_OBJECT);
3598 		assert(portname);
3599 		args->scalarOutput[0] = portname;
3600 		ret = kIOReturnSuccess;
3601 		break;
3602 	}
3603 	default:
3604 		break;
3605 	}
3606 
3607 	return ret;
3608 }
3609 
3610 IOExternalTrap *
3611 IOUserServer::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
3612 {
3613 	static const IOExternalTrap trapTemplate[] = {
3614 		{ NULL, (IOTrap) & IOUserServer::waitInterruptTrap},
3615 	};
3616 	if (index >= (sizeof(trapTemplate) / sizeof(IOExternalTrap))) {
3617 		return NULL;
3618 	}
3619 	*targetP = this;
3620 	return (IOExternalTrap *)&trapTemplate[index];
3621 }
3622 
3623 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3624 
3625 IOReturn
3626 IOUserServer::serviceAttach(IOService * service, IOService * provider)
3627 {
3628 	IOReturn           ret;
3629 	OSObjectUserVars * vars;
3630 	OSObject         * prop;
3631 	OSString         * str;
3632 	OSSymbol const*   bundleID;
3633 	char               execPath[1024];
3634 
3635 	vars = IONewZero(OSObjectUserVars, 1);
3636 	service->reserved->uvars = vars;
3637 
3638 	vars->userServer = this;
3639 	vars->userServer->retain();
3640 	IOLockLock(fLock);
3641 	if (-1U == fServices->getNextIndexOfObject(service, 0)) {
3642 		fServices->setObject(service);
3643 	}
3644 	IOLockUnlock(fLock);
3645 
3646 	prop = service->copyProperty(gIOUserClassKey);
3647 	str = OSDynamicCast(OSString, prop);
3648 	if (str) {
3649 		service->setName(str);
3650 	}
3651 	OSSafeReleaseNULL(prop);
3652 
3653 	prop = service->copyProperty(gIOModuleIdentifierKey);
3654 	bundleID = OSDynamicCast(OSSymbol, prop);
3655 	if (bundleID) {
3656 		execPath[0] = 0;
3657 		bool ok = OSKext::copyUserExecutablePath(bundleID, execPath, sizeof(execPath));
3658 		if (ok) {
3659 			ret = LoadModule(execPath);
3660 			if (kIODKLogSetup & gIODKDebug) {
3661 				DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret, execPath);
3662 			}
3663 		}
3664 	}
3665 	OSSafeReleaseNULL(prop);
3666 
3667 	ret = kIOReturnSuccess;
3668 
3669 	return ret;
3670 }
3671 
3672 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3673 
3674 #define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
3675 
3676 IOReturn
3677 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
3678     uint32_t type, OSDictionary * properties, IOUserClient ** handler)
3679 {
3680 	IOReturn           ret;
3681 	IOUserClient     * uc;
3682 	IOUserUserClient * userUC;
3683 	OSDictionary     * entitlements;
3684 	OSObject         * prop;
3685 	OSObject         * bundleID;
3686 	bool               ok;
3687 
3688 	*handler = NULL;
3689 	ret = service->NewUserClient(type, &uc);
3690 	if (kIOReturnSuccess != ret) {
3691 		return ret;
3692 	}
3693 	userUC = OSDynamicCast(IOUserUserClient, uc);
3694 	if (!userUC) {
3695 		uc->terminate();
3696 		OSSafeReleaseNULL(uc);
3697 		return kIOReturnUnsupported;
3698 	}
3699 	userUC->setTask(owningTask);
3700 
3701 	if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
3702 		bundleID = NULL;
3703 		entitlements = NULL;
3704 		if (fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowAnyKey)) {
3705 			ok = true;
3706 		} else {
3707 			entitlements = IOUserClient::copyClientEntitlements(owningTask);
3708 			bundleID = service->copyProperty(gIOModuleIdentifierKey);
3709 			ok = (entitlements
3710 			    && bundleID
3711 			    && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey)));
3712 			if (ok) {
3713 				bool found __block = false;
3714 				ok = prop->iterateObjects(^bool (OSObject * object) {
3715 					found = object->isEqualTo(bundleID);
3716 					return found;
3717 				});
3718 				ok = found;
3719 			}
3720 		}
3721 		if (ok) {
3722 			prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
3723 			ok = checkEntitlements(entitlements, prop, NULL, NULL);
3724 		}
3725 		OSSafeReleaseNULL(bundleID);
3726 		OSSafeReleaseNULL(entitlements);
3727 		if (!ok) {
3728 			DKLOG(DKS ":UC entitlements check failed\n", DKN(userUC));
3729 			uc->terminate();
3730 			OSSafeReleaseNULL(uc);
3731 			return kIOReturnNotPermitted;
3732 		}
3733 	}
3734 
3735 	*handler = userUC;
3736 
3737 	return ret;
3738 }
3739 
3740 IOReturn
3741 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
3742     uint32_t type, OSDictionary * properties, OSSharedPtr<IOUserClient>& handler)
3743 {
3744 	IOUserClient* handlerRaw = NULL;
3745 	IOReturn result = serviceNewUserClient(service, owningTask, securityID, type, properties, &handlerRaw);
3746 	handler.reset(handlerRaw, OSNoRetain);
3747 	return result;
3748 }
3749 
3750 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3751 
3752 static IOPMPowerState
3753     sPowerStates[] = {
3754 	{   .version                = kIOPMPowerStateVersion1,
3755 	    .capabilityFlags        = 0,
3756 	    .outputPowerCharacter   = 0,
3757 	    .inputPowerRequirement  = 0},
3758 	{   .version                = kIOPMPowerStateVersion1,
3759 	    .capabilityFlags        = kIOPMLowPower,
3760 	    .outputPowerCharacter   = kIOPMLowPower,
3761 	    .inputPowerRequirement  = kIOPMLowPower},
3762 	{   .version                = kIOPMPowerStateVersion1,
3763 	    .capabilityFlags        = kIOPMPowerOn,
3764 	    .outputPowerCharacter   = kIOPMPowerOn,
3765 	    .inputPowerRequirement  = kIOPMPowerOn},
3766 };
3767 
3768 IOReturn
3769 IOUserServer::setPowerState(unsigned long state, IOService * service)
3770 {
3771 	if (kIODKLogPM & gIODKDebug) {
3772 		DKLOG(DKS "::setPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
3773 	}
3774 	return kIOPMAckImplied;
3775 }
3776 
3777 IOReturn
3778 IOUserServer::serviceSetPowerState(IOService * controllingDriver, IOService * service, IOPMPowerFlags flags, unsigned long state)
3779 {
3780 	IOReturn ret;
3781 
3782 	if (service->reserved->uvars) {
3783 		if (!fSystemOff && !(kIODKDisablePM & gIODKDebug)) {
3784 			service->reserved->uvars->willPower = true;
3785 			service->reserved->uvars->willPowerState = state;
3786 			service->reserved->uvars->controllingDriver = controllingDriver;
3787 			if (kIODKLogPM & gIODKDebug) {
3788 				DKLOG(DKS "::serviceSetPowerState(%ld) 0x%qx, %d\n", DKN(service), state, fPowerStates, fSystemPowerAck);
3789 			}
3790 			ret = service->SetPowerState((uint32_t) flags);
3791 			if (kIOReturnSuccess == ret) {
3792 				return 20 * 1000 * 1000;
3793 			}
3794 		}
3795 		service->reserved->uvars->willPower = false;
3796 	}
3797 
3798 	return kIOPMAckImplied;
3799 }
3800 
3801 IOReturn
3802 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
3803 {
3804 	return kIOPMAckImplied;
3805 }
3806 
3807 IOReturn
3808 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
3809 {
3810 	unsigned int idx;
3811 	bool         pmAck;
3812 
3813 	pmAck = false;
3814 	IOLockLock(fLock);
3815 	idx = fServices->getNextIndexOfObject(service, 0);
3816 	if (-1U == idx) {
3817 		IOLockUnlock(fLock);
3818 		return kIOPMAckImplied;
3819 	}
3820 	assert(idx <= 63);
3821 
3822 	if (state) {
3823 		fPowerStates |= (1ULL << idx);
3824 	} else {
3825 		fPowerStates &= ~(1ULL << idx);
3826 	}
3827 	if (kIODKLogPM & gIODKDebug) {
3828 		DKLOG(DKS "::powerStateDidChangeTo(%ld) 0x%qx, %d\n", DKN(service), state, fPowerStates, fSystemPowerAck);
3829 	}
3830 	if (!fPowerStates && (pmAck = fSystemPowerAck)) {
3831 		fSystemPowerAck = false;
3832 		fSystemOff      = true;
3833 	}
3834 	IOLockUnlock(fLock);
3835 
3836 	if (pmAck) {
3837 		IOServicePH::serverAck(this);
3838 	}
3839 
3840 	return kIOPMAckImplied;
3841 }
3842 
3843 kern_return_t
3844 IOService::SetPowerState_Impl(
3845 	uint32_t powerFlags)
3846 {
3847 	if (kIODKLogPM & gIODKDebug) {
3848 		DKLOG(DKS "::SetPowerState(%d), %d\n", DKN(this), powerFlags, reserved->uvars->willPower);
3849 	}
3850 	if (reserved->uvars
3851 	    && reserved->uvars->userServer
3852 	    && reserved->uvars->willPower) {
3853 		IOReturn ret;
3854 		reserved->uvars->willPower = false;
3855 		ret = reserved->uvars->controllingDriver->setPowerState(reserved->uvars->willPowerState, this);
3856 		if (kIOPMAckImplied == ret) {
3857 			acknowledgeSetPowerState();
3858 		}
3859 		return kIOReturnSuccess;
3860 	}
3861 	return kIOReturnNotReady;
3862 }
3863 
3864 kern_return_t
3865 IOService::ChangePowerState_Impl(
3866 	uint32_t powerFlags)
3867 {
3868 	switch (powerFlags) {
3869 	case kIOServicePowerCapabilityOff:
3870 		changePowerStateToPriv(0);
3871 		break;
3872 	case kIOServicePowerCapabilityLow:
3873 		changePowerStateToPriv(1);
3874 		break;
3875 	case kIOServicePowerCapabilityOn:
3876 		changePowerStateToPriv(2);
3877 		break;
3878 	default:
3879 		return kIOReturnBadArgument;
3880 	}
3881 
3882 	return kIOReturnSuccess;
3883 }
3884 
3885 kern_return_t
3886 IOService::Create_Impl(
3887 	IOService * provider,
3888 	const char * propertiesKey,
3889 	IOService ** result)
3890 {
3891 	OSObject       * inst;
3892 	IOService      * service;
3893 	OSString       * str;
3894 	const OSSymbol * sym;
3895 	OSObject       * prop;
3896 	OSDictionary   * properties;
3897 	kern_return_t    ret;
3898 
3899 	if (provider != this) {
3900 		return kIOReturnUnsupported;
3901 	}
3902 
3903 	ret = kIOReturnUnsupported;
3904 	inst = NULL;
3905 	service = NULL;
3906 
3907 	prop = copyProperty(propertiesKey);
3908 	properties = OSDynamicCast(OSDictionary, prop);
3909 	assert(properties);
3910 	if (properties) {
3911 		str = OSDynamicCast(OSString, properties->getObject(gIOClassKey));
3912 		assert(str);
3913 		sym = OSSymbol::withString(str);
3914 		if (sym) {
3915 			inst = OSMetaClass::allocClassWithName(sym);
3916 			service = OSDynamicCast(IOService, inst);
3917 			if (service && service->init(properties) && service->attach(this)) {
3918 				reserved->uvars->userServer->serviceAttach(service, this);
3919 				service->reserved->uvars->started = true;
3920 				ret = kIOReturnSuccess;
3921 				*result = service;
3922 			}
3923 			OSSafeReleaseNULL(sym);
3924 		}
3925 	}
3926 
3927 	OSSafeReleaseNULL(prop);
3928 	if (kIOReturnSuccess != ret) {
3929 		OSSafeReleaseNULL(inst);
3930 	}
3931 
3932 	return ret;
3933 }
3934 
3935 kern_return_t
3936 IOService::Terminate_Impl(
3937 	uint64_t options)
3938 {
3939 	IOUserServer * us;
3940 
3941 	if (options) {
3942 		return kIOReturnUnsupported;
3943 	}
3944 
3945 	us = (typeof(us))thread_iokit_tls_get(0);
3946 	if (!reserved->uvars
3947 	    || (reserved->uvars->userServer != us)) {
3948 		return kIOReturnNotPermitted;
3949 	}
3950 	terminate(kIOServiceTerminateNeedWillTerminate);
3951 
3952 	return kIOReturnSuccess;
3953 }
3954 
3955 kern_return_t
3956 IOService::NewUserClient_Impl(
3957 	uint32_t type,
3958 	IOUserClient ** userClient)
3959 {
3960 	return kIOReturnError;
3961 }
3962 
3963 kern_return_t
3964 IOService::SearchProperty_Impl(
3965 	const char * name,
3966 	const char * plane,
3967 	uint64_t options,
3968 	OSContainer ** property)
3969 {
3970 	OSObject   * object;
3971 	IOOptionBits regOptions;
3972 
3973 	if (kIOServiceSearchPropertyParents & options) {
3974 		regOptions = kIORegistryIterateParents | kIORegistryIterateRecursively;
3975 	} else {
3976 		regOptions = 0;
3977 	}
3978 
3979 	object = copyProperty(name, IORegistryEntry::getPlane(plane), regOptions);
3980 	*property = object;
3981 
3982 	return object ? kIOReturnSuccess : kIOReturnNotFound;
3983 }
3984 
3985 kern_return_t
3986 IOService::CopyProviderProperties_Impl(
3987 	OSArray * propertyKeys,
3988 	OSArray ** properties)
3989 {
3990 	IOReturn    ret;
3991 	OSArray   * result;
3992 	IOService * provider;
3993 
3994 	result = OSArray::withCapacity(8);
3995 	if (!result) {
3996 		return kIOReturnNoMemory;
3997 	}
3998 
3999 	ret = kIOReturnSuccess;
4000 	for (provider = this; provider; provider = provider->getProvider()) {
4001 		OSObject     * obj;
4002 		OSDictionary * props;
4003 
4004 		obj = provider->copyProperty(gIOSupportedPropertiesKey);
4005 		props = OSDynamicCast(OSDictionary, obj);
4006 		if (!props) {
4007 			OSSafeReleaseNULL(obj);
4008 			props = provider->dictionaryWithProperties();
4009 		}
4010 		if (!props) {
4011 			ret = kIOReturnNoMemory;
4012 			break;
4013 		}
4014 		bool __block addClass = true;
4015 		if (propertyKeys) {
4016 			OSDictionary * retProps;
4017 			retProps = OSDictionary::withCapacity(4);
4018 			addClass = false;
4019 			if (!retProps) {
4020 				ret = kIOReturnNoMemory;
4021 				break;
4022 			}
4023 			propertyKeys->iterateObjects(^bool (OSObject * _key) {
4024 				OSString * key = OSDynamicCast(OSString, _key);
4025 				if (gIOClassKey->isEqualTo(key)) {
4026 				        addClass = true;
4027 				        return false;
4028 				}
4029 				retProps->setObject(key, props->getObject(key));
4030 				return false;
4031 			});
4032 			OSSafeReleaseNULL(props);
4033 			props = retProps;
4034 		}
4035 		if (addClass) {
4036 			OSArray * classes = OSArray::withCapacity(8);
4037 			if (!classes) {
4038 				ret = kIOReturnNoMemory;
4039 				break;
4040 			}
4041 			for (const OSMetaClass * meta = provider->getMetaClass(); meta; meta = meta->getSuperClass()) {
4042 				classes->setObject(meta->getClassNameSymbol());
4043 			}
4044 			props->setObject(gIOClassKey, classes);
4045 			OSSafeReleaseNULL(classes);
4046 		}
4047 		bool ok = result->setObject(props);
4048 		props->release();
4049 		if (!ok) {
4050 			ret = kIOReturnNoMemory;
4051 			break;
4052 		}
4053 	}
4054 	if (kIOReturnSuccess != ret) {
4055 		OSSafeReleaseNULL(result);
4056 	}
4057 	*properties = result;
4058 	return ret;
4059 }
4060 
4061 void
4062 IOUserServer::systemPower(bool powerOff)
4063 {
4064 	OSArray * services;
4065 
4066 	if (kIODKLogPM & gIODKDebug) {
4067 		DKLOG("%s::powerOff(%d) 0x%qx\n", getName(), powerOff, fPowerStates);
4068 	}
4069 
4070 	IOLockLock(fLock);
4071 	services = OSArray::withArray(fServices);
4072 
4073 	if (powerOff) {
4074 		fSystemPowerAck = (0 != fPowerStates);
4075 		if (!fSystemPowerAck) {
4076 			fSystemOff = true;
4077 		}
4078 		IOLockUnlock(fLock);
4079 
4080 		if (!fSystemPowerAck) {
4081 			IOServicePH::serverAck(this);
4082 		} else {
4083 			if (services) {
4084 				services->iterateObjects(^bool (OSObject * obj) {
4085 					IOService * service;
4086 					service = (IOService *) obj;
4087 					if (kIODKLogPM & gIODKDebug) {
4088 					        DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(service), 0);
4089 					}
4090 					service->reserved->uvars->powerOverride = service->getPowerState();
4091 					service->changePowerStateWithOverrideTo(0, 0);
4092 					return false;
4093 				});
4094 			}
4095 		}
4096 	} else {
4097 		fSystemOff = false;
4098 		IOLockUnlock(fLock);
4099 		if (services) {
4100 			services->iterateObjects(^bool (OSObject * obj) {
4101 				IOService * service;
4102 				service = (IOService *) obj;
4103 				if (-1U != service->reserved->uvars->powerOverride) {
4104 				        if (kIODKLogPM & gIODKDebug) {
4105 				                DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(service), service->reserved->uvars->powerOverride);
4106 					}
4107 				        service->changePowerStateWithOverrideTo(service->reserved->uvars->powerOverride, 0);
4108 				        service->reserved->uvars->powerOverride = -1U;
4109 				}
4110 				return false;
4111 			});
4112 		}
4113 	}
4114 	OSSafeReleaseNULL(services);
4115 }
4116 
4117 
4118 
4119 IOReturn
4120 IOUserServer::serviceStarted(IOService * service, IOService * provider, bool result)
4121 {
4122 	IOReturn    ret;
4123 	IOService * pmProvider;
4124 	bool        joinTree;
4125 
4126 	DKLOG(DKS "::start(" DKS ") %s\n", DKN(service), DKN(provider), result ? "ok" : "fail");
4127 
4128 	if (!result) {
4129 		ret = kIOReturnSuccess;
4130 		return ret;
4131 	}
4132 
4133 	if (!fRootNotifier) {
4134 		ret = registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4135 		assert(kIOReturnSuccess == ret);
4136 		IOServicePH::serverAdd(this);
4137 		fRootNotifier = true;
4138 	}
4139 
4140 	joinTree = false;
4141 	if (!(kIODKDisablePM & gIODKDebug) && !service->pm_vars) {
4142 		service->PMinit();
4143 		ret = service->registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4144 		assert(kIOReturnSuccess == ret);
4145 		joinTree = true;
4146 	}
4147 
4148 	pmProvider = service;
4149 	while (pmProvider && !pmProvider->inPlane(gIOPowerPlane)) {
4150 		pmProvider = pmProvider->getProvider();
4151 	}
4152 	if (pmProvider) {
4153 		OSObject  * prop;
4154 		OSString  * str;
4155 		prop = pmProvider->copyProperty("non-removable");
4156 		if (prop) {
4157 			str = OSDynamicCast(OSString, prop);
4158 			if (str && str->isEqualTo("yes")) {
4159 				pmProvider = NULL;
4160 			}
4161 			prop->release();
4162 		}
4163 	}
4164 
4165 	if (!(kIODKDisablePM & gIODKDebug) && pmProvider) {
4166 		IOLockLock(fLock);
4167 		unsigned int idx = fServices->getNextIndexOfObject(service, 0);
4168 		assert(idx <= 63);
4169 		fPowerStates |= (1ULL << idx);
4170 		IOLockUnlock(fLock);
4171 
4172 		if (joinTree) {
4173 			pmProvider->joinPMtree(service);
4174 			service->reserved->uvars->userServerPM = true;
4175 		}
4176 	}
4177 
4178 	service->registerInterestedDriver(this);
4179 	service->reserved->uvars->started = true;
4180 
4181 	return kIOReturnSuccess;
4182 }
4183 
4184 
4185 IOReturn
4186 IOUserServer::serviceOpen(IOService * provider, IOService * client)
4187 {
4188 	OSObjectUserVars * uvars;
4189 
4190 	uvars = client->reserved->uvars;
4191 	if (!uvars->openProviders) {
4192 		uvars->openProviders = OSArray::withObjects((const OSObject **) &provider, 1);
4193 	} else if (-1U == uvars->openProviders->getNextIndexOfObject(client, 0)) {
4194 		uvars->openProviders->setObject(provider);
4195 	}
4196 
4197 	return kIOReturnSuccess;
4198 }
4199 
4200 IOReturn
4201 IOUserServer::serviceClose(IOService * provider, IOService * client)
4202 {
4203 	OSObjectUserVars * uvars;
4204 	unsigned int       idx;
4205 
4206 	uvars = client->reserved->uvars;
4207 	if (!uvars->openProviders) {
4208 		return kIOReturnNotOpen;
4209 	}
4210 	idx = uvars->openProviders->getNextIndexOfObject(client, 0);
4211 	if (-1U == idx) {
4212 		return kIOReturnNotOpen;
4213 	}
4214 	uvars->openProviders->removeObject(idx);
4215 
4216 	return kIOReturnSuccess;
4217 }
4218 
4219 
4220 IOReturn
4221 IOUserServer::serviceStop(IOService * service, IOService *)
4222 {
4223 	IOReturn           ret;
4224 	uint32_t           idx, queueAlloc;
4225 	OSObjectUserVars * uvars;
4226 
4227 	IOLockLock(fLock);
4228 	idx = fServices->getNextIndexOfObject(service, 0);
4229 	if (-1U != idx) {
4230 		fServices->removeObject(idx);
4231 		uvars = service->reserved->uvars;
4232 		uvars->stopped = true;
4233 	}
4234 	IOLockUnlock(fLock);
4235 
4236 	if (-1U == idx) {
4237 		return kIOReturnSuccess;
4238 	}
4239 
4240 	if (uvars->queueArray && uvars->userMeta) {
4241 		queueAlloc = 1;
4242 		if (uvars->userMeta->queueNames) {
4243 			queueAlloc += uvars->userMeta->queueNames->count;
4244 		}
4245 		for (idx = 0; idx < queueAlloc; idx++) {
4246 			OSSafeReleaseNULL(uvars->queueArray[idx]);
4247 		}
4248 		IOSafeDeleteNULL(uvars->queueArray, IODispatchQueue *, queueAlloc);
4249 	}
4250 
4251 	(void) service->deRegisterInterestedDriver(this);
4252 	if (uvars->userServerPM) {
4253 		service->PMstop();
4254 	}
4255 
4256 	ret = kIOReturnSuccess;
4257 	return ret;
4258 }
4259 
4260 void
4261 IOUserServer::serviceFree(IOService * service)
4262 {
4263 	OSObjectUserVars * uvars;
4264 
4265 	uvars = service->reserved->uvars;
4266 	if (!uvars) {
4267 		return;
4268 	}
4269 	OSSafeReleaseNULL(uvars->userServer);
4270 	IOSafeDeleteNULL(service->reserved->uvars, OSObjectUserVars, 1);
4271 }
4272 
4273 void
4274 IOUserServer::serviceWillTerminate(IOService * client, IOService * provider, IOOptionBits options)
4275 {
4276 	IOReturn ret;
4277 	bool     willTerminate;
4278 
4279 	willTerminate = false;
4280 	if (client->lockForArbitration(true)) {
4281 		if (!client->reserved->uvars->serverDied
4282 		    && !client->reserved->uvars->willTerminate) {
4283 			client->reserved->uvars->willTerminate = true;
4284 			willTerminate = true;
4285 		}
4286 		client->unlockForArbitration();
4287 	}
4288 
4289 	if (willTerminate) {
4290 		if (IOServicePH::serverSlept()) {
4291 			client->Stop_async(provider);
4292 			ret = kIOReturnOffline;
4293 		} else {
4294 			ret = client->Stop(provider);
4295 		}
4296 		if (kIOReturnSuccess != ret) {
4297 			IOUserServer::serviceDidStop(client, provider);
4298 			ret = kIOReturnSuccess;
4299 		}
4300 	}
4301 }
4302 
4303 void
4304 IOUserServer::serviceDidTerminate(IOService * client, IOService * provider, IOOptionBits options, bool * defer)
4305 {
4306 	if (client->lockForArbitration(true)) {
4307 		client->reserved->uvars->didTerminate = true;
4308 		if (!client->reserved->uvars->serverDied
4309 		    && !client->reserved->uvars->stopped) {
4310 			*defer = true;
4311 		}
4312 		client->unlockForArbitration();
4313 	}
4314 }
4315 
4316 void
4317 IOUserServer::serviceDidStop(IOService * client, IOService * provider)
4318 {
4319 	bool complete;
4320 	OSArray * closeArray;
4321 
4322 	complete = false;
4323 	closeArray = NULL;
4324 
4325 	if (client->lockForArbitration(true)) {
4326 		if (client->reserved->uvars
4327 		    && client->reserved->uvars->willTerminate
4328 		    && !client->reserved->uvars->stopped) {
4329 			client->reserved->uvars->stopped = true;
4330 			complete = client->reserved->uvars->didTerminate;
4331 		}
4332 
4333 		if (client->reserved->uvars) {
4334 			closeArray = client->reserved->uvars->openProviders;
4335 			client->reserved->uvars->openProviders = NULL;
4336 		}
4337 		client->unlockForArbitration();
4338 		if (closeArray) {
4339 			closeArray->iterateObjects(^bool (OSObject * obj) {
4340 				IOService * toClose;
4341 				toClose = OSDynamicCast(IOService, obj);
4342 				if (toClose) {
4343 				        DKLOG(DKS ":force close (" DKS ")\n", DKN(client), DKN(toClose));
4344 				        toClose->close(client);
4345 				}
4346 				return false;
4347 			});
4348 			closeArray->release();
4349 		}
4350 	}
4351 	if (complete) {
4352 		bool defer = false;
4353 		client->didTerminate(provider, 0, &defer);
4354 	}
4355 }
4356 
4357 kern_return_t
4358 IOService::Stop_Impl(
4359 	IOService * provider)
4360 {
4361 	IOUserServer::serviceDidStop(this, provider);
4362 
4363 	return kIOReturnSuccess;
4364 }
4365 
4366 void
4367 IOService::Stop_async_Impl(
4368 	IOService * provider)
4369 {
4370 }
4371 
4372 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4373 
4374 #undef super
4375 #define super IOUserClient
4376 
4377 OSDefineMetaClassAndStructors(IOUserUserClient, IOUserClient)
4378 
4379 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4380 
4381 IOReturn
4382 IOUserUserClient::setTask(task_t task)
4383 {
4384 	task_reference(task);
4385 	fTask = task;
4386 
4387 	return kIOReturnSuccess;
4388 }
4389 
4390 void
4391 IOUserUserClient::stop(IOService * provider)
4392 {
4393 	if (fTask) {
4394 		task_deallocate(fTask);
4395 		fTask = NULL;
4396 	}
4397 	super::stop(provider);
4398 }
4399 
4400 IOReturn
4401 IOUserUserClient::clientClose(void)
4402 {
4403 	terminate(kIOServiceTerminateNeedWillTerminate);
4404 	return kIOReturnSuccess;
4405 }
4406 
4407 IOReturn
4408 IOUserUserClient::setProperties(OSObject * properties)
4409 {
4410 	IOReturn ret = kIOReturnUnsupported;
4411 	return ret;
4412 }
4413 
4414 struct IOUserUserClientActionRef {
4415 	OSAsyncReference64 asyncRef;
4416 };
4417 
4418 void
4419 IOUserClient::KernelCompletion_Impl(
4420 	OSAction * action,
4421 	IOReturn status,
4422 	const unsigned long long * asyncData,
4423 	uint32_t asyncDataCount)
4424 {
4425 	IOUserUserClientActionRef * ref;
4426 
4427 	ref = (typeof(ref))action->GetReference();
4428 
4429 	IOUserClient::sendAsyncResult64(ref->asyncRef, status, (io_user_reference_t *) asyncData, asyncDataCount);
4430 }
4431 
4432 kern_return_t
4433 IOUserClient::_ExternalMethod_Impl(
4434 	uint64_t selector,
4435 	const unsigned long long * scalarInput,
4436 	uint32_t scalarInputCount,
4437 	OSData * structureInput,
4438 	IOMemoryDescriptor * structureInputDescriptor,
4439 	unsigned long long * scalarOutput,
4440 	uint32_t * scalarOutputCount,
4441 	uint64_t structureOutputMaximumSize,
4442 	OSData ** structureOutput,
4443 	IOMemoryDescriptor * structureOutputDescriptor,
4444 	OSAction * completion)
4445 {
4446 	return kIOReturnUnsupported;
4447 }
4448 
4449 IOReturn
4450 IOUserUserClient::clientMemoryForType(UInt32 type,
4451     IOOptionBits * koptions,
4452     IOMemoryDescriptor ** kmemory)
4453 {
4454 	IOReturn             kr;
4455 	uint64_t             options;
4456 	IOMemoryDescriptor * memory;
4457 
4458 	kr = CopyClientMemoryForType(type, &options, &memory);
4459 
4460 	*koptions = 0;
4461 	*kmemory  = NULL;
4462 	if (kIOReturnSuccess != kr) {
4463 		return kr;
4464 	}
4465 
4466 	if (kIOUserClientMemoryReadOnly & options) {
4467 		*koptions |= kIOMapReadOnly;
4468 	}
4469 	*kmemory = memory;
4470 
4471 	return kr;
4472 }
4473 
4474 IOReturn
4475 IOUserUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
4476     IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
4477 {
4478 	IOReturn   kr;
4479 	OSData   * structureInput;
4480 	OSData   * structureOutput;
4481 	size_t     copylen;
4482 	uint64_t   structureOutputSize;
4483 	OSAction                  * action;
4484 	IOUserUserClientActionRef * ref;
4485 
4486 	kr             = kIOReturnUnsupported;
4487 	structureInput = NULL;
4488 	action         = NULL;
4489 	ref            = NULL;
4490 
4491 	if (args->structureInputSize) {
4492 		structureInput = OSData::withBytesNoCopy((void *) args->structureInput, args->structureInputSize);
4493 	}
4494 
4495 	if (MACH_PORT_NULL != args->asyncWakePort) {
4496 		kr = CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef), &action);
4497 		assert(KERN_SUCCESS == kr);
4498 		ref = (typeof(ref))action->GetReference();
4499 		bcopy(args->asyncReference, &ref->asyncRef[0], args->asyncReferenceCount * sizeof(ref->asyncRef[0]));
4500 
4501 		kr = action->SetAbortedHandler(^(void) {
4502 			IOUserUserClientActionRef * ref;
4503 			IOReturn ret;
4504 
4505 			ref = (typeof(ref))action->GetReference();
4506 			ret = releaseAsyncReference64(ref->asyncRef);
4507 			assert(kIOReturnSuccess == ret);
4508 			bzero(&ref->asyncRef[0], sizeof(ref->asyncRef));
4509 		});
4510 		assert(KERN_SUCCESS == kr);
4511 	}
4512 
4513 	if (args->structureVariableOutputData) {
4514 		structureOutputSize = kIOUserClientVariableStructureSize;
4515 	} else if (args->structureOutputDescriptor) {
4516 		structureOutputSize = args->structureOutputDescriptor->getLength();
4517 	} else {
4518 		structureOutputSize = args->structureOutputSize;
4519 	}
4520 
4521 	kr = _ExternalMethod(selector, &args->scalarInput[0], args->scalarInputCount,
4522 	    structureInput, args->structureInputDescriptor,
4523 	    args->scalarOutput, &args->scalarOutputCount,
4524 	    structureOutputSize, &structureOutput, args->structureOutputDescriptor,
4525 	    action);
4526 
4527 	OSSafeReleaseNULL(structureInput);
4528 	OSSafeReleaseNULL(action);
4529 
4530 	if (kIOReturnSuccess != kr) {
4531 		if (ref) {
4532 			// mig will destroy any async port, remove our pointer to it
4533 			bzero(&ref->asyncRef[0], sizeof(ref->asyncRef));
4534 		}
4535 		return kr;
4536 	}
4537 	if (structureOutput) {
4538 		if (args->structureVariableOutputData) {
4539 			*args->structureVariableOutputData = structureOutput;
4540 		} else {
4541 			copylen = structureOutput->getLength();
4542 			if (copylen > args->structureOutputSize) {
4543 				kr = kIOReturnBadArgument;
4544 			} else {
4545 				bcopy((const void *) structureOutput->getBytesNoCopy(), args->structureOutput, copylen);
4546 			}
4547 			OSSafeReleaseNULL(structureOutput);
4548 		}
4549 	}
4550 
4551 	return kr;
4552 }
4553 
4554 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4555 
4556 void
4557 IOUserServerCheckInToken::setNoSendersNotification(IOUserServerCheckInNotificationHandler handler,
4558     void* handlerArgs)
4559 {
4560 	this->handler = handler;
4561 	this->handlerArgs = handlerArgs;
4562 }
4563 
4564 void
4565 IOUserServerCheckInToken::notifyNoSenders(IOUserServerCheckInToken *token)
4566 {
4567 	if (token->handler) {
4568 		token->handler(token, token->handlerArgs);
4569 	}
4570 }
4571 
4572 void
4573 IOUserServerCheckInToken::clearNotification()
4574 {
4575 	this->handler = NULL;
4576 	this->handlerArgs = NULL;
4577 }
4578 
4579 IOUserServerCheckInToken *
4580 IOUserServerCheckInToken::create()
4581 {
4582 	IOUserServerCheckInToken *me = new IOUserServerCheckInToken;
4583 	if (me && !me->init()) {
4584 		me->release();
4585 		return NULL;
4586 	}
4587 	me->clearNotification();
4588 	return me;
4589 }
4590 
4591 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4592