2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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/IOLib.h>
39 #include <IOKit/IOBSD.h>
40 #include <IOKit/system.h>
41 #include <IOKit/IOUserServer.h>
42 #include <IOKit/IOInterruptEventSource.h>
43 #include <IOKit/IOTimerEventSource.h>
44 #include <IOKit/pwr_mgt/RootDomain.h>
45 #include <libkern/c++/OSKext.h>
46 #include <libkern/OSDebug.h>
47 #include <libkern/Block.h>
49 #include "IOKitKernelInternal.h"
51 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
53 #include <DriverKit/IODispatchQueue.h>
54 #include <DriverKit/OSObject.h>
55 #include <DriverKit/OSAction.h>
56 #include <DriverKit/IODispatchSource.h>
57 #include <DriverKit/IOInterruptDispatchSource.h>
58 #include <DriverKit/IOService.h>
59 #include <DriverKit/IOMemoryDescriptor.h>
60 #include <DriverKit/IOBufferMemoryDescriptor.h>
61 #include <DriverKit/IOMemoryMap.h>
62 #include <DriverKit/IODataQueueDispatchSource.h>
63 #include <DriverKit/IOServiceNotificationDispatchSource.h>
64 #include <DriverKit/IOUserServer.h>
66 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
68 #include <System/IODataQueueDispatchSourceShared.h>
70 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
72 SInt64 gIODKDebug
= kIODKEnable
;
74 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
78 class OSUserMetaClass
: public OSObject
80 OSDeclareDefaultStructors(OSUserMetaClass
);
82 const OSSymbol
* name
;
83 const OSMetaClass
* meta
;
84 OSUserMetaClass
* superMeta
;
88 OSClassDescription
* description
;
89 IOPStrings
* queueNames
;
93 virtual void free() override
;
94 virtual kern_return_t
Dispatch(const IORPC rpc
) APPLE_KEXT_OVERRIDE
;
96 OSDefineMetaClassAndStructors(OSUserMetaClass
, OSObject
);
98 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
100 class IOUserService
: public IOService
102 friend class IOService
;
104 OSDeclareDefaultStructors(IOUserService
)
107 start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
110 OSDefineMetaClassAndStructors(IOUserService
, IOService
)
112 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
114 class IOUserUserClient
: public IOUserClient
116 OSDeclareDefaultStructors(IOUserUserClient
);
120 IOReturn
setTask(task_t task
);
121 virtual void stop(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
122 virtual IOReturn
clientClose(void) APPLE_KEXT_OVERRIDE
;
123 virtual IOReturn
setProperties(OSObject
* properties
) APPLE_KEXT_OVERRIDE
;
124 virtual IOReturn
externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
125 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
) APPLE_KEXT_OVERRIDE
;
126 virtual IOReturn
clientMemoryForType(UInt32 type
,
127 IOOptionBits
* options
,
128 IOMemoryDescriptor
** memory
) APPLE_KEXT_OVERRIDE
;
132 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
136 IOUserService::start(IOService
* provider
)
141 ret
= Start(provider
);
142 if (kIOReturnSuccess
!= ret
) {
149 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
153 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
155 struct IODispatchQueue_IVars
{
156 IOUserServer
* userServer
;
157 IODispatchQueue
* queue
;
161 mach_port_t serverPort
;
164 struct OSAction_IVars
{
166 uint64_t targetmsgid
;
168 OSActionAbortedHandler abortedHandler
;
169 size_t referenceSize
;
173 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
176 IMPL(IOService
, GetRegistryEntryID
)
178 IOReturn ret
= kIOReturnSuccess
;
180 *registryEntryID
= getRegistryEntryID();
186 IMPL(IOService
, SetName
)
188 IOReturn ret
= kIOReturnSuccess
;
196 IMPL(IOService
, Start
)
198 IOReturn ret
= kIOReturnSuccess
;
203 IMPL(IOService
, RegisterService
)
205 IOReturn ret
= kIOReturnSuccess
;
213 IMPL(IOService
, CopyDispatchQueue
)
215 IODispatchQueue
* result
;
220 ret
= kIOReturnNotFound
;
222 if (!strcmp("Default", name
)) {
224 } else if (reserved
->uvars
->userMeta
225 && reserved
->uvars
->userMeta
->queueNames
) {
226 index
= reserved
->uvars
->userServer
->stringArrayIndex(reserved
->uvars
->userMeta
->queueNames
, name
);
232 if ((service
= getProvider())) {
233 ret
= service
->CopyDispatchQueue(name
, queue
);
236 result
= reserved
->uvars
->queueArray
[index
];
240 ret
= kIOReturnSuccess
;
248 IMPL(IOService
, SetDispatchQueue
)
250 IOReturn ret
= kIOReturnSuccess
;
253 if (kIODKLogSetup
& gIODKDebug
) {
254 DKLOG(DKS
"::SetDispatchQueue(%s)\n", DKN(this), name
);
256 queue
->ivars
->userServer
= reserved
->uvars
->userServer
;
258 if (!strcmp("Default", name
)) {
260 } else if (reserved
->uvars
->userMeta
261 && reserved
->uvars
->userMeta
->queueNames
) {
262 index
= reserved
->uvars
->userServer
->stringArrayIndex(reserved
->uvars
->userMeta
->queueNames
, name
);
268 ret
= kIOReturnBadArgument
;
270 reserved
->uvars
->queueArray
[index
] = queue
;
278 IMPL(IOService
, SetProperties
)
284 ret
= setProperties(properties
);
286 if (kIOReturnUnsupported
== ret
) {
287 dict
= OSDynamicCast(OSDictionary
, properties
);
288 us
= (typeof(us
))thread_iokit_tls_get(0);
289 if (dict
&& reserved
->uvars
&& (reserved
->uvars
->userServer
== us
)) {
290 ret
= runPropertyActionBlock(^IOReturn (void) {
291 OSDictionary
* userProps
;
294 userProps
= OSDynamicCast(OSDictionary
, getProperty(gIOUserServicePropertiesKey
));
296 userProps
= (typeof(userProps
))userProps
->copyCollection();
298 userProps
= OSDictionary::withCapacity(4);
301 ret
= kIOReturnNoMemory
;
303 bool ok
= userProps
->merge(dict
);
305 ok
= setProperty(gIOUserServicePropertiesKey
, userProps
);
307 OSSafeReleaseNULL(userProps
);
308 ret
= ok
? kIOReturnSuccess
: kIOReturnNotWritable
;
319 IMPL(IOService
, CopyProperties
)
321 IOReturn ret
= kIOReturnSuccess
;
322 *properties
= dictionaryWithProperties();
326 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
329 IMPL(IOMemoryDescriptor
, _CopyState
)
333 state
->length
= _length
;
334 state
->options
= _flags
;
336 ret
= kIOReturnSuccess
;
342 IOMemoryDescriptor::GetLength(uint64_t * returnLength
)
344 *returnLength
= getLength();
346 return kIOReturnSuccess
;
350 IMPL(IOMemoryDescriptor
, CreateMapping
)
353 IOMemoryMap
* resultMap
;
354 IOOptionBits koptions
;
355 mach_vm_address_t atAddress
;
357 ret
= kIOReturnSuccess
;
361 if (kIOMemoryMapFixedAddress
& options
) {
366 koptions
|= kIOMapAnywhere
;
369 if (kIOMemoryMapReadOnly
& options
|| (kIODirectionOut
== getDirection())) {
370 if (!reserved
|| (current_task() != reserved
->creator
)) {
371 koptions
|= kIOMapReadOnly
;
375 switch (0xFF00 & options
) {
376 case kIOMemoryMapCacheModeDefault
:
377 koptions
|= kIOMapDefaultCache
;
379 case kIOMemoryMapCacheModeInhibit
:
380 koptions
|= kIOMapInhibitCache
;
382 case kIOMemoryMapCacheModeCopyback
:
383 koptions
|= kIOMapCopybackCache
;
385 case kIOMemoryMapCacheModeWriteThrough
:
386 koptions
|= kIOMapWriteThruCache
;
389 ret
= kIOReturnBadArgument
;
392 if (kIOReturnSuccess
== ret
) {
393 resultMap
= createMappingInTask(current_task(), atAddress
, koptions
, offset
, length
);
395 ret
= kIOReturnError
;
405 IMPL(IOMemoryDescriptor
, PrepareForDMA
)
413 return kIOReturnBadArgument
;
416 count
= *segmentsCount
;
418 for (idx
= 0; idx
< count
; idx
++) {
420 segments
[idx
].address
= getPhysicalSegment(offset
, &segments
[idx
].length
);
422 segments
[idx
].address
= 0;
424 if (!segments
[idx
].address
) {
427 sumLength
+= segments
[idx
].length
;
428 offset
+= segments
[idx
].length
;
430 *returnLength
= sumLength
;
431 *segmentsCount
= idx
;
435 if (kIODirectionOut
& _flags
) {
436 lflags
|= kIOMemoryDirectionOut
;
438 if (kIODirectionIn
& _flags
) {
439 lflags
|= kIOMemoryDirectionIn
;
443 ret
= kIOReturnSuccess
;
448 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
451 IMPL(IOMemoryMap
, _CopyState
)
455 state
->offset
= fOffset
;
456 state
->length
= getLength();
457 state
->address
= getAddress();
458 state
->options
= getMapOptions();
460 ret
= kIOReturnSuccess
;
465 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
468 IMPL(IOBufferMemoryDescriptor
, Create
)
471 IOBufferMemoryDescriptor
* bmd
;
472 IOMemoryDescriptorReserved
* reserved
;
474 if (options
& ~((uint64_t) kIOMemoryDirectionOutIn
)) {
475 // no other options currently defined
476 return kIOReturnBadArgument
;
478 options
&= kIOMemoryDirectionOutIn
;
479 options
|= kIOMemoryKernelUserShared
;
480 bmd
= IOBufferMemoryDescriptor::inTaskWithOptions(
481 kernel_task
, options
, capacity
, alignment
);
486 return kIOReturnNoMemory
;
489 reserved
= bmd
->getKernelReserved();
490 reserved
->creator
= current_task();
491 task_reference(reserved
->creator
);
493 ret
= kIOReturnSuccess
;
499 IMPL(IOBufferMemoryDescriptor
, SetLength
)
502 return kIOReturnSuccess
;
505 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
508 OSAction::Create(OSAction_Create_Args
)
511 ret
= OSAction::Create_Call(target
, targetmsgid
, msgid
, referenceSize
, action
);
516 IMPL(OSAction
, Create
)
521 if (os_add_overflow(referenceSize
, sizeof(OSAction_IVars
), &allocsize
)) {
522 return kIOReturnBadArgument
;
524 inst
= OSTypeAlloc(OSAction
);
526 return kIOReturnNoMemory
;
528 inst
->ivars
= (typeof(inst
->ivars
))(uintptr_t) IONewZero(uint8_t, allocsize
);
531 return kIOReturnNoMemory
;
534 inst
->ivars
->target
= target
;
535 inst
->ivars
->targetmsgid
= targetmsgid
;
536 inst
->ivars
->msgid
= msgid
;
537 inst
->ivars
->referenceSize
= referenceSize
;
541 return kIOReturnSuccess
;
548 if (ivars
->abortedHandler
) {
549 Block_release(ivars
->abortedHandler
);
550 ivars
->abortedHandler
= NULL
;
552 OSSafeReleaseNULL(ivars
->target
);
553 IOSafeDeleteNULL(ivars
, uint8_t, ivars
->referenceSize
+ sizeof(OSAction_IVars
));
555 return super::free();
559 OSAction::GetReference()
561 assert(ivars
&& ivars
->referenceSize
);
562 return &ivars
->reference
[0];
566 OSAction::SetAbortedHandler(OSActionAbortedHandler handler
)
568 ivars
->abortedHandler
= Block_copy(handler
);
569 return kIOReturnSuccess
;
573 OSAction::Aborted_Impl(void)
575 if (ivars
->abortedHandler
) {
576 ivars
->abortedHandler();
580 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
582 struct IODispatchSource_IVars
{
584 IODispatchSource
* source
;
585 IOUserServer
* server
;
586 IODispatchQueue_IVars
* queue
;
591 IODispatchSource::init()
593 if (!super::init()) {
597 ivars
= IONewZero(IODispatchSource_IVars
, 1);
599 ivars
->source
= this;
605 IODispatchSource::free()
607 IOSafeDeleteNULL(ivars
, IODispatchSource_IVars
, 1);
612 IMPL(IODispatchSource
, SetEnable
)
614 return SetEnableWithCompletion(enable
, NULL
);
617 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
619 struct IOInterruptDispatchSource_IVars
{
620 IOService
* provider
;
631 IOInterruptDispatchSourceInterrupt(OSObject
* target
, void * refCon
,
632 IOService
* nub
, int source
)
634 IOInterruptDispatchSource_IVars
* ivars
= (typeof(ivars
))refCon
;
637 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
640 ivars
->time
= mach_absolute_time();
641 thread_wakeup_thread((event_t
) ivars
, ivars
->waiter
);
642 ivars
->waiter
= NULL
;
644 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
648 IMPL(IOInterruptDispatchSource
, Create
)
651 IOInterruptDispatchSource
* inst
;
653 inst
= OSTypeAlloc(IOInterruptDispatchSource
);
656 return kIOReturnNoMemory
;
659 inst
->ivars
->lock
= IOSimpleLockAlloc();
661 ret
= provider
->registerInterrupt(index
, inst
, IOInterruptDispatchSourceInterrupt
, inst
->ivars
);
662 if (kIOReturnSuccess
== ret
) {
663 inst
->ivars
->intIndex
= index
;
664 inst
->ivars
->provider
= provider
;
671 IOInterruptDispatchSource::init()
673 if (!super::init()) {
676 ivars
= IONewZero(IOInterruptDispatchSource_IVars
, 1);
685 IOInterruptDispatchSource::free()
689 if (ivars
&& ivars
->provider
) {
690 ret
= ivars
->provider
->unregisterInterrupt(ivars
->intIndex
);
691 assert(kIOReturnSuccess
== ret
);
694 if (ivars
&& ivars
->lock
) {
695 IOSimpleLockFree(ivars
->lock
);
698 IOSafeDeleteNULL(ivars
, IOInterruptDispatchSource_IVars
, 1);
704 IMPL(IOInterruptDispatchSource
, SetHandler
)
707 OSAction
* oldAction
;
709 oldAction
= (typeof(oldAction
))ivars
->action
;
710 if (oldAction
&& OSCompareAndSwapPtr(oldAction
, NULL
, &ivars
->action
)) {
711 oldAction
->release();
714 ivars
->action
= action
;
716 ret
= kIOReturnSuccess
;
722 IMPL(IOInterruptDispatchSource
, SetEnableWithCompletion
)
727 if (enable
== ivars
->enable
) {
728 return kIOReturnSuccess
;
732 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
733 ivars
->enable
= enable
;
734 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
735 ret
= ivars
->provider
->enableInterrupt(ivars
->intIndex
);
737 ret
= ivars
->provider
->disableInterrupt(ivars
->intIndex
);
738 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
739 ivars
->enable
= enable
;
740 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
747 IMPL(IOInterruptDispatchSource
, Cancel
)
749 return kIOReturnUnsupported
;
753 IMPL(IOInterruptDispatchSource
, CheckForWork
)
755 IOReturn ret
= kIOReturnNotReady
;
757 wait_result_t waitResult
;
762 self
= current_thread();
765 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
766 if ((icount
= ivars
->count
)) {
769 waitResult
= THREAD_AWAKENED
;
770 } else if (synchronous
) {
771 assert(NULL
== ivars
->waiter
);
772 ivars
->waiter
= self
;
773 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
775 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
776 if (synchronous
&& (waitResult
== THREAD_WAITING
)) {
777 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
778 if (THREAD_INTERRUPTED
== waitResult
) {
782 } while (synchronous
&& !icount
);
784 if (icount
&& ivars
->action
) {
785 ret
= InterruptOccurred(rpc
, ivars
->action
, icount
, itime
);
792 IMPL(IOInterruptDispatchSource
, InterruptOccurred
)
796 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
799 kIOServiceNotificationTypeCount
= kIOServiceNotificationTypeLast
+ 1,
802 struct IOServiceNotificationDispatchSource_IVars
{
803 OSObject
* serverName
;
806 IONotifier
* notifier
;
807 OSDictionary
* interestNotifiers
;
808 OSArray
* pending
[kIOServiceNotificationTypeCount
];
813 IMPL(IOServiceNotificationDispatchSource
, Create
)
817 IOServiceNotificationDispatchSource
* inst
;
819 inst
= OSTypeAlloc(IOServiceNotificationDispatchSource
);
821 OSSafeReleaseNULL(inst
);
822 return kIOReturnNoMemory
;
825 us
= (typeof(us
))thread_iokit_tls_get(0);
826 assert(OSDynamicCast(IOUserServer
, us
));
828 OSSafeReleaseNULL(inst
);
829 return kIOReturnError
;
831 inst
->ivars
->serverName
= us
->copyProperty(gIOUserServerNameKey
);
832 if (!inst
->ivars
->serverName
) {
833 OSSafeReleaseNULL(inst
);
834 return kIOReturnNoMemory
;
837 inst
->ivars
->lock
= IOLockAlloc();
838 if (!inst
->ivars
->lock
) {
839 OSSafeReleaseNULL(inst
);
840 return kIOReturnNoMemory
;
842 for (uint32_t idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
843 inst
->ivars
->pending
[idx
] = OSArray::withCapacity(4);
844 if (!inst
->ivars
->pending
[idx
]) {
845 OSSafeReleaseNULL(inst
);
846 return kIOReturnNoMemory
;
849 inst
->ivars
->interestNotifiers
= OSDictionary::withCapacity(4);
850 if (!inst
->ivars
->interestNotifiers
) {
851 OSSafeReleaseNULL(inst
);
852 return kIOReturnNoMemory
;
855 inst
->ivars
->notifier
= IOService::addMatchingNotification(gIOMatchedNotification
, matching
, 0 /*priority*/,
856 ^bool (IOService
* newService
, IONotifier
* notifier
) {
857 bool notifyReady
= false;
858 IONotifier
* interest
;
859 OSObject
* serverName
;
862 serverName
= newService
->copyProperty(gIOUserServerNameKey
);
863 okToUse
= (serverName
&& inst
->ivars
->serverName
->isEqualTo(serverName
));
864 OSSafeReleaseNULL(serverName
);
869 IOLockLock(inst
->ivars
->lock
);
870 notifyReady
= (0 == inst
->ivars
->pending
[kIOServiceNotificationTypeMatched
]->getCount());
871 inst
->ivars
->pending
[kIOServiceNotificationTypeMatched
]->setObject(newService
);
872 IOLockUnlock(inst
->ivars
->lock
);
874 interest
= newService
->registerInterest(gIOGeneralInterest
,
875 ^IOReturn (uint32_t messageType
, IOService
* provider
,
876 void * messageArgument
, size_t argSize
) {
877 IONotifier
* interest
;
878 bool notifyReady
= false;
880 switch (messageType
) {
881 case kIOMessageServiceIsTerminated
:
882 IOLockLock(inst
->ivars
->lock
);
883 notifyReady
= (0 == inst
->ivars
->pending
[kIOServiceNotificationTypeTerminated
]->getCount());
884 inst
->ivars
->pending
[kIOServiceNotificationTypeTerminated
]->setObject(provider
);
885 interest
= (typeof(interest
))inst
->ivars
->interestNotifiers
->getObject((const OSSymbol
*) newService
);
888 inst
->ivars
->interestNotifiers
->removeObject((const OSSymbol
*) newService
);
889 IOLockUnlock(inst
->ivars
->lock
);
894 if (notifyReady
&& inst
->ivars
->action
) {
895 inst
->ServiceNotificationReady(inst
->ivars
->action
);
897 return kIOReturnSuccess
;
900 IOLockLock(inst
->ivars
->lock
);
901 inst
->ivars
->interestNotifiers
->setObject((const OSSymbol
*) newService
, interest
);
902 IOLockUnlock(inst
->ivars
->lock
);
905 if (inst
->ivars
->action
) {
906 inst
->ServiceNotificationReady(inst
->ivars
->action
);
912 if (!inst
->ivars
->notifier
) {
913 OSSafeReleaseNULL(inst
);
914 ret
= kIOReturnError
;
917 *notification
= inst
;
918 ret
= kIOReturnSuccess
;
924 IMPL(IOServiceNotificationDispatchSource
, CopyNextNotification
)
929 IOLockLock(ivars
->lock
);
930 for (idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
931 next
= (IOService
*) ivars
->pending
[idx
]->getObject(0);
934 ivars
->pending
[idx
]->removeObject(0);
938 IOLockUnlock(ivars
->lock
);
940 if (idx
== kIOServiceNotificationTypeCount
) {
941 idx
= kIOServiceNotificationTypeNone
;
947 return kIOReturnSuccess
;
951 IOServiceNotificationDispatchSource::init()
953 if (!super::init()) {
956 ivars
= IONewZero(IOServiceNotificationDispatchSource_IVars
, 1);
965 IOServiceNotificationDispatchSource::free()
968 OSSafeReleaseNULL(ivars
->serverName
);
969 if (ivars
->interestNotifiers
) {
970 ivars
->interestNotifiers
->iterateObjects(^bool (const OSSymbol
* key
, OSObject
* object
) {
971 IONotifier
* interest
= (typeof(interest
))object
;
975 OSSafeReleaseNULL(ivars
->interestNotifiers
);
977 for (uint32_t idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
978 OSSafeReleaseNULL(ivars
->pending
[idx
]);
981 IOLockFree(ivars
->lock
);
984 if (ivars
->notifier
) {
985 ivars
->notifier
->remove();
986 ivars
->notifier
= NULL
;
988 IOSafeDeleteNULL(ivars
, IOServiceNotificationDispatchSource_IVars
, 1);
995 IMPL(IOServiceNotificationDispatchSource
, SetHandler
)
1000 notifyReady
= false;
1002 IOLockLock(ivars
->lock
);
1003 OSSafeReleaseNULL(ivars
->action
);
1005 ivars
->action
= action
;
1007 for (uint32_t idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
1008 notifyReady
= (ivars
->pending
[idx
]->getCount());
1014 IOLockUnlock(ivars
->lock
);
1017 ServiceNotificationReady(action
);
1019 ret
= kIOReturnSuccess
;
1025 IMPL(IOServiceNotificationDispatchSource
, SetEnableWithCompletion
)
1027 if (enable
== ivars
->enable
) {
1028 return kIOReturnSuccess
;
1031 IOLockLock(ivars
->lock
);
1032 ivars
->enable
= enable
;
1033 IOLockUnlock(ivars
->lock
);
1035 return kIOReturnSuccess
;
1039 IMPL(IOServiceNotificationDispatchSource
, Cancel
)
1041 return kIOReturnUnsupported
;
1045 IMPL(IOServiceNotificationDispatchSource
, CheckForWork
)
1047 return kIOReturnNotReady
;
1051 IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block
)
1053 return kIOReturnUnsupported
;
1056 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1059 IOUserServer::waitInterruptTrap(void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
1061 IOReturn ret
= kIOReturnBadArgument
;
1062 IOInterruptState is
;
1063 IOInterruptDispatchSource
* interrupt
;
1064 IOInterruptDispatchSource_IVars
* ivars
;
1065 IOInterruptDispatchSourcePayload payload
;
1067 wait_result_t waitResult
;
1072 object
= iokit_lookup_object_with_port_name((mach_port_name_t
)(uintptr_t)p1
, IKOT_UEXT_OBJECT
, current_task());
1075 return kIOReturnBadArgument
;
1077 if (!(interrupt
= OSDynamicCast(IOInterruptDispatchSource
, object
))) {
1078 ret
= kIOReturnBadArgument
;
1080 self
= current_thread();
1081 ivars
= interrupt
->ivars
;
1084 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1085 if ((payload
.count
= ivars
->count
)) {
1086 payload
.time
= ivars
->time
;
1088 waitResult
= THREAD_AWAKENED
;
1090 assert(NULL
== ivars
->waiter
);
1091 ivars
->waiter
= self
;
1092 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
1094 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1095 if (waitResult
== THREAD_WAITING
) {
1096 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
1097 if (THREAD_INTERRUPTED
== waitResult
) {
1101 } while (!payload
.count
);
1102 ret
= (payload
.count
? kIOReturnSuccess
: kIOReturnAborted
);
1105 if (kIOReturnSuccess
== ret
) {
1106 int copyerr
= copyout(&payload
, (user_addr_t
) p2
, sizeof(payload
));
1108 ret
= kIOReturnVMError
;
1117 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1120 IMPL(IOUserServer
, Create
)
1124 const OSSymbol
* sym
;
1125 OSNumber
* serverTag
;
1128 us
= (typeof(us
))thread_iokit_tls_get(0);
1129 assert(OSDynamicCast(IOUserServer
, us
));
1130 if (kIODKLogSetup
& gIODKDebug
) {
1131 DKLOG(DKS
"::Create(" DKS
") %p\n", DKN(us
), name
, tag
, us
);
1134 return kIOReturnError
;
1137 sym
= OSSymbol::withCString(name
);
1138 serverTag
= OSNumber::withNumber(tag
, 64);
1140 us
->setProperty(gIOUserServerNameKey
, (OSObject
*) sym
);
1141 us
->setProperty(gIOUserServerTagKey
, serverTag
);
1143 serverTag
->release();
1144 OSSafeReleaseNULL(sym
);
1146 snprintf(rname
, sizeof(rname
), "IOUserServer(%s-0x%qx)", name
, tag
);
1151 ret
= kIOReturnSuccess
;
1157 IMPL(IOUserServer
, Exit
)
1159 return kIOReturnUnsupported
;
1163 IMPL(IOUserServer
, LoadModule
)
1165 return kIOReturnUnsupported
;
1169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1172 IMPL(IODispatchQueue
, Create
)
1174 IODispatchQueue
* result
;
1177 result
= OSTypeAlloc(IODispatchQueue
);
1179 return kIOReturnNoMemory
;
1181 if (!result
->init()) {
1182 return kIOReturnNoMemory
;
1187 if (!strcmp("Root", name
)) {
1188 us
= (typeof(us
))thread_iokit_tls_get(0);
1189 assert(OSDynamicCast(IOUserServer
, us
));
1190 us
->setRootQueue(result
);
1193 if (kIODKLogSetup
& gIODKDebug
) {
1194 DKLOG("IODispatchQueue::Create %s %p\n", name
, result
);
1197 return kIOReturnSuccess
;
1201 IMPL(IODispatchQueue
, SetPort
)
1203 if (MACH_PORT_NULL
!= ivars
->serverPort
) {
1204 return kIOReturnNotReady
;
1207 ivars
->serverPort
= port
;
1208 return kIOReturnSuccess
;
1212 IODispatchQueue::init()
1214 ivars
= IONewZero(IODispatchQueue_IVars
, 1);
1218 ivars
->queue
= this;
1224 IODispatchQueue::free()
1226 if (ivars
&& ivars
->serverPort
) {
1227 ipc_port_release_send(ivars
->serverPort
);
1228 ivars
->serverPort
= MACH_PORT_NULL
;
1230 IOSafeDeleteNULL(ivars
, IODispatchQueue_IVars
, 1);
1235 IODispatchQueue::OnQueue()
1240 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1244 OSMetaClassBase::Dispatch(IORPC rpc
)
1246 return kIOReturnUnsupported
;
1250 OSMetaClassBase::Invoke(IORPC rpc
)
1252 IOReturn ret
= kIOReturnUnsupported
;
1253 OSMetaClassBase
* object
;
1255 IOService
* service
;
1257 IORPCMessage
* message
;
1259 assert(rpc
.sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
1260 message
= IORPCMessageFromMach(rpc
.message
, false);
1262 return kIOReturnIPCError
;
1264 message
->flags
|= kIORPCMessageKernel
;
1267 if (!(kIORPCMessageLocalHost
& message
->flags
)) {
1268 us
= OSDynamicCast(IOUserServer
, this);
1270 if ((action
= OSDynamicCast(OSAction
, this))) {
1271 object
= IOUserServer::target(action
, message
);
1275 if ((service
= OSDynamicCast(IOService
, object
))
1276 && service
->reserved
->uvars
) {
1277 // xxx other classes
1278 us
= service
->reserved
->uvars
->userServer
;
1283 message
->flags
|= kIORPCMessageRemote
;
1285 if (kIOReturnSuccess
!= ret
) {
1286 if (kIODKLogIPC
& gIODKDebug
) {
1287 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret
);
1291 if (kIODKLogIPC
& gIODKDebug
) {
1292 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message
->msgid
);
1294 ret
= Dispatch(rpc
);
1300 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1305 const char strings
[0];
1309 OSUserMetaClass::Dispatch(IORPC rpc
)
1312 return const_cast<OSMetaClass
*>(meta
)->Dispatch(rpc
);
1314 return kIOReturnUnsupported
;
1319 OSUserMetaClass::free()
1322 IOFree(queueNames
, sizeof(IOPStrings
) + queueNames
->dataSize
* sizeof(char));
1326 IOFree(description
, description
->descriptionSize
);
1329 IOSafeDeleteNULL(methods
, uint64_t, 2 * methodCount
);
1331 meta
->releaseMetaClass();
1340 * Sets the loadTag of the associated OSKext
1342 * NOTE: different instances of the same OSKext
1343 * (so same BounleID but different tasks)
1344 * will have the same loadTag.
1347 IOUserServer::setTaskLoadTag(OSKext
*kext
)
1350 uint32_t loadTag
, prev_taskloadTag
;
1352 owningTask
= this->fOwningTask
;
1354 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1358 loadTag
= kext
->getLoadTag();
1359 prev_taskloadTag
= set_task_loadTag(owningTask
, loadTag
);
1360 if (prev_taskloadTag
) {
1361 printf("%s: found the task loadTag already set to %u (set to %u)\n",
1362 __FUNCTION__
, prev_taskloadTag
, loadTag
);
1367 * Sets the OSKext uuid as the uuid of the userspace
1371 IOUserServer::setDriverKitUUID(OSKext
*kext
)
1375 uuid_t p_uuid
, k_uuid
;
1376 OSData
*k_data_uuid
;
1378 uuid_string_t uuid_string
= "";
1380 task
= this->fOwningTask
;
1382 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1386 p
= (proc_t
)(get_bsdtask_info(task
));
1388 printf("%s: proc not found\n", __FUNCTION__
);
1391 proc_getexecutableuuid(p
, p_uuid
, sizeof(p_uuid
));
1393 k_data_uuid
= kext
->copyUUID();
1395 memcpy(&k_uuid
, k_data_uuid
->getBytesNoCopy(), sizeof(k_uuid
));
1396 OSSafeReleaseNULL(k_data_uuid
);
1397 if (uuid_compare(k_uuid
, p_uuid
) != 0) {
1398 printf("%s: uuid not matching\n", __FUNCTION__
);
1403 uuid_unparse(p_uuid
, uuid_string
);
1404 new_uuid
= OSData::withBytes(p_uuid
, sizeof(p_uuid
));
1405 kext
->setDriverKitUUID(new_uuid
);
1409 IOUserServer::serviceMatchesCDHash(IOService
*service
)
1411 OSObject
*obj
= NULL
;
1412 bool result
= false;
1413 OSString
*requiredCDHashStr
= NULL
;
1414 const char *requiredCDHash
= NULL
;
1415 char taskCDHash
[CS_CDHASH_LEN
];
1417 task_t owningTask
= this->fOwningTask
;
1419 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1423 obj
= service
->copyProperty(gIOUserServerCDHashKey
);
1424 requiredCDHashStr
= OSDynamicCast(OSString
, obj
);
1425 if (!requiredCDHashStr
) {
1426 printf("%s: required cdhash not found as property of personality\n", __FUNCTION__
);
1430 requiredCDHash
= requiredCDHashStr
->getCStringNoCopy();
1431 if (!requiredCDHash
) {
1432 printf("%s: required cdhash unable to be read as string\n", __FUNCTION__
);
1436 if (strlen(requiredCDHash
) != CS_CDHASH_LEN
* 2) {
1437 printf("%s: required cdhash string has incorrect length\n", __FUNCTION__
);
1441 get_task_cdhash(owningTask
, taskCDHash
);
1442 for (int i
= 0; i
< (int)CS_CDHASH_LEN
* 2; i
++) {
1443 uint8_t which
= (i
+ 1) & 0x1; /* 1 for upper nibble, 0 for lower */
1444 uint8_t nibble
= requiredCDHash
[i
];
1445 uint8_t byte
= taskCDHash
[i
/ 2];
1446 if ('0' <= nibble
&& nibble
<= '9') {
1448 } else if ('a' <= nibble
&& nibble
<= 'f') {
1450 } else if ('A' <= nibble
&& nibble
<= 'F') {
1453 printf("%s: required cdhash contains invalid token '%c'\n", __FUNCTION__
, nibble
);
1458 * Decide which half of the byte to compare
1460 if (nibble
!= (which
? (byte
>> 4) : (byte
& 0x0f))) {
1461 printf("%s: required cdhash %s in personality does not match service\n", __FUNCTION__
, requiredCDHash
);
1468 OSSafeReleaseNULL(obj
);
1473 IOUserServer::checkEntitlements(
1474 OSDictionary
* entitlements
, OSObject
* prop
,
1475 IOService
* provider
, IOService
* dext
)
1477 OSDictionary
* matching
;
1482 if (!entitlements
) {
1488 matching
= dext
->dictionaryWithProperties();
1494 bool allPresent __block
;
1495 prop
->iterateObjects(^bool (OSObject
* object
) {
1497 object
->iterateObjects(^bool (OSObject
* object
) {
1500 string
= OSDynamicCast(OSString
, object
);
1501 value
= entitlements
->getObject(string
);
1502 if (matching
&& value
) {
1503 matching
->setObject(string
, value
);
1505 allPresent
= (NULL
!= value
);
1511 if (allPresent
&& matching
&& provider
) {
1512 allPresent
= provider
->matchPropertyTable(matching
);
1515 OSSafeReleaseNULL(matching
);
1516 OSSafeReleaseNULL(prop
);
1522 IOUserServer::checkEntitlements(IOService
* provider
, IOService
* dext
)
1531 prop
= provider
->copyProperty(gIOServiceDEXTEntitlementsKey
);
1532 ok
= checkEntitlements(fEntitlements
, prop
, provider
, dext
);
1534 DKLOG(DKS
": provider entitlements check failed\n", DKN(dext
));
1537 prop
= dext
->copyProperty(gIOServiceDEXTEntitlementsKey
);
1538 ok
= checkEntitlements(fEntitlements
, prop
, NULL
, NULL
);
1540 DKLOG(DKS
": family entitlements check failed\n", DKN(dext
));
1548 IOUserServer::exit(const char * reason
)
1550 DKLOG("%s::exit(%s)\n", getName(), reason
);
1552 return kIOReturnSuccess
;
1556 IOUserServer::varsForObject(OSObject
* obj
)
1558 IOService
* service
;
1560 if ((service
= OSDynamicCast(IOService
, obj
))) {
1561 return service
->reserved
->uvars
;
1568 IOUserServer::copyInStringArray(const char * string
, uint32_t userSize
)
1576 if (userSize
<= 1) {
1580 if (os_add_overflow(sizeof(IOPStrings
), userSize
, &alloc
)) {
1584 if (alloc
> 16384) {
1588 array
= (typeof(array
))IOMalloc(alloc
);
1592 array
->dataSize
= userSize
;
1593 bcopy(string
, (void *) &array
->strings
[0], userSize
);
1596 cstr
= &array
->strings
[0];
1597 end
= &array
->strings
[array
->dataSize
];
1598 while ((len
= (unsigned char)cstr
[0])) {
1600 if ((cstr
+ len
) >= end
) {
1607 IOFree(array
, alloc
);
1615 IOUserServer::stringArrayIndex(IOPStrings
* array
, const char * look
)
1623 cstr
= &array
->strings
[0];
1624 end
= &array
->strings
[array
->dataSize
];
1625 llen
= strlen(look
);
1626 while ((len
= (unsigned char)cstr
[0])) {
1628 if ((cstr
+ len
) >= end
) {
1631 if ((len
== llen
) && !strncmp(cstr
, look
, len
)) {
1640 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
1643 IOUserServer::queueForObject(OSObject
* obj
, uint64_t msgid
)
1645 IODispatchQueue
* queue
;
1646 OSObjectUserVars
* uvars
;
1649 uvars
= varsForObject(obj
);
1653 if (!uvars
->queueArray
) {
1654 if (uvars
->stopped
) {
1655 return kIODispatchQueueStopped
;
1659 queue
= uvars
->queueArray
[0];
1662 && uvars
->userMeta
->methods
) {
1663 uint32_t idx
, baseIdx
;
1666 for (baseIdx
= 0, lim
= uvars
->userMeta
->methodCount
; lim
; lim
>>= 1) {
1667 idx
= baseIdx
+ (lim
>> 1);
1668 if (msgid
== uvars
->userMeta
->methods
[idx
]) {
1669 option
= uvars
->userMeta
->methods
[uvars
->userMeta
->methodCount
+ idx
];
1671 if (option
< uvars
->userMeta
->queueNames
->count
) {
1672 queue
= uvars
->queueArray
[option
+ 1];
1675 } else if (msgid
> uvars
->userMeta
->methods
[idx
]) {
1677 baseIdx
+= (lim
>> 1) + 1;
1687 IOUserServer::objectInstantiate(OSObject
* obj
, IORPC rpc
, IORPCMessage
* message
)
1692 IOService
* service
;
1696 uint32_t queueCount
, queueAlloc
;
1697 const char * resultClassName
;
1698 uint64_t resultFlags
;
1701 uint32_t methodCount
;
1702 const uint64_t * methods
;
1703 IODispatchQueue
* queue
;
1704 OSUserMetaClass
* userMeta
;
1705 OSObjectUserVars
* uvars
;
1707 ipc_port_t sendPort
;
1709 OSObject_Instantiate_Rpl_Content
* reply
;
1717 resultClassName
= NULL
;
1719 ret
= kIOReturnUnsupportedMode
;
1721 service
= OSDynamicCast(IOService
, obj
);
1723 // xxx other classes hosted
1724 resultFlags
|= kOSObjectRPCKernel
;
1725 resultFlags
|= kOSObjectRPCRemote
;
1727 if (service
->isInactive()) {
1728 DKLOG(DKS
"::instantiate inactive\n", DKN(service
));
1729 return kIOReturnOffline
;
1731 prop
= service
->copyProperty(gIOUserClassKey
);
1732 str
= OSDynamicCast(OSString
, prop
);
1733 if (!service
->reserved
->uvars
) {
1734 resultFlags
|= kOSObjectRPCRemote
;
1735 resultFlags
|= kOSObjectRPCKernel
;
1736 } else if (this != service
->reserved
->uvars
->userServer
) {
1737 // remote, use base class
1738 resultFlags
|= kOSObjectRPCRemote
;
1740 if (service
->reserved
->uvars
&& service
->reserved
->uvars
->userServer
) {
1741 IOLockLock(service
->reserved
->uvars
->userServer
->fLock
);
1742 userMeta
= (typeof(userMeta
))service
->reserved
->uvars
->userServer
->fClasses
->getObject(str
);
1743 IOLockUnlock(service
->reserved
->uvars
->userServer
->fLock
);
1746 if (!str
&& !userMeta
) {
1747 const OSMetaClass
* meta
;
1748 meta
= obj
->getMetaClass();
1750 while (meta
&& !userMeta
) {
1751 str
= (OSString
*) meta
->getClassNameSymbol();
1752 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
1754 meta
= meta
->getSuperClass();
1757 IOLockUnlock(fLock
);
1762 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
1763 IOLockUnlock(fLock
);
1765 if (kIODKLogSetup
& gIODKDebug
) {
1766 DKLOG("userMeta %s %p\n", str
->getCStringNoCopy(), userMeta
);
1769 if (kOSObjectRPCRemote
& resultFlags
) {
1770 while (userMeta
&& !(kOSClassCanRemote
& userMeta
->description
->flags
)) {
1771 userMeta
= userMeta
->superMeta
;
1774 resultClassName
= userMeta
->description
->name
;
1775 ret
= kIOReturnSuccess
;
1778 service
->reserved
->uvars
->userMeta
= userMeta
;
1780 if (userMeta
->queueNames
) {
1781 queueAlloc
+= userMeta
->queueNames
->count
;
1783 service
->reserved
->uvars
->queueArray
=
1784 IONewZero(IODispatchQueue
*, queueAlloc
);
1785 resultClassName
= str
->getCStringNoCopy();
1786 ret
= kIOReturnSuccess
;
1790 OSSafeReleaseNULL(prop
);
1792 IORPCMessageMach
* machReply
= rpc
.reply
;
1793 replySize
= sizeof(OSObject_Instantiate_Rpl
);
1795 if ((kIOReturnSuccess
== ret
) && (kOSObjectRPCRemote
& resultFlags
)) {
1797 if ((action
= OSDynamicCast(OSAction
, obj
))) {
1798 if (action
->ivars
->referenceSize
) {
1799 resultFlags
|= kOSObjectRPCKernel
;
1801 resultFlags
&= ~kOSObjectRPCKernel
;
1802 target
= action
->ivars
->target
;
1805 queue
= queueForObject(target
, action
->ivars
->targetmsgid
);
1808 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
1809 sendPort
= ipc_port_copy_send(queue
->ivars
->serverPort
);
1811 replySize
= sizeof(OSObject_Instantiate_Rpl
)
1812 + queueCount
* sizeof(machReply
->objects
[0])
1813 + 2 * methodCount
* sizeof(reply
->methods
[0]);
1814 if (replySize
> rpc
.replySize
) {
1816 return kIOReturnIPCError
;
1818 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
1819 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1820 machReply
->objects
[idx
].name
= sendPort
;
1821 machReply
->objects
[idx
].pad2
= 0;
1822 machReply
->objects
[idx
].pad_end
= 0;
1825 uvars
= varsForObject(target
);
1826 if (uvars
&& uvars
->userMeta
) {
1828 if (uvars
->userMeta
->queueNames
) {
1829 queueCount
+= uvars
->userMeta
->queueNames
->count
;
1831 methods
= &uvars
->userMeta
->methods
[0];
1832 methodCount
= uvars
->userMeta
->methodCount
;
1833 replySize
= sizeof(OSObject_Instantiate_Rpl
)
1834 + queueCount
* sizeof(machReply
->objects
[0])
1835 + 2 * methodCount
* sizeof(reply
->methods
[0]);
1836 if (replySize
> rpc
.replySize
) {
1838 return kIOReturnIPCError
;
1840 for (idx
= 0; idx
< queueCount
; idx
++) {
1841 queue
= uvars
->queueArray
[idx
];
1844 sendPort
= ipc_port_copy_send(queue
->ivars
->serverPort
);
1846 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
1847 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1848 machReply
->objects
[idx
].name
= sendPort
;
1849 machReply
->objects
[idx
].pad2
= 0;
1850 machReply
->objects
[idx
].pad_end
= 0;
1856 if (kIODKLogIPC
& gIODKDebug
) {
1857 DKLOG("instantiate %s\n", obj
->getMetaClass()->getClassName());
1860 if (kIOReturnSuccess
!= ret
) {
1861 DKLOG("%s: no user class found\n", str
? str
->getCStringNoCopy() : obj
->getMetaClass()->getClassName());
1862 resultClassName
= "unknown";
1865 machReply
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
1866 machReply
->msgh
.msgh_size
= replySize
;
1867 machReply
->msgh_body
.msgh_descriptor_count
= queueCount
;
1869 reply
= (typeof(reply
))IORPCMessageFromMach(machReply
, true);
1871 return kIOReturnIPCError
;
1874 bcopy(methods
, &reply
->methods
[0], methodCount
* 2 * sizeof(reply
->methods
[0]));
1876 reply
->__hdr
.msgid
= OSObject_Instantiate_ID
;
1877 reply
->__hdr
.flags
= kIORPCMessageOneway
;
1878 reply
->__hdr
.objectRefs
= 0;
1880 reply
->flags
= resultFlags
;
1881 strlcpy(reply
->classname
, resultClassName
, sizeof(reply
->classname
));
1882 reply
->__result
= ret
;
1884 ret
= kIOReturnSuccess
;
1889 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1892 IOUserServer::kernelDispatch(OSObject
* obj
, IORPC rpc
)
1895 IORPCMessage
* message
;
1897 message
= IORPCMessageFromMach(rpc
.message
, false);
1899 return kIOReturnIPCError
;
1902 if (OSObject_Instantiate_ID
== message
->msgid
) {
1903 ret
= objectInstantiate(obj
, rpc
, message
);
1904 if (kIOReturnSuccess
!= ret
) {
1905 DKLOG("%s: instantiate failed 0x%x\n", obj
->getMetaClass()->getClassName(), ret
);
1908 if (kIODKLogIPC
& gIODKDebug
) {
1909 DKLOG("%s::Dispatch kernel 0x%qx\n", obj
->getMetaClass()->getClassName(), message
->msgid
);
1911 ret
= obj
->Dispatch(rpc
);
1912 if (kIODKLogIPC
& gIODKDebug
) {
1913 DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj
->getMetaClass()->getClassName(), message
->msgid
, ret
);
1921 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1924 IOUserServer::target(OSAction
* action
, IORPCMessage
* message
)
1928 if (message
->msgid
!= action
->ivars
->msgid
) {
1931 object
= action
->ivars
->target
;
1932 message
->msgid
= action
->ivars
->targetmsgid
;
1933 message
->objects
[0] = (OSObjectRef
) object
;
1934 if (kIORPCMessageRemote
& message
->flags
) {
1938 if (kIODKLogIPC
& gIODKDebug
) {
1939 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
, action
->ivars
->msgid
);
1945 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1948 uext_server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
1951 IORPCMessageMach
* msgin
;
1953 IOUserServer
* server
;
1955 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
1957 object
= IOUserServer::copyObjectForSendRight(msgin
->msgh
.msgh_remote_port
, IKOT_UEXT_OBJECT
);
1958 server
= OSDynamicCast(IOUserServer
, object
);
1960 OSSafeReleaseNULL(object
);
1961 return KERN_INVALID_NAME
;
1963 ret
= server
->server(requestkmsg
, pReply
);
1969 #define MAX_UEXT_REPLY_SIZE 0x17c0
1972 IOUserServer::server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
1975 mach_msg_size_t replyAlloc
;
1976 ipc_kmsg_t replykmsg
;
1977 IORPCMessageMach
* msgin
;
1978 IORPCMessage
* message
;
1979 IORPCMessageMach
* msgout
;
1980 IORPCMessage
* reply
;
1987 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
1992 if (msgin
->msgh
.msgh_size
< (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
1993 if (kIODKLogIPC
& gIODKDebug
) {
1994 DKLOG("UEXT notify %o\n", msgin
->msgh
.msgh_id
);
1996 return KERN_NOT_SUPPORTED
;
1999 if (!(MACH_MSGH_BITS_COMPLEX
& msgin
->msgh
.msgh_bits
)) {
2000 msgin
->msgh_body
.msgh_descriptor_count
= 0;
2002 message
= IORPCMessageFromMach(msgin
, false);
2004 return kIOReturnIPCError
;
2006 if (message
->objectRefs
== 0) {
2007 return kIOReturnIPCError
;
2009 ret
= copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, true, false);
2010 if (kIOReturnSuccess
!= ret
) {
2011 if (kIODKLogIPC
& gIODKDebug
) {
2012 DKLOG("UEXT copyin(0x%x) %x\n", ret
, msgin
->msgh
.msgh_id
);
2014 return KERN_NOT_SUPPORTED
;
2017 if (msgin
->msgh_body
.msgh_descriptor_count
< 1) {
2018 return KERN_NOT_SUPPORTED
;
2020 object
= (OSObject
*) message
->objects
[0];
2021 msgid
= message
->msgid
;
2022 message
->flags
&= ~kIORPCMessageKernel
;
2023 message
->flags
|= kIORPCMessageRemote
;
2025 if ((action
= OSDynamicCast(OSAction
, object
))) {
2026 object
= target(action
, message
);
2027 msgid
= message
->msgid
;
2030 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
2031 assert(oneway
|| (MACH_PORT_NULL
!= msgin
->msgh
.msgh_local_port
));
2033 // includes trailer size
2034 replyAlloc
= oneway
? 0 : MAX_UEXT_REPLY_SIZE
;
2036 replykmsg
= ipc_kmsg_alloc(replyAlloc
);
2037 if (replykmsg
== NULL
) {
2038 // printf("uext_server: dropping request\n");
2039 // ipc_kmsg_trace_send(request, option);
2040 consumeObjects(message
, msgin
->msgh
.msgh_size
);
2041 ipc_kmsg_destroy(requestkmsg
);
2042 return KERN_MEMORY_FAILURE
;
2045 msgout
= (typeof(msgout
))ipc_kmsg_msg_header(replykmsg
);
2047 * MIG should really assure no data leakage -
2048 * but until it does, pessimistically zero the
2049 * whole reply buffer.
2051 bzero((void *)msgout
, replyAlloc
);
2054 IORPC rpc
= { .message
= msgin
, .reply
= msgout
, .sendSize
= msgin
->msgh
.msgh_size
, .replySize
= replyAlloc
};
2057 thread_iokit_tls_set(0, this);
2058 ret
= kernelDispatch(object
, rpc
);
2059 thread_iokit_tls_set(0, NULL
);
2061 ret
= kIOReturnBadArgument
;
2065 consumeObjects(message
, msgin
->msgh
.msgh_size
);
2068 copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, false, true);
2071 if (kIOReturnSuccess
== ret
) {
2072 replySize
= msgout
->msgh
.msgh_size
;
2073 reply
= IORPCMessageFromMach(msgout
, true);
2075 ret
= kIOReturnIPCError
;
2077 ret
= copyOutObjects(msgout
, reply
, replySize
, (kIORPCVersionCurrentReply
== msgout
->msgh
.msgh_id
) /* =>!InvokeReply */);
2080 if (kIOReturnSuccess
!= ret
) {
2081 IORPCMessageErrorReturnContent
* errorMsg
;
2083 msgout
->msgh_body
.msgh_descriptor_count
= 0;
2084 msgout
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
2085 errorMsg
= (typeof(errorMsg
))IORPCMessageFromMach(msgout
, true);
2086 errorMsg
->hdr
.msgid
= message
->msgid
;
2087 errorMsg
->hdr
.flags
= kIORPCMessageOneway
| kIORPCMessageError
;
2088 errorMsg
->hdr
.objectRefs
= 0;
2089 errorMsg
->result
= ret
;
2091 replySize
= sizeof(IORPCMessageErrorReturn
);
2094 msgout
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
2095 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin
->msgh
.msgh_bits
) /*remote*/, 0 /*local*/, 0, 0);
2097 msgout
->msgh
.msgh_remote_port
= msgin
->msgh
.msgh_local_port
;
2098 msgout
->msgh
.msgh_local_port
= MACH_PORT_NULL
;
2099 msgout
->msgh
.msgh_voucher_port
= (mach_port_name_t
) 0;
2100 msgout
->msgh
.msgh_reserved
= 0;
2101 msgout
->msgh
.msgh_size
= replySize
;
2104 *pReply
= replykmsg
;
2106 return oneway
? MIG_NO_REPLY
: KERN_SUCCESS
;
2109 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2111 #define MAX_OBJECT_COUNT(mach, size, message) \
2112 ((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))
2115 IOUserServerUEXTTrap(OSObject
* object
, void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
2117 const user_addr_t msg
= (uintptr_t) p1
;
2118 size_t inSize
= (uintptr_t) p2
;
2119 user_addr_t out
= (uintptr_t) p3
;
2120 size_t outSize
= (uintptr_t) p4
;
2121 mach_port_name_t objectName1
= (uintptr_t) p5
;
2123 OSObject
* objectArg1
;
2125 IORPCMessageMach
* mach
;
2126 mach_msg_port_descriptor_t
* descs
;
2131 IORPCMessageMach mach
;
2132 mach_msg_port_descriptor_t objects
[2];
2133 IOTrapMessageBuffer buffer
;
2140 IORPCMessage
* message
;
2141 IORPCMessage
* reply
;
2144 uint32_t maxObjectCount
;
2146 uint64_t * replyHdr
;
2149 bzero(&buffer
, sizeof(buffer
));
2151 p
= (typeof(p
)) & buffer
.buffer
[0];
2152 if (os_add_overflow(inSize
, outSize
, &totalSize
)) {
2153 return kIOReturnMessageTooLarge
;
2155 if (totalSize
> sizeof(buffer
.buffer
)) {
2156 return kIOReturnMessageTooLarge
;
2158 if (inSize
< sizeof(IORPCMessage
)) {
2159 return kIOReturnIPCError
;
2161 copyerr
= copyin(msg
, &buffer
.buffer
[0], inSize
);
2163 return kIOReturnVMError
;
2166 message
= (typeof(message
))p
;
2167 refs
= message
->objectRefs
;
2168 if ((refs
> 2) || !refs
) {
2169 return kIOReturnUnsupported
;
2171 if (!(kIORPCMessageSimpleReply
& message
->flags
)) {
2172 return kIOReturnUnsupported
;
2175 descs
= (typeof(descs
))(p
- refs
* sizeof(*descs
));
2176 mach
= (typeof(mach
))(p
- refs
* sizeof(*descs
) - sizeof(*mach
));
2178 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
2179 mach
->msgh
.msgh_size
= sizeof(IORPCMessageMach
) + refs
* sizeof(*descs
) + inSize
;
2180 mach
->msgh_body
.msgh_descriptor_count
= refs
;
2183 rpc
.sendSize
= mach
->msgh
.msgh_size
;
2184 rpc
.reply
= (IORPCMessageMach
*) (p
+ inSize
);
2185 rpc
.replySize
= sizeof(buffer
.buffer
) - inSize
;
2187 message
->objects
[0] = 0;
2188 if ((action
= OSDynamicCast(OSAction
, object
))) {
2189 maxObjectCount
= MAX_OBJECT_COUNT(rpc
.message
, rpc
.sendSize
, message
);
2190 if (refs
> maxObjectCount
) {
2191 return kIOReturnBadArgument
;
2193 object
= IOUserServer::target(action
, message
);
2194 message
->objects
[1] = (OSObjectRef
) action
;
2195 if (kIODKLogIPC
& gIODKDebug
) {
2196 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
2198 ret
= object
->Dispatch(rpc
);
2202 objectArg1
= iokit_lookup_uext_ref_current_task(objectName1
);
2204 return kIOReturnIPCError
;
2206 message
->objects
[1] = (OSObjectRef
) objectArg1
;
2208 if (kIODKLogIPC
& gIODKDebug
) {
2209 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
2211 ret
= object
->Dispatch(rpc
);
2212 if (kIODKLogIPC
& gIODKDebug
) {
2213 DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object
->getMetaClass()->getClassName(), message
->msgid
, ret
);
2215 OSSafeReleaseNULL(objectArg1
);
2217 if (kIOReturnSuccess
== ret
) {
2218 if (rpc
.reply
->msgh_body
.msgh_descriptor_count
) {
2219 return kIOReturnIPCError
;
2221 reply
= IORPCMessageFromMach(rpc
.reply
, rpc
.reply
->msgh
.msgh_size
);
2223 return kIOReturnIPCError
;
2225 copySize
= rpc
.reply
->msgh
.msgh_size
- (((uintptr_t) reply
) - ((uintptr_t) rpc
.reply
)) + sizeof(uint64_t);
2226 if (copySize
> outSize
) {
2227 return kIOReturnIPCError
;
2229 replyHdr
= (uint64_t *) reply
;
2231 replyHdr
[0] = copySize
;
2232 copyerr
= copyout(replyHdr
, out
, copySize
);
2234 return kIOReturnVMError
;
2242 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2245 IOUserServer::rpc(IORPC rpc
)
2247 if (isInactive() && !fRootQueue
) {
2248 return kIOReturnOffline
;
2252 IORPCMessage
* message
;
2253 IORPCMessageMach
* mach
;
2254 mach_msg_id_t machid
;
2255 uint32_t sendSize
, replySize
;
2258 IODispatchQueue
* queue
;
2259 IOService
* service
;
2261 ipc_port_t sendPort
;
2268 sendSize
= rpc
.sendSize
;
2269 replySize
= rpc
.replySize
;
2271 assert(sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
2273 message
= IORPCMessageFromMach(mach
, false);
2275 ret
= kIOReturnIPCError
;
2277 msgid
= message
->msgid
;
2278 machid
= (msgid
>> 32);
2280 if (mach
->msgh_body
.msgh_descriptor_count
< 1) {
2281 return kIOReturnNoMedia
;
2284 IOLockLock(gIOUserServerLock
);
2285 if ((service
= OSDynamicCast(IOService
, (OSObject
*) message
->objects
[0]))) {
2286 queue
= queueForObject(service
, msgid
);
2291 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
2292 port
= queue
->ivars
->serverPort
;
2295 sendPort
= ipc_port_copy_send(port
);
2297 IOLockUnlock(gIOUserServerLock
);
2299 return kIOReturnNotReady
;
2302 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
2304 ret
= copyOutObjects(mach
, message
, sendSize
, false);
2306 mach
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
2307 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, (oneway
? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE
));
2308 mach
->msgh
.msgh_remote_port
= sendPort
;
2309 mach
->msgh
.msgh_local_port
= (oneway
? MACH_PORT_NULL
: mig_get_reply_port());
2310 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
2311 mach
->msgh
.msgh_reserved
= 0;
2313 boolean_t message_moved
;
2316 ret
= kernel_mach_msg_send(&mach
->msgh
, sendSize
,
2317 MACH_SEND_MSG
| MACH_SEND_ALWAYS
| MACH_SEND_NOIMPORTANCE
,
2320 assert(replySize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
2321 ret
= kernel_mach_msg_rpc(&mach
->msgh
, sendSize
, replySize
, FALSE
, &message_moved
);
2324 ipc_port_release_send(sendPort
);
2326 if (MACH_MSG_SUCCESS
!= ret
) {
2327 if (kIODKLogIPC
& gIODKDebug
) {
2328 DKLOG("mach_msg() failed 0x%x\n", ret
);
2330 if (!message_moved
) {
2332 copyInObjects(mach
, message
, sendSize
, false, true);
2336 if ((KERN_SUCCESS
== ret
) && !oneway
) {
2337 if (kIORPCVersionCurrentReply
!= mach
->msgh
.msgh_id
) {
2338 ret
= (MACH_NOTIFY_SEND_ONCE
== mach
->msgh
.msgh_id
) ? MIG_SERVER_DIED
: MIG_REPLY_MISMATCH
;
2339 } else if ((replySize
= mach
->msgh
.msgh_size
) < (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
2340 // printf("BAD REPLY SIZE\n");
2341 ret
= MIG_BAD_ARGUMENTS
;
2343 if (!(MACH_MSGH_BITS_COMPLEX
& mach
->msgh
.msgh_bits
)) {
2344 mach
->msgh_body
.msgh_descriptor_count
= 0;
2346 message
= IORPCMessageFromMach(mach
, true);
2348 ret
= kIOReturnIPCError
;
2349 } else if (message
->msgid
!= msgid
) {
2350 // printf("BAD REPLY ID\n");
2351 ret
= MIG_BAD_ARGUMENTS
;
2353 bool isError
= (0 != (kIORPCMessageError
& message
->flags
));
2354 ret
= copyInObjects(mach
, message
, replySize
, !isError
, true);
2355 if (kIOReturnSuccess
!= ret
) {
2356 if (kIODKLogIPC
& gIODKDebug
) {
2357 DKLOG("rpc copyin(0x%x) %x\n", ret
, mach
->msgh
.msgh_id
);
2359 return KERN_NOT_SUPPORTED
;
2362 IORPCMessageErrorReturnContent
* errorMsg
= (typeof(errorMsg
))message
;
2363 ret
= errorMsg
->result
;
2372 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2375 IORPCMessageFromMach(IORPCMessageMach
* msg
, bool reply
)
2377 mach_msg_size_t idx
, count
;
2378 mach_msg_port_descriptor_t
* desc
;
2379 mach_msg_port_descriptor_t
* maxDesc
;
2380 size_t size
, msgsize
;
2383 msgsize
= msg
->msgh
.msgh_size
;
2384 count
= msg
->msgh_body
.msgh_descriptor_count
;
2385 desc
= &msg
->objects
[0];
2386 maxDesc
= (typeof(maxDesc
))(((uintptr_t) msg
) + msgsize
);
2387 upgrade
= (msg
->msgh
.msgh_id
!= (reply
? kIORPCVersionCurrentReply
: kIORPCVersionCurrent
));
2390 OSReportWithBacktrace("obsolete message");
2394 for (idx
= 0; idx
< count
; idx
++) {
2395 if (desc
>= maxDesc
) {
2398 switch (desc
->type
) {
2399 case MACH_MSG_PORT_DESCRIPTOR
:
2400 size
= sizeof(mach_msg_port_descriptor_t
);
2402 case MACH_MSG_OOL_DESCRIPTOR
:
2403 size
= sizeof(mach_msg_ool_descriptor_t
);
2408 desc
= (typeof(desc
))(((uintptr_t) desc
) + size
);
2410 return (IORPCMessage
*)(uintptr_t) desc
;
2414 IOUserServer::copySendRightForObject(OSObject
* object
, ipc_kobject_type_t type
)
2417 ipc_port_t sendPort
= NULL
;
2419 port
= iokit_port_for_object(object
, type
);
2421 sendPort
= ipc_port_make_send(port
);
2422 iokit_release_port(port
);
2429 IOUserServer::copyObjectForSendRight(ipc_port_t port
, ipc_kobject_type_t type
)
2432 object
= iokit_lookup_io_object(port
, type
);
2436 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2438 // Create a vm_map_copy_t or kalloc'ed data for memory
2439 // to be copied out. ipc will free after the copyout.
2441 static kern_return_t
2442 copyoutkdata(const void * data
, vm_size_t len
, void ** buf
)
2447 err
= vm_map_copyin( kernel_map
, CAST_USER_ADDR_T(data
), len
,
2448 false /* src_destroy */, ©
);
2450 assert( err
== KERN_SUCCESS
);
2451 if (err
== KERN_SUCCESS
) {
2452 *buf
= (char *) copy
;
2458 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2461 IOUserServer::copyOutObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
2462 size_t size
, bool consume
)
2465 uint32_t idx
, maxObjectCount
;
2469 mach_msg_port_descriptor_t
* desc
;
2470 mach_msg_ool_descriptor_t
* ool
;
2473 mach_msg_size_t length
;
2477 refs
= message
->objectRefs
;
2478 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
2479 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2480 // assert(refs <= maxObjectCount);
2481 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
2482 return kIOReturnBadArgument
;
2484 if (refs
> maxObjectCount
) {
2485 return kIOReturnBadArgument
;
2488 desc
= &mach
->objects
[0];
2489 for (idx
= 0; idx
< refs
; idx
++) {
2490 object
= (OSObject
*) message
->objects
[idx
];
2492 switch (desc
->type
) {
2493 case MACH_MSG_PORT_DESCRIPTOR
:
2494 descsize
= sizeof(mach_msg_port_descriptor_t
);
2497 port
= copySendRightForObject(object
, IKOT_UEXT_OBJECT
);
2504 message
->objects
[idx
] = 0;
2506 // desc->type = MACH_MSG_PORT_DESCRIPTOR;
2507 desc
->disposition
= MACH_MSG_TYPE_MOVE_SEND
;
2513 case MACH_MSG_OOL_DESCRIPTOR
:
2514 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2519 s
= OSSerialize::binaryWithCapacity(4096);
2524 s
->setIndexed(true);
2525 if (!object
->serialize(s
)) {
2531 length
= s
->getLength();
2532 kr
= copyoutkdata(s
->text(), length
, &address
);
2534 if (KERN_SUCCESS
!= kr
) {
2542 message
->objects
[idx
] = 0;
2544 ool
= (typeof(ool
))desc
;
2545 // ool->type = MACH_MSG_OOL_DESCRIPTOR;
2546 ool
->deallocate
= false;
2547 ool
->copy
= MACH_MSG_PHYSICAL_COPY
;
2549 ool
->address
= address
;
2556 if (-1UL == descsize
) {
2559 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2563 return kIOReturnSuccess
;
2566 desc
= &mach
->objects
[0];
2568 switch (desc
->type
) {
2569 case MACH_MSG_PORT_DESCRIPTOR
:
2570 descsize
= sizeof(mach_msg_port_descriptor_t
);
2573 ipc_port_release_send(port
);
2577 case MACH_MSG_OOL_DESCRIPTOR
:
2578 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2579 ool
= (typeof(ool
))desc
;
2580 copy
= (vm_map_copy_t
) ool
->address
;
2582 vm_map_copy_discard(copy
);
2590 if (-1UL == descsize
) {
2593 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2596 return kIOReturnBadArgument
;
2600 IOUserServer::copyInObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
2601 size_t size
, bool copyObjects
, bool consumePorts
)
2604 uint32_t idx
, maxObjectCount
;
2608 mach_msg_port_descriptor_t
* desc
;
2609 mach_msg_ool_descriptor_t
* ool
;
2610 vm_map_address_t copyoutdata
;
2613 refs
= message
->objectRefs
;
2614 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
2615 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2616 // assert(refs <= maxObjectCount);
2617 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
2618 return kIOReturnBadArgument
;
2620 if (refs
> maxObjectCount
) {
2621 return kIOReturnBadArgument
;
2624 desc
= &mach
->objects
[0];
2625 for (idx
= 0; idx
< refs
; idx
++) {
2626 switch (desc
->type
) {
2627 case MACH_MSG_PORT_DESCRIPTOR
:
2628 descsize
= sizeof(mach_msg_port_descriptor_t
);
2634 object
= copyObjectForSendRight(port
, IKOT_UEXT_OBJECT
);
2641 ipc_port_release_send(port
);
2646 case MACH_MSG_OOL_DESCRIPTOR
:
2647 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2648 ool
= (typeof(ool
))desc
;
2651 if (copyObjects
&& ool
->size
&& ool
->address
) {
2652 kr
= vm_map_copyout(kernel_map
, ©outdata
, (vm_map_copy_t
) ool
->address
);
2653 if (KERN_SUCCESS
== kr
) {
2654 object
= OSUnserializeXML((const char *) copyoutdata
, ool
->size
);
2655 // vm_map_copyout() has consumed the vm_map_copy_t in the message
2657 ool
->address
= NULL
;
2658 kr
= vm_deallocate(kernel_map
, copyoutdata
, ool
->size
);
2659 assert(KERN_SUCCESS
== kr
);
2672 if (-1UL == descsize
) {
2676 message
->objects
[idx
] = (OSObjectRef
) object
;
2678 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2682 return kIOReturnSuccess
;
2686 object
= (OSObject
*) message
->objects
[idx
];
2688 message
->objects
[idx
] = 0;
2691 return kIOReturnBadArgument
;
2695 IOUserServer::consumeObjects(IORPCMessage
* message
, size_t messageSize
)
2700 refs
= message
->objectRefs
;
2701 for (idx
= 0; idx
< refs
; idx
++) {
2702 object
= (OSObject
*) message
->objects
[idx
];
2705 message
->objects
[idx
] = 0;
2709 return kIOReturnSuccess
;
2712 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2715 IOUserServer::finalize(IOOptionBits options
)
2719 if (kIODKLogSetup
& gIODKDebug
) {
2720 DKLOG("%s::finalize(%p)\n", getName(), this);
2723 IOLockLock(gIOUserServerLock
);
2724 OSSafeReleaseNULL(fRootQueue
);
2725 IOLockUnlock(gIOUserServerLock
);
2730 services
= OSArray::withArray(fServices
);
2732 IOLockUnlock(fLock
);
2735 services
->iterateObjects(^bool (OSObject
* obj
) {
2736 IOService
* service
;
2737 IOService
* provider
;
2738 bool started
= false;
2740 service
= (IOService
*) obj
;
2741 if (kIODKLogSetup
& gIODKDebug
) {
2742 DKLOG("%s::terminate(" DKS
")\n", getName(), DKN(service
));
2744 if (service
->reserved
->uvars
) {
2745 started
= service
->reserved
->uvars
->started
;
2746 service
->reserved
->uvars
->serverDied
= true;
2748 provider
= service
->getProvider();
2749 serviceDidStop(service
, provider
);
2750 service
->terminate(kIOServiceTerminateNeedWillTerminate
| kIOServiceTerminateWithRematch
);
2754 DKLOG("%s::terminate(" DKS
") server exit before start()\n", getName(), DKN(service
));
2755 serviceStop(service
, NULL
);
2759 services
->release();
2762 return IOUserClient::finalize(options
);
2765 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2768 #define super IOUserClient
2770 OSDefineMetaClassAndStructors(IOUserServer
, IOUserClient
)
2772 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2774 IOUserClient
* IOUserServer::withTask(task_t owningTask
)
2776 IOUserServer
* inst
;
2778 inst
= new IOUserServer
;
2779 if (inst
&& !inst
->init()) {
2786 inst
->fOwningTask
= current_task();
2787 inst
->fEntitlements
= IOUserClient::copyClientEntitlements(inst
->fOwningTask
);
2789 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
2790 if (!inst
->fEntitlements
|| !inst
->fEntitlements
->getObject(gIODriverKitEntitlementKey
)) {
2794 p
= (proc_t
)get_bsdtask_info(inst
->fOwningTask
);
2797 IOLog(kIODriverKitEntitlementKey
" entitlement check failed for %s[%d]\n", proc_best_name(p
), pid
);
2805 /* Mark the current task's space as eligible for uext object ports */
2806 iokit_label_dext_task(inst
->fOwningTask
);
2808 inst
->fLock
= IOLockAlloc();
2809 inst
->fServices
= OSArray::withCapacity(4);
2810 inst
->fClasses
= OSDictionary::withCapacity(16);
2811 inst
->fClasses
->setOptions(OSCollection::kSort
, OSCollection::kSort
);
2817 IOUserServer::clientClose(void)
2820 return kIOReturnSuccess
;
2824 IOUserServer::setProperties(OSObject
* properties
)
2826 IOReturn kr
= kIOReturnUnsupported
;
2831 IOUserServer::stop(IOService
* provider
)
2833 fOwningTask
= TASK_NULL
;
2837 IOServicePH::serverRemove(this);
2839 OSSafeReleaseNULL(fRootQueue
);
2841 if (fInterruptLock
) {
2842 IOSimpleLockFree(fInterruptLock
);
2847 IOUserServer::free()
2849 OSSafeReleaseNULL(fEntitlements
);
2850 OSSafeReleaseNULL(fClasses
);
2854 OSSafeReleaseNULL(fServices
);
2855 IOUserClient::free();
2859 IOUserServer::registerClass(OSClassDescription
* desc
, uint32_t size
, OSUserMetaClass
** pCls
)
2861 OSUserMetaClass
* cls
;
2862 const OSSymbol
* sym
;
2863 uint64_t * methodOptions
;
2864 const char * queueNames
;
2865 uint32_t methodOptionsEnd
, queueNamesEnd
;
2866 IOReturn ret
= kIOReturnSuccess
;
2868 if (size
< sizeof(OSClassDescription
)) {
2870 return kIOReturnBadArgument
;
2873 if (kIODKLogSetup
& gIODKDebug
) {
2874 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc
->name
, desc
->queueNamesSize
, desc
->methodNamesSize
);
2877 if (desc
->descriptionSize
!= size
) {
2879 return kIOReturnBadArgument
;
2881 if (os_add_overflow(desc
->queueNamesOffset
, desc
->queueNamesSize
, &queueNamesEnd
)) {
2883 return kIOReturnBadArgument
;
2885 if (queueNamesEnd
> size
) {
2887 return kIOReturnBadArgument
;
2889 if (os_add_overflow(desc
->methodOptionsOffset
, desc
->methodOptionsSize
, &methodOptionsEnd
)) {
2891 return kIOReturnBadArgument
;
2893 if (methodOptionsEnd
> size
) {
2895 return kIOReturnBadArgument
;
2898 if ((desc
->queueNamesOffset
>= desc
->methodOptionsOffset
) && (desc
->queueNamesOffset
< methodOptionsEnd
)) {
2900 return kIOReturnBadArgument
;
2902 if ((queueNamesEnd
>= desc
->methodOptionsOffset
) && (queueNamesEnd
< methodOptionsEnd
)) {
2904 return kIOReturnBadArgument
;
2907 if (desc
->methodOptionsSize
& ((2 * sizeof(uint64_t)) - 1)) {
2909 return kIOReturnBadArgument
;
2911 if (sizeof(desc
->name
) == strnlen(desc
->name
, sizeof(desc
->name
))) {
2913 return kIOReturnBadArgument
;
2915 if (sizeof(desc
->superName
) == strnlen(desc
->superName
, sizeof(desc
->superName
))) {
2917 return kIOReturnBadArgument
;
2920 cls
= OSTypeAlloc(OSUserMetaClass
);
2923 return kIOReturnNoMemory
;
2926 cls
->description
= (typeof(cls
->description
))IOMalloc(size
);
2927 assert(cls
->description
);
2928 if (!cls
->description
) {
2931 return kIOReturnNoMemory
;
2933 bcopy(desc
, cls
->description
, size
);
2935 cls
->methodCount
= desc
->methodOptionsSize
/ (2 * sizeof(uint64_t));
2936 cls
->methods
= IONew(uint64_t, 2 * cls
->methodCount
);
2937 if (!cls
->methods
) {
2940 return kIOReturnNoMemory
;
2943 methodOptions
= (typeof(methodOptions
))(((uintptr_t) desc
) + desc
->methodOptionsOffset
);
2944 bcopy(methodOptions
, cls
->methods
, 2 * cls
->methodCount
* sizeof(uint64_t));
2946 queueNames
= (typeof(queueNames
))(((uintptr_t) desc
) + desc
->queueNamesOffset
);
2947 cls
->queueNames
= copyInStringArray(queueNames
, desc
->queueNamesSize
);
2949 sym
= OSSymbol::withCString(desc
->name
);
2954 return kIOReturnNoMemory
;
2958 cls
->meta
= OSMetaClass::copyMetaClassWithName(sym
);
2960 cls
->superMeta
= OSDynamicCast(OSUserMetaClass
, fClasses
->getObject(desc
->superName
));
2961 if (fClasses
->getObject(sym
) != NULL
) {
2962 /* class with this name exists */
2963 ret
= kIOReturnBadArgument
;
2965 if (fClasses
->setObject(sym
, cls
)) {
2968 /* could not add class to fClasses */
2969 ret
= kIOReturnNoMemory
;
2972 IOLockUnlock(fLock
);
2978 IOUserServer::setRootQueue(IODispatchQueue
* queue
)
2980 assert(!fRootQueue
);
2982 return kIOReturnStillOpen
;
2987 return kIOReturnSuccess
;
2991 IOUserServer::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
2992 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
2994 IOReturn ret
= kIOReturnBadArgument
;
2995 mach_port_name_t portname
;
2998 case kIOUserServerMethodRegisterClass
:
3000 OSUserMetaClass
* cls
;
3001 if (!args
->structureInputSize
) {
3002 return kIOReturnBadArgument
;
3004 if (args
->scalarOutputCount
!= 2) {
3005 return kIOReturnBadArgument
;
3007 ret
= registerClass((OSClassDescription
*) args
->structureInput
, args
->structureInputSize
, &cls
);
3008 if (kIOReturnSuccess
== ret
) {
3009 portname
= iokit_make_send_right(fOwningTask
, cls
, IKOT_UEXT_OBJECT
);
3011 args
->scalarOutput
[0] = portname
;
3012 args
->scalarOutput
[1] = kOSObjectRPCRemote
;
3016 case kIOUserServerMethodStart
:
3018 if (args
->scalarOutputCount
!= 1) {
3019 return kIOReturnBadArgument
;
3021 portname
= iokit_make_send_right(fOwningTask
, this, IKOT_UEXT_OBJECT
);
3023 args
->scalarOutput
[0] = portname
;
3024 ret
= kIOReturnSuccess
;
3035 IOUserServer::getTargetAndTrapForIndex( IOService
**targetP
, UInt32 index
)
3037 static const IOExternalTrap trapTemplate
[] = {
3038 { NULL
, (IOTrap
) & IOUserServer::waitInterruptTrap
},
3040 if (index
>= (sizeof(trapTemplate
) / sizeof(IOExternalTrap
))) {
3044 return (IOExternalTrap
*)&trapTemplate
[index
];
3047 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3050 IOUserServer::serviceAttach(IOService
* service
, IOService
* provider
)
3053 OSObjectUserVars
* vars
;
3056 OSSymbolConstPtr bundleID
;
3057 char execPath
[1024];
3059 vars
= IONewZero(OSObjectUserVars
, 1);
3060 service
->reserved
->uvars
= vars
;
3062 vars
->userServer
= this;
3063 vars
->userServer
->retain();
3065 if (-1U == fServices
->getNextIndexOfObject(service
, 0)) {
3066 fServices
->setObject(service
);
3068 IOLockUnlock(fLock
);
3070 prop
= service
->copyProperty(gIOUserClassKey
);
3071 str
= OSDynamicCast(OSString
, prop
);
3073 service
->setName(str
);
3075 OSSafeReleaseNULL(prop
);
3077 prop
= service
->copyProperty(gIOModuleIdentifierKey
);
3078 bundleID
= OSDynamicCast(OSSymbol
, prop
);
3081 bool ok
= OSKext::copyUserExecutablePath(bundleID
, execPath
, sizeof(execPath
));
3083 ret
= LoadModule(execPath
);
3084 if (kIODKLogSetup
& gIODKDebug
) {
3085 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret
, execPath
);
3089 OSSafeReleaseNULL(prop
);
3091 ret
= kIOReturnSuccess
;
3096 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3098 #define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
3101 IOUserServer::serviceNewUserClient(IOService
* service
, task_t owningTask
, void * securityID
,
3102 uint32_t type
, OSDictionary
* properties
, IOUserClient
** handler
)
3106 IOUserUserClient
* userUC
;
3107 OSDictionary
* entitlements
;
3109 OSObject
* bundleID
;
3113 ret
= service
->NewUserClient(type
, &uc
);
3114 if (kIOReturnSuccess
!= ret
) {
3117 userUC
= OSDynamicCast(IOUserUserClient
, uc
);
3120 OSSafeReleaseNULL(uc
);
3121 return kIOReturnUnsupported
;
3123 userUC
->setTask(owningTask
);
3125 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
3126 entitlements
= IOUserClient::copyClientEntitlements(owningTask
);
3127 bundleID
= service
->copyProperty(gIOModuleIdentifierKey
);
3130 && (prop
= entitlements
->getObject(gIODriverKitUserClientEntitlementsKey
)));
3132 bool found __block
= false;
3133 ok
= prop
->iterateObjects(^bool (OSObject
* object
) {
3134 found
= object
->isEqualTo(bundleID
);
3140 prop
= userUC
->copyProperty(gIOServiceDEXTEntitlementsKey
);
3141 ok
= checkEntitlements(entitlements
, prop
, NULL
, NULL
);
3143 OSSafeReleaseNULL(bundleID
);
3144 OSSafeReleaseNULL(entitlements
);
3146 DKLOG(DKS
":UC entitlements check failed\n", DKN(userUC
));
3148 OSSafeReleaseNULL(uc
);
3149 return kIOReturnNotPermitted
;
3158 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3160 static IOPMPowerState
3162 { .version
= kIOPMPowerStateVersion1
,
3163 .capabilityFlags
= 0,
3164 .outputPowerCharacter
= 0,
3165 .inputPowerRequirement
= 0},
3166 { .version
= kIOPMPowerStateVersion1
,
3167 .capabilityFlags
= kIOPMLowPower
,
3168 .outputPowerCharacter
= kIOPMLowPower
,
3169 .inputPowerRequirement
= kIOPMLowPower
},
3170 { .version
= kIOPMPowerStateVersion1
,
3171 .capabilityFlags
= kIOPMPowerOn
,
3172 .outputPowerCharacter
= kIOPMPowerOn
,
3173 .inputPowerRequirement
= kIOPMPowerOn
},
3177 IOUserServer::setPowerState(unsigned long state
, IOService
* service
)
3179 if (kIODKLogPM
& gIODKDebug
) {
3180 DKLOG(DKS
"::setPowerState(%ld) %d\n", DKN(service
), state
, fSystemPowerAck
);
3182 return kIOPMAckImplied
;
3186 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
3190 if (service
->reserved
->uvars
) {
3191 if (!fSystemOff
&& !(kIODKDisablePM
& gIODKDebug
)) {
3192 service
->reserved
->uvars
->willPower
= true;
3193 if (kIODKLogPM
& gIODKDebug
) {
3194 DKLOG(DKS
"::powerStateWillChangeTo(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
3196 ret
= service
->SetPowerState(flags
);
3197 if (kIOReturnSuccess
== ret
) {
3198 return 20 * 1000 * 1000;
3201 service
->reserved
->uvars
->willPower
= false;
3204 return kIOPMAckImplied
;
3208 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
3215 idx
= fServices
->getNextIndexOfObject(service
, 0);
3217 IOLockUnlock(fLock
);
3218 return kIOPMAckImplied
;
3223 fPowerStates
|= (1ULL << idx
);
3225 fPowerStates
&= ~(1ULL << idx
);
3227 if (kIODKLogPM
& gIODKDebug
) {
3228 DKLOG(DKS
"::powerStateDidChangeTo(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
3230 if (!fPowerStates
&& (pmAck
= fSystemPowerAck
)) {
3231 fSystemPowerAck
= false;
3234 IOLockUnlock(fLock
);
3237 IOServicePH::serverAck(this);
3240 return kIOPMAckImplied
;
3244 IMPL(IOService
, SetPowerState
)
3246 if (kIODKLogPM
& gIODKDebug
) {
3247 DKLOG(DKS
"::SetPowerState(%d), %d\n", DKN(this), powerFlags
, reserved
->uvars
->willPower
);
3250 && reserved
->uvars
->userServer
3251 && reserved
->uvars
->willPower
) {
3252 reserved
->uvars
->willPower
= false;
3253 acknowledgePowerChange(reserved
->uvars
->userServer
);
3254 return kIOReturnSuccess
;
3256 return kIOReturnNotReady
;
3260 IMPL(IOService
, ChangePowerState
)
3262 switch (powerFlags
) {
3263 case kIOServicePowerCapabilityOff
:
3264 changePowerStateToPriv(0);
3266 case kIOServicePowerCapabilityLow
:
3267 changePowerStateToPriv(1);
3269 case kIOServicePowerCapabilityOn
:
3270 changePowerStateToPriv(2);
3273 return kIOReturnBadArgument
;
3276 return kIOReturnSuccess
;
3280 IMPL(IOService
, Create
)
3283 IOService
* service
;
3285 const OSSymbol
* sym
;
3287 OSDictionary
* properties
;
3290 if (provider
!= this) {
3291 return kIOReturnUnsupported
;
3294 ret
= kIOReturnUnsupported
;
3298 prop
= copyProperty(propertiesKey
);
3299 properties
= OSDynamicCast(OSDictionary
, prop
);
3302 str
= OSDynamicCast(OSString
, properties
->getObject(gIOClassKey
));
3304 sym
= OSSymbol::withString(str
);
3306 inst
= OSMetaClass::allocClassWithName(sym
);
3307 service
= OSDynamicCast(IOService
, inst
);
3308 if (service
&& service
->init(properties
) && service
->attach(this)) {
3309 reserved
->uvars
->userServer
->serviceAttach(service
, this);
3310 service
->reserved
->uvars
->started
= true;
3311 ret
= kIOReturnSuccess
;
3314 OSSafeReleaseNULL(sym
);
3318 OSSafeReleaseNULL(prop
);
3319 if (kIOReturnSuccess
!= ret
) {
3320 OSSafeReleaseNULL(inst
);
3327 IMPL(IOService
, Terminate
)
3332 return kIOReturnUnsupported
;
3335 us
= (typeof(us
))thread_iokit_tls_get(0);
3336 if (!reserved
->uvars
3337 || (reserved
->uvars
->userServer
!= us
)) {
3338 return kIOReturnNotPermitted
;
3340 terminate(kIOServiceTerminateNeedWillTerminate
);
3342 return kIOReturnSuccess
;
3346 IMPL(IOService
, NewUserClient
)
3348 return kIOReturnError
;
3352 IMPL(IOService
, SearchProperty
)
3356 if (kIOServiceSearchPropertyParents
& options
) {
3357 options
= kIORegistryIterateParents
| kIORegistryIterateRecursively
;
3362 object
= copyProperty(name
, IORegistryEntry::getPlane(plane
), options
);
3365 return object
? kIOReturnSuccess
: kIOReturnNotFound
;
3369 IMPL(IOService
, CopyProviderProperties
)
3373 IOService
* provider
;
3375 result
= OSArray::withCapacity(8);
3377 return kIOReturnNoMemory
;
3380 ret
= kIOReturnSuccess
;
3381 for (provider
= this; provider
; provider
= provider
->getProvider()) {
3383 OSDictionary
* props
;
3385 obj
= provider
->copyProperty(gIOSupportedPropertiesKey
);
3386 props
= OSDynamicCast(OSDictionary
, obj
);
3388 OSSafeReleaseNULL(obj
);
3389 props
= provider
->dictionaryWithProperties();
3392 ret
= kIOReturnNoMemory
;
3395 bool __block addClass
= true;
3397 OSDictionary
* retProps
;
3398 retProps
= OSDictionary::withCapacity(4);
3401 ret
= kIOReturnNoMemory
;
3404 propertyKeys
->iterateObjects(^bool (OSObject
* _key
) {
3405 OSString
* key
= OSDynamicCast(OSString
, _key
);
3406 if (gIOClassKey
->isEqualTo(key
)) {
3410 retProps
->setObject(key
, props
->getObject(key
));
3413 OSSafeReleaseNULL(props
);
3417 OSArray
* classes
= OSArray::withCapacity(8);
3419 ret
= kIOReturnNoMemory
;
3422 for (const OSMetaClass
* meta
= provider
->getMetaClass(); meta
; meta
= meta
->getSuperClass()) {
3423 classes
->setObject(meta
->getClassNameSymbol());
3425 props
->setObject(gIOClassKey
, classes
);
3426 OSSafeReleaseNULL(classes
);
3428 bool ok
= result
->setObject(props
);
3431 ret
= kIOReturnNoMemory
;
3435 if (kIOReturnSuccess
!= ret
) {
3436 OSSafeReleaseNULL(result
);
3438 *properties
= result
;
3443 IOUserServer::systemPower(bool powerOff
)
3447 if (kIODKLogPM
& gIODKDebug
) {
3448 DKLOG("%s::powerOff(%d) 0x%qx\n", getName(), powerOff
, fPowerStates
);
3452 services
= OSArray::withArray(fServices
);
3455 fSystemPowerAck
= (0 != fPowerStates
);
3456 if (!fSystemPowerAck
) {
3459 IOLockUnlock(fLock
);
3461 if (!fSystemPowerAck
) {
3462 IOServicePH::serverAck(this);
3465 services
->iterateObjects(^bool (OSObject
* obj
) {
3466 IOService
* service
;
3467 service
= (IOService
*) obj
;
3468 if (kIODKLogPM
& gIODKDebug
) {
3469 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), 0);
3471 service
->reserved
->uvars
->powerOverride
= service
->getPowerState();
3472 service
->changePowerStateWithOverrideTo(0, 0);
3479 IOLockUnlock(fLock
);
3481 services
->iterateObjects(^bool (OSObject
* obj
) {
3482 IOService
* service
;
3483 service
= (IOService
*) obj
;
3484 if (-1U != service
->reserved
->uvars
->powerOverride
) {
3485 if (kIODKLogPM
& gIODKDebug
) {
3486 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), service
->reserved
->uvars
->powerOverride
);
3488 service
->changePowerStateWithOverrideTo(service
->reserved
->uvars
->powerOverride
, 0);
3489 service
->reserved
->uvars
->powerOverride
= -1U;
3495 OSSafeReleaseNULL(services
);
3501 IOUserServer::serviceStarted(IOService
* service
, IOService
* provider
, bool result
)
3504 IOService
* pmProvider
;
3506 DKLOG(DKS
"::start(" DKS
") %s\n", DKN(service
), DKN(provider
), result
? "ok" : "fail");
3509 ret
= kIOReturnSuccess
;
3513 if (!fRootNotifier
) {
3514 ret
= registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
3515 assert(kIOReturnSuccess
== ret
);
3516 IOServicePH::serverAdd(this);
3517 fRootNotifier
= true;
3520 if (!(kIODKDisablePM
& gIODKDebug
) && !service
->pm_vars
) {
3522 ret
= service
->registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
3523 assert(kIOReturnSuccess
== ret
);
3525 pmProvider
= service
;
3526 while (pmProvider
&& !pmProvider
->inPlane(gIOPowerPlane
)) {
3527 pmProvider
= pmProvider
->getProvider();
3532 prop
= pmProvider
->copyProperty("non-removable");
3534 str
= OSDynamicCast(OSString
, prop
);
3535 if (str
&& str
->isEqualTo("yes")) {
3543 unsigned int idx
= fServices
->getNextIndexOfObject(service
, 0);
3545 fPowerStates
|= (1ULL << idx
);
3546 IOLockUnlock(fLock
);
3548 pmProvider
->joinPMtree(service
);
3549 service
->reserved
->uvars
->userServerPM
= true;
3553 service
->registerInterestedDriver(this);
3554 service
->reserved
->uvars
->started
= true;
3556 return kIOReturnSuccess
;
3561 IOUserServer::serviceOpen(IOService
* provider
, IOService
* client
)
3563 OSObjectUserVars
* uvars
;
3565 uvars
= client
->reserved
->uvars
;
3566 if (!uvars
->openProviders
) {
3567 uvars
->openProviders
= OSArray::withObjects((const OSObject
**) &provider
, 1);
3568 } else if (-1U == uvars
->openProviders
->getNextIndexOfObject(client
, 0)) {
3569 uvars
->openProviders
->setObject(provider
);
3572 return kIOReturnSuccess
;
3576 IOUserServer::serviceClose(IOService
* provider
, IOService
* client
)
3578 OSObjectUserVars
* uvars
;
3581 uvars
= client
->reserved
->uvars
;
3582 if (!uvars
->openProviders
) {
3583 return kIOReturnNotOpen
;
3585 idx
= uvars
->openProviders
->getNextIndexOfObject(client
, 0);
3587 return kIOReturnNotOpen
;
3589 uvars
->openProviders
->removeObject(idx
);
3591 return kIOReturnSuccess
;
3596 IOUserServer::serviceStop(IOService
* service
, IOService
*)
3599 uint32_t idx
, queueAlloc
;
3600 OSObjectUserVars
* uvars
;
3603 idx
= fServices
->getNextIndexOfObject(service
, 0);
3605 fServices
->removeObject(idx
);
3606 uvars
= service
->reserved
->uvars
;
3607 uvars
->stopped
= true;
3609 IOLockUnlock(fLock
);
3612 return kIOReturnSuccess
;
3615 if (uvars
->queueArray
&& uvars
->userMeta
) {
3617 if (uvars
->userMeta
->queueNames
) {
3618 queueAlloc
+= uvars
->userMeta
->queueNames
->count
;
3620 for (idx
= 0; idx
< queueAlloc
; idx
++) {
3621 OSSafeReleaseNULL(uvars
->queueArray
[idx
]);
3623 IOSafeDeleteNULL(uvars
->queueArray
, IODispatchQueue
*, queueAlloc
);
3626 (void) service
->deRegisterInterestedDriver(this);
3627 if (uvars
->userServerPM
) {
3631 ret
= kIOReturnSuccess
;
3636 IOUserServer::serviceFree(IOService
* service
)
3638 OSObjectUserVars
* uvars
;
3640 uvars
= service
->reserved
->uvars
;
3644 OSSafeReleaseNULL(uvars
->userServer
);
3645 IOSafeDeleteNULL(service
->reserved
->uvars
, OSObjectUserVars
, 1);
3649 IOUserServer::serviceWillTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
)
3654 willTerminate
= false;
3655 if (client
->lockForArbitration(true)) {
3656 if (!client
->reserved
->uvars
->serverDied
3657 && !client
->reserved
->uvars
->willTerminate
) {
3658 client
->reserved
->uvars
->willTerminate
= true;
3659 willTerminate
= true;
3661 client
->unlockForArbitration();
3664 if (willTerminate
) {
3665 ret
= client
->Stop(provider
);
3666 if (kIOReturnSuccess
!= ret
) {
3667 ret
= client
->IOService::Stop(provider
);
3673 IOUserServer::serviceDidTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
, bool * defer
)
3675 if (client
->lockForArbitration(true)) {
3676 client
->reserved
->uvars
->didTerminate
= true;
3677 if (!client
->reserved
->uvars
->serverDied
3678 && !client
->reserved
->uvars
->stopped
) {
3681 client
->unlockForArbitration();
3686 IOUserServer::serviceDidStop(IOService
* client
, IOService
* provider
)
3689 OSArray
* closeArray
;
3694 if (client
->lockForArbitration(true)) {
3695 if (client
->reserved
->uvars
3696 && client
->reserved
->uvars
->willTerminate
3697 && !client
->reserved
->uvars
->stopped
) {
3698 client
->reserved
->uvars
->stopped
= true;
3699 complete
= client
->reserved
->uvars
->didTerminate
;
3702 if (client
->reserved
->uvars
) {
3703 closeArray
= client
->reserved
->uvars
->openProviders
;
3704 client
->reserved
->uvars
->openProviders
= NULL
;
3706 client
->unlockForArbitration();
3708 closeArray
->iterateObjects(^bool (OSObject
* obj
) {
3709 IOService
* toClose
;
3710 toClose
= OSDynamicCast(IOService
, obj
);
3712 DKLOG(DKS
":force close (" DKS
")\n", DKN(client
), DKN(toClose
));
3713 toClose
->close(client
);
3717 closeArray
->release();
3722 client
->didTerminate(provider
, 0, &defer
);
3727 IMPL(IOService
, Stop
)
3729 IOUserServer::serviceDidStop(this, provider
);
3731 return kIOReturnSuccess
;
3734 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3737 #define super IOUserClient
3739 OSDefineMetaClassAndStructors(IOUserUserClient
, IOUserClient
)
3741 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3744 IOUserUserClient::setTask(task_t task
)
3746 task_reference(task
);
3749 return kIOReturnSuccess
;
3753 IOUserUserClient::stop(IOService
* provider
)
3756 task_deallocate(fTask
);
3759 super::stop(provider
);
3763 IOUserUserClient::clientClose(void)
3765 terminate(kIOServiceTerminateNeedWillTerminate
);
3766 return kIOReturnSuccess
;
3770 IOUserUserClient::setProperties(OSObject
* properties
)
3772 IOReturn ret
= kIOReturnUnsupported
;
3776 struct IOUserUserClientActionRef
{
3777 OSAsyncReference64 asyncRef
;
3781 IMPL(IOUserClient
, KernelCompletion
)
3783 IOUserUserClientActionRef
* ref
;
3785 ref
= (typeof(ref
))action
->GetReference();
3787 IOUserClient::sendAsyncResult64(ref
->asyncRef
, status
, (io_user_reference_t
*) asyncData
, asyncDataCount
);
3791 IMPL(IOUserClient
, _ExternalMethod
)
3793 return kIOReturnUnsupported
;
3797 IOUserUserClient::clientMemoryForType(UInt32 type
,
3798 IOOptionBits
* koptions
,
3799 IOMemoryDescriptor
** kmemory
)
3803 IOMemoryDescriptor
* memory
;
3805 kr
= CopyClientMemoryForType(type
, &options
, &memory
);
3809 if (kIOReturnSuccess
!= kr
) {
3813 if (kIOUserClientMemoryReadOnly
& options
) {
3814 *koptions
|= kIOMapReadOnly
;
3822 IOUserUserClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
3823 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
3826 OSData
* structureInput
;
3827 OSData
* structureOutput
;
3829 uint64_t structureOutputSize
;
3831 IOUserUserClientActionRef
* ref
;
3833 kr
= kIOReturnUnsupported
;
3834 structureInput
= NULL
;
3837 if (args
->structureInputSize
) {
3838 structureInput
= OSData::withBytesNoCopy((void *) args
->structureInput
, args
->structureInputSize
);
3841 if (MACH_PORT_NULL
!= args
->asyncWakePort
) {
3842 kr
= CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef
), &action
);
3843 assert(KERN_SUCCESS
== kr
);
3844 ref
= (typeof(ref
))action
->GetReference();
3845 bcopy(args
->asyncReference
, &ref
->asyncRef
[0], args
->asyncReferenceCount
* sizeof(ref
->asyncRef
[0]));
3848 if (args
->structureVariableOutputData
) {
3849 structureOutputSize
= kIOUserClientVariableStructureSize
;
3850 } else if (args
->structureOutputDescriptor
) {
3851 structureOutputSize
= args
->structureOutputDescriptor
->getLength();
3853 structureOutputSize
= args
->structureOutputSize
;
3856 kr
= _ExternalMethod(selector
, &args
->scalarInput
[0], args
->scalarInputCount
,
3857 structureInput
, args
->structureInputDescriptor
,
3858 args
->scalarOutput
, &args
->scalarOutputCount
,
3859 structureOutputSize
, &structureOutput
, args
->structureOutputDescriptor
,
3862 OSSafeReleaseNULL(structureInput
);
3863 OSSafeReleaseNULL(action
);
3865 if (kIOReturnSuccess
!= kr
) {
3868 if (structureOutput
) {
3869 if (args
->structureVariableOutputData
) {
3870 *args
->structureVariableOutputData
= structureOutput
;
3872 copylen
= structureOutput
->getLength();
3873 if (copylen
> args
->structureOutputSize
) {
3874 kr
= kIOReturnBadArgument
;
3876 bcopy((const void *) structureOutput
->getBytesNoCopy(), args
->structureOutput
, copylen
);
3878 OSSafeReleaseNULL(structureOutput
);
3885 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */