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/IOUserServer.h>
65 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
67 #include <System/IODataQueueDispatchSourceShared.h>
69 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
71 SInt64 gIODKDebug
= kIODKEnable
;
73 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
77 class OSUserMetaClass
: public OSObject
79 OSDeclareDefaultStructors(OSUserMetaClass
);
81 const OSSymbol
* name
;
82 const OSMetaClass
* meta
;
83 OSUserMetaClass
* superMeta
;
87 OSClassDescription
* description
;
88 IOPStrings
* queueNames
;
92 virtual void free() override
;
93 virtual kern_return_t
Dispatch(const IORPC rpc
) APPLE_KEXT_OVERRIDE
;
95 OSDefineMetaClassAndStructors(OSUserMetaClass
, OSObject
);
97 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
99 class IOUserService
: public IOService
101 friend class IOService
;
103 OSDeclareDefaultStructors(IOUserService
)
106 start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
108 setProperties(OSObject
* props
) APPLE_KEXT_OVERRIDE
;
111 OSDefineMetaClassAndStructors(IOUserService
, IOService
)
113 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
115 class IOUserUserClient
: public IOUserClient
117 OSDeclareDefaultStructors(IOUserUserClient
);
121 IOReturn
setTask(task_t task
);
122 virtual void stop(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
123 virtual IOReturn
clientClose(void) APPLE_KEXT_OVERRIDE
;
124 virtual IOReturn
setProperties(OSObject
* properties
) APPLE_KEXT_OVERRIDE
;
125 virtual IOReturn
externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
126 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
) APPLE_KEXT_OVERRIDE
;
127 virtual IOReturn
clientMemoryForType(UInt32 type
,
128 IOOptionBits
* options
,
129 IOMemoryDescriptor
** memory
) APPLE_KEXT_OVERRIDE
;
133 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
137 IOUserService::start(IOService
* provider
)
142 ret
= Start(provider
);
143 if (kIOReturnSuccess
!= ret
) {
151 IOUserService::setProperties(OSObject
* properties
)
153 setProperty("USER", properties
);
154 return kIOReturnSuccess
;
157 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
161 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
163 struct IODispatchQueue_IVars
{
164 IOUserServer
* userServer
;
165 IODispatchQueue
* queue
;
169 mach_port_t serverPort
;
172 struct OSAction_IVars
{
174 uint64_t targetmsgid
;
176 OSActionAbortedHandler abortedHandler
;
177 size_t referenceSize
;
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
184 IMPL(IOService
, GetRegistryEntryID
)
186 IOReturn ret
= kIOReturnSuccess
;
188 *registryEntryID
= getRegistryEntryID();
194 IMPL(IOService
, SetName
)
196 IOReturn ret
= kIOReturnSuccess
;
204 IMPL(IOService
, Start
)
206 IOReturn ret
= kIOReturnSuccess
;
211 IMPL(IOService
, RegisterService
)
213 IOReturn ret
= kIOReturnSuccess
;
221 IMPL(IOService
, CopyDispatchQueue
)
223 IODispatchQueue
* result
;
228 ret
= kIOReturnNotFound
;
230 if (!strcmp("Default", name
)) {
232 } else if (reserved
->uvars
->userMeta
233 && reserved
->uvars
->userMeta
->queueNames
) {
234 index
= reserved
->uvars
->userServer
->stringArrayIndex(reserved
->uvars
->userMeta
->queueNames
, name
);
240 if ((service
= getProvider())) {
241 ret
= service
->CopyDispatchQueue(name
, queue
);
244 result
= reserved
->uvars
->queueArray
[index
];
248 ret
= kIOReturnSuccess
;
256 IMPL(IOService
, SetDispatchQueue
)
258 IOReturn ret
= kIOReturnSuccess
;
261 if (kIODKLogSetup
& gIODKDebug
) {
262 DKLOG(DKS
"::SetDispatchQueue(%s)\n", DKN(this), name
);
264 queue
->ivars
->userServer
= reserved
->uvars
->userServer
;
266 if (!strcmp("Default", name
)) {
268 } else if (reserved
->uvars
->userMeta
269 && reserved
->uvars
->userMeta
->queueNames
) {
270 index
= reserved
->uvars
->userServer
->stringArrayIndex(reserved
->uvars
->userMeta
->queueNames
, name
);
276 ret
= kIOReturnBadArgument
;
278 reserved
->uvars
->queueArray
[index
] = queue
;
286 IMPL(IOService
, SetProperties
)
288 IOReturn ret
= kIOReturnUnsupported
;
290 ret
= setProperties(properties
);
296 IMPL(IOService
, CopyProperties
)
298 IOReturn ret
= kIOReturnSuccess
;
299 *properties
= dictionaryWithProperties();
303 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
306 IMPL(IOMemoryDescriptor
, _CopyState
)
310 state
->length
= _length
;
311 state
->options
= _flags
;
313 ret
= kIOReturnSuccess
;
319 IOMemoryDescriptor::GetLength(uint64_t * returnLength
)
321 *returnLength
= getLength();
323 return kIOReturnSuccess
;
327 IMPL(IOMemoryDescriptor
, CreateMapping
)
330 IOMemoryMap
* resultMap
;
331 IOOptionBits koptions
;
332 mach_vm_address_t atAddress
;
334 ret
= kIOReturnSuccess
;
338 if (kIOMemoryMapFixedAddress
& options
) {
343 koptions
|= kIOMapAnywhere
;
346 if (kIOMemoryMapReadOnly
& options
|| (kIODirectionOut
== getDirection())) {
347 if (!reserved
|| (current_task() != reserved
->creator
)) {
348 koptions
|= kIOMapReadOnly
;
352 switch (0xFF00 & options
) {
353 case kIOMemoryMapCacheModeDefault
:
354 koptions
|= kIOMapDefaultCache
;
356 case kIOMemoryMapCacheModeInhibit
:
357 koptions
|= kIOMapInhibitCache
;
359 case kIOMemoryMapCacheModeCopyback
:
360 koptions
|= kIOMapCopybackCache
;
362 case kIOMemoryMapCacheModeWriteThrough
:
363 koptions
|= kIOMapWriteThruCache
;
366 ret
= kIOReturnBadArgument
;
369 if (kIOReturnSuccess
== ret
) {
370 resultMap
= createMappingInTask(current_task(), atAddress
, koptions
, offset
, length
);
372 ret
= kIOReturnError
;
382 IMPL(IOMemoryDescriptor
, PrepareForDMA
)
390 return kIOReturnBadArgument
;
393 count
= *segmentsCount
;
395 for (idx
= 0; idx
< count
; idx
++) {
397 segments
[idx
].address
= getPhysicalSegment(offset
, &segments
[idx
].length
);
399 segments
[idx
].address
= 0;
401 if (!segments
[idx
].address
) {
404 sumLength
+= segments
[idx
].length
;
405 offset
+= segments
[idx
].length
;
407 *returnLength
= sumLength
;
408 *segmentsCount
= idx
;
412 if (kIODirectionOut
& _flags
) {
413 lflags
|= kIOMemoryDirectionOut
;
415 if (kIODirectionIn
& _flags
) {
416 lflags
|= kIOMemoryDirectionIn
;
420 ret
= kIOReturnSuccess
;
425 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
428 IMPL(IOMemoryMap
, _CopyState
)
432 state
->offset
= fOffset
;
433 state
->length
= getLength();
434 state
->address
= getAddress();
435 state
->options
= getMapOptions();
437 ret
= kIOReturnSuccess
;
442 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
445 IMPL(IOBufferMemoryDescriptor
, Create
)
448 IOBufferMemoryDescriptor
* bmd
;
449 IOMemoryDescriptorReserved
* reserved
;
451 if (options
& ~((uint64_t) kIOMemoryDirectionOutIn
)) {
452 // no other options currently defined
453 return kIOReturnBadArgument
;
455 options
&= kIOMemoryDirectionOutIn
;
456 bmd
= IOBufferMemoryDescriptor::inTaskWithOptions(
457 kernel_task
, options
, capacity
, alignment
);
462 return kIOReturnNoMemory
;
465 reserved
= bmd
->getKernelReserved();
466 reserved
->creator
= current_task();
467 task_reference(reserved
->creator
);
469 ret
= kIOReturnSuccess
;
475 IMPL(IOBufferMemoryDescriptor
, SetLength
)
478 return kIOReturnSuccess
;
481 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
484 OSAction::Create(OSAction_Create_Args
)
487 ret
= OSAction::Create_Call(target
, targetmsgid
, msgid
, referenceSize
, action
);
492 IMPL(OSAction
, Create
)
497 if (os_add_overflow(referenceSize
, sizeof(OSAction_IVars
), &allocsize
)) {
498 return kIOReturnBadArgument
;
500 inst
= OSTypeAlloc(OSAction
);
502 return kIOReturnNoMemory
;
504 inst
->ivars
= (typeof(inst
->ivars
))(uintptr_t) IONewZero(uint8_t, allocsize
);
507 return kIOReturnNoMemory
;
510 inst
->ivars
->target
= target
;
511 inst
->ivars
->targetmsgid
= targetmsgid
;
512 inst
->ivars
->msgid
= msgid
;
513 inst
->ivars
->referenceSize
= referenceSize
;
517 return kIOReturnSuccess
;
524 if (ivars
->abortedHandler
) {
525 Block_release(ivars
->abortedHandler
);
526 ivars
->abortedHandler
= NULL
;
528 OSSafeReleaseNULL(ivars
->target
);
529 IOSafeDeleteNULL(ivars
, uint8_t, ivars
->referenceSize
+ sizeof(OSAction_IVars
));
531 return super::free();
535 OSAction::GetReference()
537 assert(ivars
&& ivars
->referenceSize
);
538 return &ivars
->reference
[0];
542 OSAction::SetAbortedHandler(OSActionAbortedHandler handler
)
544 ivars
->abortedHandler
= Block_copy(handler
);
545 return kIOReturnSuccess
;
549 OSAction::Aborted_Impl(void)
551 if (ivars
->abortedHandler
) {
552 ivars
->abortedHandler();
556 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
558 struct IODispatchSource_IVars
{
560 IODispatchSource
* source
;
561 IOUserServer
* server
;
562 IODispatchQueue_IVars
* queue
;
567 IODispatchSource::init()
569 if (!super::init()) {
573 ivars
= IONewZero(IODispatchSource_IVars
, 1);
575 ivars
->source
= this;
581 IODispatchSource::free()
583 IOSafeDeleteNULL(ivars
, IODispatchSource_IVars
, 1);
587 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
589 struct IOInterruptDispatchSource_IVars
{
590 IOService
* provider
;
601 IOInterruptDispatchSourceInterrupt(OSObject
* target
, void * refCon
,
602 IOService
* nub
, int source
)
604 IOInterruptDispatchSource_IVars
* ivars
= (typeof(ivars
))refCon
;
607 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
610 ivars
->time
= mach_absolute_time();
611 thread_wakeup_thread((event_t
) ivars
, ivars
->waiter
);
612 ivars
->waiter
= NULL
;
614 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
618 IMPL(IOInterruptDispatchSource
, Create
)
621 IOInterruptDispatchSource
* inst
;
623 inst
= OSTypeAlloc(IOInterruptDispatchSource
);
626 return kIOReturnNoMemory
;
629 inst
->ivars
->lock
= IOSimpleLockAlloc();
631 ret
= provider
->registerInterrupt(index
, inst
, IOInterruptDispatchSourceInterrupt
, inst
->ivars
);
632 if (kIOReturnSuccess
== ret
) {
633 inst
->ivars
->intIndex
= index
;
634 inst
->ivars
->provider
= provider
;
641 IOInterruptDispatchSource::init()
643 if (!super::init()) {
646 ivars
= IONewZero(IOInterruptDispatchSource_IVars
, 1);
655 IOInterruptDispatchSource::free()
659 if (ivars
&& ivars
->provider
) {
660 ret
= ivars
->provider
->unregisterInterrupt(ivars
->intIndex
);
661 assert(kIOReturnSuccess
== ret
);
664 IOSafeDeleteNULL(ivars
, IOInterruptDispatchSource_IVars
, 1);
670 IMPL(IOInterruptDispatchSource
, SetHandler
)
673 OSAction
* oldAction
;
675 oldAction
= (typeof(oldAction
))ivars
->action
;
676 if (oldAction
&& OSCompareAndSwapPtr(oldAction
, NULL
, &ivars
->action
)) {
677 oldAction
->release();
680 ivars
->action
= action
;
682 ret
= kIOReturnSuccess
;
688 IMPL(IOInterruptDispatchSource
, SetEnableWithCompletion
)
693 if (enable
== ivars
->enable
) {
694 return kIOReturnSuccess
;
698 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
699 ivars
->enable
= enable
;
700 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
701 ret
= ivars
->provider
->enableInterrupt(ivars
->intIndex
);
703 ret
= ivars
->provider
->disableInterrupt(ivars
->intIndex
);
704 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
705 ivars
->enable
= enable
;
706 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
713 IMPL(IODispatchSource
, SetEnable
)
715 return SetEnableWithCompletion(enable
, NULL
);
719 IMPL(IOInterruptDispatchSource
, CheckForWork
)
721 IOReturn ret
= kIOReturnNotReady
;
723 wait_result_t waitResult
;
728 self
= current_thread();
731 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
732 if ((icount
= ivars
->count
)) {
735 waitResult
= THREAD_AWAKENED
;
736 } else if (synchronous
) {
737 assert(NULL
== ivars
->waiter
);
738 ivars
->waiter
= self
;
739 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
741 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
742 if (synchronous
&& (waitResult
== THREAD_WAITING
)) {
743 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
744 if (THREAD_INTERRUPTED
== waitResult
) {
748 } while (synchronous
&& !icount
);
750 if (icount
&& ivars
->action
) {
751 ret
= InterruptOccurred(rpc
, ivars
->action
, icount
, itime
);
758 IMPL(IOInterruptDispatchSource
, InterruptOccurred
)
762 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
765 IOUserServer::waitInterruptTrap(void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
767 IOReturn ret
= kIOReturnBadArgument
;
769 IOInterruptDispatchSource
* interrupt
;
770 IOInterruptDispatchSource_IVars
* ivars
;
771 IOInterruptDispatchSourcePayload payload
;
773 wait_result_t waitResult
;
778 object
= iokit_lookup_object_with_port_name((mach_port_name_t
)(uintptr_t)p1
, IKOT_UEXT_OBJECT
, current_task());
781 return kIOReturnBadArgument
;
783 if (!(interrupt
= OSDynamicCast(IOInterruptDispatchSource
, object
))) {
784 ret
= kIOReturnBadArgument
;
786 self
= current_thread();
787 ivars
= interrupt
->ivars
;
790 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
791 if ((payload
.count
= ivars
->count
)) {
792 payload
.time
= ivars
->time
;
794 waitResult
= THREAD_AWAKENED
;
796 assert(NULL
== ivars
->waiter
);
797 ivars
->waiter
= self
;
798 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
800 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
801 if (waitResult
== THREAD_WAITING
) {
802 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
803 if (THREAD_INTERRUPTED
== waitResult
) {
807 } while (!payload
.count
);
808 ret
= (payload
.count
? kIOReturnSuccess
: kIOReturnAborted
);
811 if (kIOReturnSuccess
== ret
) {
812 int copyerr
= copyout(&payload
, (user_addr_t
) p2
, sizeof(payload
));
814 ret
= kIOReturnVMError
;
823 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
826 IMPL(IOUserServer
, Create
)
830 const OSSymbol
* sym
;
831 OSNumber
* serverTag
;
834 us
= (typeof(us
))thread_iokit_tls_get(0);
835 assert(OSDynamicCast(IOUserServer
, us
));
836 if (kIODKLogSetup
& gIODKDebug
) {
837 DKLOG(DKS
"::Create(" DKS
") %p\n", DKN(us
), name
, tag
, us
);
840 return kIOReturnError
;
843 sym
= OSSymbol::withCString(name
);
844 serverTag
= OSNumber::withNumber(tag
, 64);
846 us
->setProperty(gIOUserServerNameKey
, (OSObject
*) sym
);
847 us
->setProperty(gIOUserServerTagKey
, serverTag
);
849 serverTag
->release();
850 OSSafeReleaseNULL(sym
);
852 snprintf(rname
, sizeof(rname
), "IOUserServer(%s-0x%qx)", name
, tag
);
857 ret
= kIOReturnSuccess
;
863 IMPL(IOUserServer
, Exit
)
865 return kIOReturnUnsupported
;
869 IMPL(IOUserServer
, LoadModule
)
871 return kIOReturnUnsupported
;
875 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
878 IMPL(IODispatchQueue
, Create
)
880 IODispatchQueue
* result
;
883 result
= OSTypeAlloc(IODispatchQueue
);
885 return kIOReturnNoMemory
;
887 if (!result
->init()) {
888 return kIOReturnNoMemory
;
893 if (!strcmp("Root", name
)) {
894 us
= (typeof(us
))thread_iokit_tls_get(0);
895 assert(OSDynamicCast(IOUserServer
, us
));
896 us
->setRootQueue(result
);
899 if (kIODKLogSetup
& gIODKDebug
) {
900 DKLOG("IODispatchQueue::Create %s %p\n", name
, result
);
903 return kIOReturnSuccess
;
907 IMPL(IODispatchQueue
, SetPort
)
909 ivars
->serverPort
= port
;
910 return kIOReturnSuccess
;
914 IODispatchQueue::init()
916 ivars
= IONewZero(IODispatchQueue_IVars
, 1);
926 IODispatchQueue::free()
928 IOSafeDeleteNULL(ivars
, IODispatchQueue_IVars
, 1);
933 IODispatchQueue::OnQueue()
938 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
942 OSMetaClassBase::Dispatch(IORPC rpc
)
944 return kIOReturnUnsupported
;
948 OSMetaClassBase::Invoke(IORPC rpc
)
950 IOReturn ret
= kIOReturnUnsupported
;
951 OSMetaClassBase
* object
;
955 IORPCMessage
* message
;
957 assert(rpc
.sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
958 message
= IORPCMessageFromMach(rpc
.message
, false);
960 return kIOReturnIPCError
;
962 message
->flags
|= kIORPCMessageKernel
;
965 if (!(kIORPCMessageLocalHost
& message
->flags
)) {
966 us
= OSDynamicCast(IOUserServer
, this);
968 if ((action
= OSDynamicCast(OSAction
, this))) {
969 object
= IOUserServer::target(action
, message
);
973 if ((service
= OSDynamicCast(IOService
, object
))
974 && service
->reserved
->uvars
) {
976 us
= service
->reserved
->uvars
->userServer
;
981 message
->flags
|= kIORPCMessageRemote
;
983 if (kIOReturnSuccess
!= ret
) {
984 if (kIODKLogIPC
& gIODKDebug
) {
985 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret
);
989 if (kIODKLogIPC
& gIODKDebug
) {
990 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message
->msgid
);
998 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1003 const char strings
[0];
1007 OSUserMetaClass::Dispatch(IORPC rpc
)
1009 return const_cast<OSMetaClass
*>(meta
)->Dispatch(rpc
);
1013 OSUserMetaClass::free()
1016 IOFree(queueNames
, sizeof(IOPStrings
) + queueNames
->dataSize
* sizeof(char));
1020 IOFree(description
, description
->descriptionSize
);
1023 IOSafeDeleteNULL(methods
, uint64_t, 2 * methodCount
);
1025 meta
->releaseMetaClass();
1034 * Sets the loadTag of the associated OSKext
1036 * NOTE: different instances of the same OSKext
1037 * (so same BounleID but different tasks)
1038 * will have the same loadTag.
1041 IOUserServer::setTaskLoadTag(OSKext
*kext
)
1044 uint32_t loadTag
, prev_taskloadTag
;
1046 owningTask
= this->fOwningTask
;
1048 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1052 loadTag
= kext
->getLoadTag();
1053 prev_taskloadTag
= set_task_loadTag(owningTask
, loadTag
);
1054 if (prev_taskloadTag
) {
1055 printf("%s: found the task loadTag already set to %u (set to %u)\n",
1056 __FUNCTION__
, prev_taskloadTag
, loadTag
);
1061 * Sets the OSKext uuid as the uuid of the userspace
1065 IOUserServer::setDriverKitUUID(OSKext
*kext
)
1069 uuid_t p_uuid
, k_uuid
;
1070 OSData
*k_data_uuid
;
1072 uuid_string_t uuid_string
= "";
1074 task
= this->fOwningTask
;
1076 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1080 p
= (proc_t
)(get_bsdtask_info(task
));
1082 printf("%s: proc not found\n", __FUNCTION__
);
1085 proc_getexecutableuuid(p
, p_uuid
, sizeof(p_uuid
));
1087 k_data_uuid
= kext
->copyUUID();
1089 memcpy(&k_uuid
, k_data_uuid
->getBytesNoCopy(), sizeof(k_uuid
));
1090 OSSafeReleaseNULL(k_data_uuid
);
1091 if (uuid_compare(k_uuid
, p_uuid
) != 0) {
1092 printf("%s: uuid not matching\n", __FUNCTION__
);
1097 uuid_unparse(p_uuid
, uuid_string
);
1098 new_uuid
= OSData::withBytes(p_uuid
, sizeof(p_uuid
));
1099 kext
->setDriverKitUUID(new_uuid
);
1103 IOUserServer::serviceMatchesCDHash(IOService
*service
)
1105 OSObject
*obj
= NULL
;
1106 bool result
= false;
1107 OSString
*requiredCDHashStr
= NULL
;
1108 const char *requiredCDHash
= NULL
;
1109 char taskCDHash
[CS_CDHASH_LEN
];
1111 task_t owningTask
= this->fOwningTask
;
1113 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1117 obj
= service
->copyProperty(gIOUserServerCDHashKey
);
1118 requiredCDHashStr
= OSDynamicCast(OSString
, obj
);
1119 if (!requiredCDHashStr
) {
1120 printf("%s: required cdhash not found as property of personality\n", __FUNCTION__
);
1124 requiredCDHash
= requiredCDHashStr
->getCStringNoCopy();
1125 if (!requiredCDHash
) {
1126 printf("%s: required cdhash unable to be read as string\n", __FUNCTION__
);
1130 if (strlen(requiredCDHash
) != CS_CDHASH_LEN
* 2) {
1131 printf("%s: required cdhash string has incorrect length\n", __FUNCTION__
);
1135 get_task_cdhash(owningTask
, taskCDHash
);
1136 for (int i
= 0; i
< (int)CS_CDHASH_LEN
* 2; i
++) {
1137 uint8_t which
= (i
+ 1) & 0x1; /* 1 for upper nibble, 0 for lower */
1138 uint8_t nibble
= requiredCDHash
[i
];
1139 uint8_t byte
= taskCDHash
[i
/ 2];
1140 if ('0' <= nibble
&& nibble
<= '9') {
1142 } else if ('a' <= nibble
&& nibble
<= 'f') {
1144 } else if ('A' <= nibble
&& nibble
<= 'F') {
1147 printf("%s: required cdhash contains invalid token '%c'\n", __FUNCTION__
, nibble
);
1152 * Decide which half of the byte to compare
1154 if (nibble
!= (which
? (byte
>> 4) : (byte
& 0x0f))) {
1155 printf("%s: required cdhash %s in personality does not match service\n", __FUNCTION__
, requiredCDHash
);
1162 OSSafeReleaseNULL(obj
);
1167 IOUserServer::checkEntitlements(
1168 OSDictionary
* entitlements
, OSObject
* prop
,
1169 IOService
* provider
, IOService
* dext
)
1171 OSDictionary
* matching
;
1176 if (!entitlements
) {
1182 matching
= dext
->dictionaryWithProperties();
1188 bool allPresent __block
;
1189 prop
->iterateObjects(^bool (OSObject
* object
) {
1191 object
->iterateObjects(^bool (OSObject
* object
) {
1194 string
= OSDynamicCast(OSString
, object
);
1195 value
= entitlements
->getObject(string
);
1196 if (matching
&& value
) {
1197 matching
->setObject(string
, value
);
1199 allPresent
= (NULL
!= value
);
1205 if (allPresent
&& matching
&& provider
) {
1206 allPresent
= provider
->matchPropertyTable(matching
);
1209 OSSafeReleaseNULL(matching
);
1210 OSSafeReleaseNULL(prop
);
1216 IOUserServer::checkEntitlements(IOService
* provider
, IOService
* dext
)
1225 prop
= provider
->copyProperty(gIOServiceDEXTEntitlementsKey
);
1226 ok
= checkEntitlements(fEntitlements
, prop
, provider
, dext
);
1228 DKLOG(DKS
": provider entitlements check failed\n", DKN(dext
));
1231 prop
= dext
->copyProperty(gIOServiceDEXTEntitlementsKey
);
1232 ok
= checkEntitlements(fEntitlements
, prop
, NULL
, NULL
);
1234 DKLOG(DKS
": family entitlements check failed\n", DKN(dext
));
1242 IOUserServer::exit(const char * reason
)
1244 DKLOG("%s::exit(%s)\n", getName(), reason
);
1246 return kIOReturnSuccess
;
1250 IOUserServer::varsForObject(OSObject
* obj
)
1252 IOService
* service
;
1254 if ((service
= OSDynamicCast(IOService
, obj
))) {
1255 return service
->reserved
->uvars
;
1262 IOUserServer::copyInStringArray(const char * string
, uint32_t userSize
)
1270 if (userSize
<= 1) {
1274 if (os_add_overflow(sizeof(IOPStrings
), userSize
, &alloc
)) {
1278 if (alloc
> 16384) {
1282 array
= (typeof(array
))IOMalloc(alloc
);
1286 array
->dataSize
= userSize
;
1287 bcopy(string
, (void *) &array
->strings
[0], userSize
);
1290 cstr
= &array
->strings
[0];
1291 end
= &array
->strings
[array
->dataSize
];
1292 while ((len
= cstr
[0])) {
1294 if ((cstr
+ len
) >= end
) {
1301 IOFree(array
, alloc
);
1309 IOUserServer::stringArrayIndex(IOPStrings
* array
, const char * look
)
1317 cstr
= &array
->strings
[0];
1318 end
= &array
->strings
[array
->dataSize
];
1319 llen
= strlen(look
);
1320 while ((len
= cstr
[0])) {
1322 if ((cstr
+ len
) >= end
) {
1325 if ((len
== llen
) && !strncmp(cstr
, look
, len
)) {
1334 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
1337 IOUserServer::queueForObject(OSObject
* obj
, uint64_t msgid
)
1339 IODispatchQueue
* queue
;
1340 OSObjectUserVars
* uvars
;
1343 uvars
= varsForObject(obj
);
1347 if (!uvars
->queueArray
) {
1348 if (uvars
->stopped
) {
1349 return kIODispatchQueueStopped
;
1353 queue
= uvars
->queueArray
[0];
1356 && uvars
->userMeta
->methods
) {
1357 uint32_t idx
, baseIdx
;
1360 for (baseIdx
= 0, lim
= uvars
->userMeta
->methodCount
; lim
; lim
>>= 1) {
1361 idx
= baseIdx
+ (lim
>> 1);
1362 if (msgid
== uvars
->userMeta
->methods
[idx
]) {
1363 option
= uvars
->userMeta
->methods
[uvars
->userMeta
->methodCount
+ idx
];
1365 if (option
< uvars
->userMeta
->queueNames
->count
) {
1366 queue
= uvars
->queueArray
[option
+ 1];
1369 } else if (msgid
> uvars
->userMeta
->methods
[idx
]) {
1371 baseIdx
+= (lim
>> 1) + 1;
1381 IOUserServer::objectInstantiate(OSObject
* obj
, IORPC rpc
, IORPCMessage
* message
)
1386 IOService
* service
;
1390 uint32_t queueCount
, queueAlloc
;
1391 const char * resultClassName
;
1392 uint64_t resultFlags
;
1395 uint32_t methodCount
;
1396 const uint64_t * methods
;
1397 IODispatchQueue
* queue
;
1398 OSUserMetaClass
* userMeta
;
1399 OSObjectUserVars
* uvars
;
1401 ipc_port_t sendPort
;
1403 OSObject_Instantiate_Rpl_Content
* reply
;
1411 resultClassName
= NULL
;
1413 ret
= kIOReturnUnsupportedMode
;
1415 service
= OSDynamicCast(IOService
, obj
);
1417 // xxx other classes hosted
1418 resultFlags
|= kOSObjectRPCKernel
;
1419 resultFlags
|= kOSObjectRPCRemote
;
1421 if (service
->isInactive()) {
1422 DKLOG(DKS
"::instantiate inactive\n", DKN(service
));
1423 return kIOReturnOffline
;
1425 prop
= service
->copyProperty(gIOUserClassKey
);
1426 str
= OSDynamicCast(OSString
, prop
);
1427 if (!service
->reserved
->uvars
) {
1428 resultFlags
|= kOSObjectRPCRemote
;
1429 resultFlags
|= kOSObjectRPCKernel
;
1430 } else if (this != service
->reserved
->uvars
->userServer
) {
1431 // remote, use base class
1432 resultFlags
|= kOSObjectRPCRemote
;
1434 if (service
->reserved
->uvars
&& service
->reserved
->uvars
->userServer
) {
1435 userMeta
= (typeof(userMeta
))service
->reserved
->uvars
->userServer
->fClasses
->getObject(str
);
1438 if (!str
&& !userMeta
) {
1439 const OSMetaClass
* meta
;
1440 meta
= obj
->getMetaClass();
1441 while (meta
&& !userMeta
) {
1442 str
= (OSString
*) meta
->getClassNameSymbol();
1443 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
1445 meta
= meta
->getSuperClass();
1451 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
1453 if (kIODKLogSetup
& gIODKDebug
) {
1454 DKLOG("userMeta %s %p\n", str
->getCStringNoCopy(), userMeta
);
1457 if (kOSObjectRPCRemote
& resultFlags
) {
1458 while (userMeta
&& !(kOSClassCanRemote
& userMeta
->description
->flags
)) {
1459 userMeta
= userMeta
->superMeta
;
1462 resultClassName
= userMeta
->description
->name
;
1463 ret
= kIOReturnSuccess
;
1466 service
->reserved
->uvars
->userMeta
= userMeta
;
1468 if (userMeta
->queueNames
) {
1469 queueAlloc
+= userMeta
->queueNames
->count
;
1471 service
->reserved
->uvars
->queueArray
=
1472 IONewZero(IODispatchQueue
*, queueAlloc
);
1473 resultClassName
= str
->getCStringNoCopy();
1474 ret
= kIOReturnSuccess
;
1478 OSSafeReleaseNULL(prop
);
1480 IORPCMessageMach
* machReply
= rpc
.reply
;
1481 replySize
= sizeof(OSObject_Instantiate_Rpl
);
1483 if ((kIOReturnSuccess
== ret
) && (kOSObjectRPCRemote
& resultFlags
)) {
1485 if ((action
= OSDynamicCast(OSAction
, obj
))) {
1486 if (action
->ivars
->referenceSize
) {
1487 resultFlags
|= kOSObjectRPCKernel
;
1489 resultFlags
&= ~kOSObjectRPCKernel
;
1490 target
= action
->ivars
->target
;
1493 queue
= queueForObject(target
, action
->ivars
->targetmsgid
);
1496 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
1497 sendPort
= ipc_port_make_send(queue
->ivars
->serverPort
);
1499 replySize
= sizeof(OSObject_Instantiate_Rpl
)
1500 + queueCount
* sizeof(machReply
->objects
[0])
1501 + 2 * methodCount
* sizeof(reply
->methods
[0]);
1502 if (replySize
> rpc
.replySize
) {
1504 return kIOReturnIPCError
;
1506 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
1507 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1508 machReply
->objects
[idx
].name
= sendPort
;
1509 machReply
->objects
[idx
].pad2
= 0;
1510 machReply
->objects
[idx
].pad_end
= 0;
1513 uvars
= varsForObject(target
);
1514 if (uvars
&& uvars
->userMeta
) {
1516 if (uvars
->userMeta
->queueNames
) {
1517 queueCount
+= uvars
->userMeta
->queueNames
->count
;
1519 methods
= &uvars
->userMeta
->methods
[0];
1520 methodCount
= uvars
->userMeta
->methodCount
;
1521 replySize
= sizeof(OSObject_Instantiate_Rpl
)
1522 + queueCount
* sizeof(machReply
->objects
[0])
1523 + 2 * methodCount
* sizeof(reply
->methods
[0]);
1524 if (replySize
> rpc
.replySize
) {
1526 return kIOReturnIPCError
;
1528 for (idx
= 0; idx
< queueCount
; idx
++) {
1529 queue
= uvars
->queueArray
[idx
];
1532 sendPort
= ipc_port_make_send(queue
->ivars
->serverPort
);
1534 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
1535 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1536 machReply
->objects
[idx
].name
= sendPort
;
1537 machReply
->objects
[idx
].pad2
= 0;
1538 machReply
->objects
[idx
].pad_end
= 0;
1544 if (kIODKLogIPC
& gIODKDebug
) {
1545 DKLOG("instantiate %s\n", obj
->getMetaClass()->getClassName());
1548 if (kIOReturnSuccess
!= ret
) {
1549 DKLOG("%s: no user class found\n", str
? str
->getCStringNoCopy() : obj
->getMetaClass()->getClassName());
1550 resultClassName
= "unknown";
1553 machReply
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
1554 machReply
->msgh
.msgh_size
= replySize
;
1555 machReply
->msgh_body
.msgh_descriptor_count
= queueCount
;
1557 reply
= (typeof(reply
))IORPCMessageFromMach(machReply
, true);
1559 return kIOReturnIPCError
;
1562 bcopy(methods
, &reply
->methods
[0], methodCount
* 2 * sizeof(reply
->methods
[0]));
1564 reply
->__hdr
.msgid
= OSObject_Instantiate_ID
;
1565 reply
->__hdr
.flags
= kIORPCMessageOneway
;
1566 reply
->__hdr
.objectRefs
= 0;
1568 reply
->flags
= resultFlags
;
1569 strlcpy(reply
->classname
, resultClassName
, sizeof(reply
->classname
));
1570 reply
->__result
= ret
;
1572 ret
= kIOReturnSuccess
;
1577 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1580 IOUserServer::kernelDispatch(OSObject
* obj
, IORPC rpc
)
1583 IORPCMessage
* message
;
1585 message
= IORPCMessageFromMach(rpc
.message
, false);
1587 return kIOReturnIPCError
;
1590 if (OSObject_Instantiate_ID
== message
->msgid
) {
1591 ret
= objectInstantiate(obj
, rpc
, message
);
1592 if (kIOReturnSuccess
!= ret
) {
1593 DKLOG("%s: instantiate failed 0x%x\n", obj
->getMetaClass()->getClassName(), ret
);
1596 if (kIODKLogIPC
& gIODKDebug
) {
1597 DKLOG("%s::Dispatch kernel 0x%qx\n", obj
->getMetaClass()->getClassName(), message
->msgid
);
1599 ret
= obj
->Dispatch(rpc
);
1600 if (kIODKLogIPC
& gIODKDebug
) {
1601 DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj
->getMetaClass()->getClassName(), message
->msgid
, ret
);
1609 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1612 IOUserServer::target(OSAction
* action
, IORPCMessage
* message
)
1616 if (message
->msgid
!= action
->ivars
->msgid
) {
1619 object
= action
->ivars
->target
;
1620 message
->msgid
= action
->ivars
->targetmsgid
;
1621 message
->objects
[0] = (OSObjectRef
) object
;
1622 if (kIORPCMessageRemote
& message
->flags
) {
1626 if (kIODKLogIPC
& gIODKDebug
) {
1627 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
, action
->ivars
->msgid
);
1633 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1636 uext_server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
1639 IORPCMessageMach
* msgin
;
1641 IOUserServer
* server
;
1643 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
1645 object
= IOUserServer::copyObjectForSendRight(msgin
->msgh
.msgh_remote_port
, IKOT_UEXT_OBJECT
);
1646 server
= OSDynamicCast(IOUserServer
, object
);
1648 OSSafeReleaseNULL(object
);
1649 return KERN_INVALID_NAME
;
1651 ret
= server
->server(requestkmsg
, pReply
);
1657 #define MAX_UEXT_REPLY_SIZE 0x17c0
1660 IOUserServer::server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
1663 mach_msg_size_t replyAlloc
;
1664 ipc_kmsg_t replykmsg
;
1665 IORPCMessageMach
* msgin
;
1666 IORPCMessage
* message
;
1667 IORPCMessageMach
* msgout
;
1668 IORPCMessage
* reply
;
1675 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
1680 if (msgin
->msgh
.msgh_size
< (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
1681 if (kIODKLogIPC
& gIODKDebug
) {
1682 DKLOG("UEXT notify %o\n", msgin
->msgh
.msgh_id
);
1684 return KERN_NOT_SUPPORTED
;
1687 if (!(MACH_MSGH_BITS_COMPLEX
& msgin
->msgh
.msgh_bits
)) {
1688 msgin
->msgh_body
.msgh_descriptor_count
= 0;
1690 message
= IORPCMessageFromMach(msgin
, false);
1692 return kIOReturnIPCError
;
1694 ret
= copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, true, false);
1695 if (kIOReturnSuccess
!= ret
) {
1696 if (kIODKLogIPC
& gIODKDebug
) {
1697 DKLOG("UEXT copyin(0x%x) %x\n", ret
, msgin
->msgh
.msgh_id
);
1699 return KERN_NOT_SUPPORTED
;
1702 if (msgin
->msgh_body
.msgh_descriptor_count
< 1) {
1703 return KERN_NOT_SUPPORTED
;
1705 object
= (OSObject
*) message
->objects
[0];
1706 msgid
= message
->msgid
;
1707 message
->flags
&= ~kIORPCMessageKernel
;
1708 message
->flags
|= kIORPCMessageRemote
;
1710 if ((action
= OSDynamicCast(OSAction
, object
))) {
1711 object
= target(action
, message
);
1712 msgid
= message
->msgid
;
1715 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
1716 assert(oneway
|| (MACH_PORT_NULL
!= msgin
->msgh
.msgh_local_port
));
1718 // includes trailer size
1719 replyAlloc
= oneway
? 0 : MAX_UEXT_REPLY_SIZE
;
1721 replykmsg
= ipc_kmsg_alloc(replyAlloc
);
1722 if (replykmsg
== NULL
) {
1723 // printf("uext_server: dropping request\n");
1724 // ipc_kmsg_trace_send(request, option);
1725 consumeObjects(message
, msgin
->msgh
.msgh_size
);
1726 ipc_kmsg_destroy(requestkmsg
);
1727 return KERN_MEMORY_FAILURE
;
1730 msgout
= (typeof(msgout
))ipc_kmsg_msg_header(replykmsg
);
1732 * MIG should really assure no data leakage -
1733 * but until it does, pessimistically zero the
1734 * whole reply buffer.
1736 bzero((void *)msgout
, replyAlloc
);
1739 IORPC rpc
= { .message
= msgin
, .sendSize
= msgin
->msgh
.msgh_size
, .reply
= msgout
, .replySize
= replyAlloc
};
1742 thread_iokit_tls_set(0, this);
1743 ret
= kernelDispatch(object
, rpc
);
1744 thread_iokit_tls_set(0, NULL
);
1746 ret
= kIOReturnBadArgument
;
1750 consumeObjects(message
, msgin
->msgh
.msgh_size
);
1753 copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, false, true);
1756 if (kIOReturnSuccess
== ret
) {
1757 replySize
= msgout
->msgh
.msgh_size
;
1758 reply
= IORPCMessageFromMach(msgout
, true);
1760 ret
= kIOReturnIPCError
;
1762 ret
= copyOutObjects(msgout
, reply
, replySize
, (kIORPCVersionCurrentReply
== msgout
->msgh
.msgh_id
) /* =>!InvokeReply */);
1765 if (kIOReturnSuccess
!= ret
) {
1766 IORPCMessageErrorReturnContent
* errorMsg
;
1768 msgout
->msgh_body
.msgh_descriptor_count
= 0;
1769 msgout
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
1770 errorMsg
= (typeof(errorMsg
))IORPCMessageFromMach(msgout
, true);
1771 errorMsg
->hdr
.msgid
= message
->msgid
;
1772 errorMsg
->hdr
.flags
= kIORPCMessageOneway
| kIORPCMessageError
;
1773 errorMsg
->hdr
.objectRefs
= 0;
1774 errorMsg
->result
= ret
;
1776 replySize
= sizeof(IORPCMessageErrorReturn
);
1779 msgout
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
1780 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin
->msgh
.msgh_bits
) /*remote*/, 0 /*local*/, 0, 0);
1782 msgout
->msgh
.msgh_remote_port
= msgin
->msgh
.msgh_local_port
;
1783 msgout
->msgh
.msgh_local_port
= MACH_PORT_NULL
;
1784 msgout
->msgh
.msgh_voucher_port
= (mach_port_name_t
) 0;
1785 msgout
->msgh
.msgh_reserved
= 0;
1786 msgout
->msgh
.msgh_size
= replySize
;
1789 *pReply
= replykmsg
;
1791 return oneway
? MIG_NO_REPLY
: KERN_SUCCESS
;
1794 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1796 #define MAX_OBJECT_COUNT(mach, size, message) \
1797 ((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))
1800 IOUserServerUEXTTrap(OSObject
* object
, void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
1802 const user_addr_t msg
= (uintptr_t) p1
;
1803 size_t inSize
= (uintptr_t) p2
;
1804 user_addr_t out
= (uintptr_t) p3
;
1805 size_t outSize
= (uintptr_t) p4
;
1806 mach_port_name_t objectName1
= (uintptr_t) p5
;
1808 OSObject
* objectArg1
;
1810 IORPCMessageMach
* mach
;
1811 mach_msg_port_descriptor_t
* descs
;
1816 IORPCMessageMach mach
;
1817 mach_msg_port_descriptor_t objects
[2];
1818 IOTrapMessageBuffer buffer
;
1825 IORPCMessage
* message
;
1826 IORPCMessage
* reply
;
1829 uint32_t maxObjectCount
;
1831 uint64_t * replyHdr
;
1834 bzero(&buffer
, sizeof(buffer
));
1836 p
= (typeof(p
)) & buffer
.buffer
[0];
1837 if (os_add_overflow(inSize
, outSize
, &totalSize
)) {
1838 return kIOReturnMessageTooLarge
;
1840 if (totalSize
> sizeof(buffer
.buffer
)) {
1841 return kIOReturnMessageTooLarge
;
1843 if (inSize
< sizeof(IORPCMessage
)) {
1844 return kIOReturnIPCError
;
1846 copyerr
= copyin(msg
, &buffer
.buffer
[0], inSize
);
1848 return kIOReturnVMError
;
1851 message
= (typeof(message
))p
;
1852 refs
= message
->objectRefs
;
1853 if ((refs
> 2) || !refs
) {
1854 return kIOReturnUnsupported
;
1856 if (!(kIORPCMessageSimpleReply
& message
->flags
)) {
1857 return kIOReturnUnsupported
;
1860 descs
= (typeof(descs
))(p
- refs
* sizeof(*descs
));
1861 mach
= (typeof(mach
))(p
- refs
* sizeof(*descs
) - sizeof(*mach
));
1863 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
1864 mach
->msgh
.msgh_size
= sizeof(IORPCMessageMach
) + refs
* sizeof(*descs
) + inSize
;
1865 mach
->msgh_body
.msgh_descriptor_count
= refs
;
1868 rpc
.sendSize
= mach
->msgh
.msgh_size
;
1869 rpc
.reply
= (IORPCMessageMach
*) (p
+ inSize
);
1870 rpc
.replySize
= sizeof(buffer
.buffer
) - inSize
;
1872 message
->objects
[0] = 0;
1873 if ((action
= OSDynamicCast(OSAction
, object
))) {
1874 maxObjectCount
= MAX_OBJECT_COUNT(rpc
.message
, rpc
.sendSize
, message
);
1875 if (refs
> maxObjectCount
) {
1876 return kIOReturnBadArgument
;
1878 object
= IOUserServer::target(action
, message
);
1879 message
->objects
[1] = (OSObjectRef
) action
;
1880 if (kIODKLogIPC
& gIODKDebug
) {
1881 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
1883 ret
= object
->Dispatch(rpc
);
1887 objectArg1
= iokit_lookup_uext_ref_current_task(objectName1
);
1889 return kIOReturnIPCError
;
1891 message
->objects
[1] = (OSObjectRef
) objectArg1
;
1893 if (kIODKLogIPC
& gIODKDebug
) {
1894 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
1896 ret
= object
->Dispatch(rpc
);
1897 if (kIODKLogIPC
& gIODKDebug
) {
1898 DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object
->getMetaClass()->getClassName(), message
->msgid
, ret
);
1900 OSSafeReleaseNULL(objectArg1
);
1902 if (kIOReturnSuccess
== ret
) {
1903 if (rpc
.reply
->msgh_body
.msgh_descriptor_count
) {
1904 return kIOReturnIPCError
;
1906 reply
= IORPCMessageFromMach(rpc
.reply
, rpc
.reply
->msgh
.msgh_size
);
1908 return kIOReturnIPCError
;
1910 copySize
= rpc
.reply
->msgh
.msgh_size
- (((uintptr_t) reply
) - ((uintptr_t) rpc
.reply
)) + sizeof(uint64_t);
1911 if (copySize
> outSize
) {
1912 return kIOReturnIPCError
;
1914 replyHdr
= (uint64_t *) reply
;
1916 replyHdr
[0] = copySize
;
1917 copyerr
= copyout(replyHdr
, out
, copySize
);
1919 return kIOReturnVMError
;
1927 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1930 IOUserServer::rpc(IORPC rpc
)
1932 if (isInactive() && !fRootQueue
) {
1933 return kIOReturnOffline
;
1937 IORPCMessage
* message
;
1938 IORPCMessageMach
* mach
;
1939 mach_msg_id_t machid
;
1940 uint32_t sendSize
, replySize
;
1943 IODispatchQueue
* queue
;
1944 IOService
* service
;
1946 ipc_port_t sendPort
;
1953 sendSize
= rpc
.sendSize
;
1954 replySize
= rpc
.replySize
;
1956 assert(sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
1958 message
= IORPCMessageFromMach(mach
, false);
1960 ret
= kIOReturnIPCError
;
1962 msgid
= message
->msgid
;
1963 machid
= (msgid
>> 32);
1965 if (mach
->msgh_body
.msgh_descriptor_count
< 1) {
1966 return kIOReturnNoMedia
;
1969 IOLockLock(gIOUserServerLock
);
1970 if ((service
= OSDynamicCast(IOService
, (OSObject
*) message
->objects
[0]))) {
1971 queue
= queueForObject(service
, msgid
);
1976 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
1977 port
= queue
->ivars
->serverPort
;
1980 sendPort
= ipc_port_make_send(port
);
1982 IOLockUnlock(gIOUserServerLock
);
1984 return kIOReturnNotReady
;
1987 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
1989 ret
= copyOutObjects(mach
, message
, sendSize
, false);
1991 mach
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
1992 MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND
, (oneway
? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE
));
1993 mach
->msgh
.msgh_remote_port
= sendPort
;
1994 mach
->msgh
.msgh_local_port
= (oneway
? MACH_PORT_NULL
: mig_get_reply_port());
1995 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
1996 mach
->msgh
.msgh_reserved
= 0;
1999 ret
= mach_msg_send_from_kernel(&mach
->msgh
, sendSize
);
2001 assert(replySize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
2002 ret
= mach_msg_rpc_from_kernel(&mach
->msgh
, sendSize
, replySize
);
2003 if (KERN_SUCCESS
== ret
) {
2004 if (kIORPCVersionCurrentReply
!= mach
->msgh
.msgh_id
) {
2005 ret
= (MACH_NOTIFY_SEND_ONCE
== mach
->msgh
.msgh_id
) ? MIG_SERVER_DIED
: MIG_REPLY_MISMATCH
;
2006 } else if ((replySize
= mach
->msgh
.msgh_size
) < (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
2007 // printf("BAD REPLY SIZE\n");
2008 ret
= MIG_BAD_ARGUMENTS
;
2010 if (!(MACH_MSGH_BITS_COMPLEX
& mach
->msgh
.msgh_bits
)) {
2011 mach
->msgh_body
.msgh_descriptor_count
= 0;
2013 message
= IORPCMessageFromMach(mach
, true);
2015 ret
= kIOReturnIPCError
;
2016 } else if (message
->msgid
!= msgid
) {
2017 // printf("BAD REPLY ID\n");
2018 ret
= MIG_BAD_ARGUMENTS
;
2020 bool isError
= (0 != (kIORPCMessageError
& message
->flags
));
2021 ret
= copyInObjects(mach
, message
, replySize
, !isError
, true);
2022 if (kIOReturnSuccess
!= ret
) {
2023 if (kIODKLogIPC
& gIODKDebug
) {
2024 DKLOG("rpc copyin(0x%x) %x\n", ret
, mach
->msgh
.msgh_id
);
2026 return KERN_NOT_SUPPORTED
;
2029 IORPCMessageErrorReturnContent
* errorMsg
= (typeof(errorMsg
))message
;
2030 ret
= errorMsg
->result
;
2040 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2043 IORPCMessageFromMach(IORPCMessageMach
* msg
, bool reply
)
2045 mach_msg_size_t idx
, count
;
2046 mach_msg_port_descriptor_t
* desc
;
2047 mach_msg_port_descriptor_t
* maxDesc
;
2048 size_t size
, msgsize
;
2051 msgsize
= msg
->msgh
.msgh_size
;
2052 count
= msg
->msgh_body
.msgh_descriptor_count
;
2053 desc
= &msg
->objects
[0];
2054 maxDesc
= (typeof(maxDesc
))(((uintptr_t) msg
) + msgsize
);
2055 upgrade
= (msg
->msgh
.msgh_id
!= (reply
? kIORPCVersionCurrentReply
: kIORPCVersionCurrent
));
2058 OSReportWithBacktrace("obsolete message");
2062 for (idx
= 0; idx
< count
; idx
++) {
2063 if (desc
>= maxDesc
) {
2066 switch (desc
->type
) {
2067 case MACH_MSG_PORT_DESCRIPTOR
:
2068 size
= sizeof(mach_msg_port_descriptor_t
);
2070 case MACH_MSG_OOL_DESCRIPTOR
:
2071 size
= sizeof(mach_msg_ool_descriptor_t
);
2076 desc
= (typeof(desc
))(((uintptr_t) desc
) + size
);
2078 return (IORPCMessage
*)(uintptr_t) desc
;
2082 IOUserServer::copySendRightForObject(OSObject
* object
, ipc_kobject_type_t type
)
2085 ipc_port_t sendPort
= NULL
;
2087 port
= iokit_port_for_object(object
, type
);
2089 sendPort
= ipc_port_make_send(port
);
2090 iokit_release_port(port
);
2097 IOUserServer::copyObjectForSendRight(ipc_port_t port
, ipc_kobject_type_t type
)
2100 object
= iokit_lookup_io_object(port
, type
);
2104 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2106 // Create a vm_map_copy_t or kalloc'ed data for memory
2107 // to be copied out. ipc will free after the copyout.
2109 static kern_return_t
2110 copyoutkdata(const void * data
, vm_size_t len
, void ** buf
)
2115 err
= vm_map_copyin( kernel_map
, CAST_USER_ADDR_T(data
), len
,
2116 false /* src_destroy */, ©
);
2118 assert( err
== KERN_SUCCESS
);
2119 if (err
== KERN_SUCCESS
) {
2120 *buf
= (char *) copy
;
2126 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2129 IOUserServer::copyOutObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
2130 size_t size
, bool consume
)
2133 uint32_t idx
, maxObjectCount
;
2137 mach_msg_port_descriptor_t
* desc
;
2138 mach_msg_ool_descriptor_t
* ool
;
2141 mach_msg_size_t length
;
2145 refs
= message
->objectRefs
;
2146 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
2147 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2148 // assert(refs <= maxObjectCount);
2149 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
2150 return kIOReturnBadArgument
;
2152 if (refs
> maxObjectCount
) {
2153 return kIOReturnBadArgument
;
2156 desc
= &mach
->objects
[0];
2157 for (idx
= 0; idx
< refs
; idx
++) {
2158 object
= (OSObject
*) message
->objects
[idx
];
2160 switch (desc
->type
) {
2161 case MACH_MSG_PORT_DESCRIPTOR
:
2162 descsize
= sizeof(mach_msg_port_descriptor_t
);
2165 port
= copySendRightForObject(object
, IKOT_UEXT_OBJECT
);
2172 message
->objects
[idx
] = 0;
2174 // desc->type = MACH_MSG_PORT_DESCRIPTOR;
2175 desc
->disposition
= MACH_MSG_TYPE_MOVE_SEND
;
2181 case MACH_MSG_OOL_DESCRIPTOR
:
2182 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2187 s
= OSSerialize::binaryWithCapacity(4096);
2192 s
->setIndexed(true);
2193 if (!object
->serialize(s
)) {
2199 length
= s
->getLength();
2200 kr
= copyoutkdata(s
->text(), length
, &address
);
2202 if (KERN_SUCCESS
!= kr
) {
2210 message
->objects
[idx
] = 0;
2212 ool
= (typeof(ool
))desc
;
2213 // ool->type = MACH_MSG_OOL_DESCRIPTOR;
2214 ool
->deallocate
= false;
2215 ool
->copy
= MACH_MSG_PHYSICAL_COPY
;
2217 ool
->address
= address
;
2224 if (-1UL == descsize
) {
2227 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2231 return kIOReturnSuccess
;
2234 desc
= &mach
->objects
[0];
2236 switch (desc
->type
) {
2237 case MACH_MSG_PORT_DESCRIPTOR
:
2238 descsize
= sizeof(mach_msg_port_descriptor_t
);
2241 ipc_port_release_send(port
);
2245 case MACH_MSG_OOL_DESCRIPTOR
:
2246 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2247 ool
= (typeof(ool
))desc
;
2248 copy
= (vm_map_copy_t
) ool
->address
;
2250 vm_map_copy_discard(copy
);
2258 if (-1UL == descsize
) {
2261 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2264 return kIOReturnBadArgument
;
2268 IOUserServer::copyInObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
2269 size_t size
, bool copyObjects
, bool consumePorts
)
2272 uint32_t idx
, maxObjectCount
;
2276 mach_msg_port_descriptor_t
* desc
;
2277 mach_msg_ool_descriptor_t
* ool
;
2278 vm_map_address_t copyoutdata
;
2281 refs
= message
->objectRefs
;
2282 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
2283 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2284 // assert(refs <= maxObjectCount);
2285 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
2286 return kIOReturnBadArgument
;
2288 if (refs
> maxObjectCount
) {
2289 return kIOReturnBadArgument
;
2292 desc
= &mach
->objects
[0];
2293 for (idx
= 0; idx
< refs
; idx
++) {
2294 switch (desc
->type
) {
2295 case MACH_MSG_PORT_DESCRIPTOR
:
2296 descsize
= sizeof(mach_msg_port_descriptor_t
);
2302 object
= copyObjectForSendRight(port
, IKOT_UEXT_OBJECT
);
2309 ipc_port_release_send(port
);
2314 case MACH_MSG_OOL_DESCRIPTOR
:
2315 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2316 ool
= (typeof(ool
))desc
;
2319 if (copyObjects
&& ool
->size
&& ool
->address
) {
2320 kr
= vm_map_copyout(kernel_map
, ©outdata
, (vm_map_copy_t
) ool
->address
);
2321 if (KERN_SUCCESS
== kr
) {
2322 object
= OSUnserializeXML((const char *) copyoutdata
, ool
->size
);
2323 // vm_map_copyout() has consumed the vm_map_copy_t in the message
2325 ool
->address
= NULL
;
2326 kr
= vm_deallocate(kernel_map
, copyoutdata
, ool
->size
);
2327 assert(KERN_SUCCESS
== kr
);
2340 if (-1UL == descsize
) {
2344 message
->objects
[idx
] = (OSObjectRef
) object
;
2346 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2350 return kIOReturnSuccess
;
2354 object
= (OSObject
*) message
->objects
[idx
];
2356 message
->objects
[idx
] = 0;
2359 return kIOReturnBadArgument
;
2363 IOUserServer::consumeObjects(IORPCMessage
* message
, size_t messageSize
)
2368 refs
= message
->objectRefs
;
2369 for (idx
= 0; idx
< refs
; idx
++) {
2370 object
= (OSObject
*) message
->objects
[idx
];
2373 message
->objects
[idx
] = 0;
2377 return kIOReturnSuccess
;
2380 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2383 IOUserServer::finalize(IOOptionBits options
)
2387 if (kIODKLogSetup
& gIODKDebug
) {
2388 DKLOG("%s::finalize(%p)\n", getName(), this);
2391 IOLockLock(gIOUserServerLock
);
2392 OSSafeReleaseNULL(fRootQueue
);
2393 IOLockUnlock(gIOUserServerLock
);
2398 services
= OSArray::withArray(fServices
);
2400 IOLockUnlock(fLock
);
2403 services
->iterateObjects(^bool (OSObject
* obj
) {
2404 IOService
* service
;
2405 IOService
* provider
;
2406 bool started
= false;
2408 service
= (IOService
*) obj
;
2409 if (kIODKLogSetup
& gIODKDebug
) {
2410 DKLOG("%s::terminate(" DKS
")\n", getName(), DKN(service
));
2412 if (service
->reserved
->uvars
) {
2413 started
= service
->reserved
->uvars
->started
;
2414 service
->reserved
->uvars
->serverDied
= true;
2416 provider
= service
->getProvider();
2417 serviceDidStop(service
, provider
);
2418 service
->terminate(kIOServiceTerminateNeedWillTerminate
| kIOServiceTerminateWithRematch
);
2422 DKLOG("%s::terminate(" DKS
") server exit before start()\n", getName(), DKN(service
));
2423 serviceStop(service
, NULL
);
2427 services
->release();
2430 return IOUserClient::finalize(options
);
2433 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2436 #define super IOUserClient
2438 OSDefineMetaClassAndStructors(IOUserServer
, IOUserClient
)
2440 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2442 IOUserClient
* IOUserServer::withTask(task_t owningTask
)
2444 IOUserServer
* inst
;
2446 inst
= new IOUserServer
;
2447 if (inst
&& !inst
->init()) {
2454 inst
->fOwningTask
= current_task();
2455 inst
->fEntitlements
= IOUserClient::copyClientEntitlements(inst
->fOwningTask
);
2457 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
2458 if (!inst
->fEntitlements
|| !inst
->fEntitlements
->getObject(gIODriverKitEntitlementKey
)) {
2462 p
= (proc_t
)get_bsdtask_info(inst
->fOwningTask
);
2465 IOLog(kIODriverKitEntitlementKey
" entitlement check failed for %s[%d]\n", proc_best_name(p
), pid
);
2473 inst
->fLock
= IOLockAlloc();
2474 inst
->fServices
= OSArray::withCapacity(4);
2475 inst
->fClasses
= OSDictionary::withCapacity(16);
2476 inst
->fClasses
->setOptions(OSCollection::kSort
, OSCollection::kSort
);
2482 IOUserServer::clientClose(void)
2485 return kIOReturnSuccess
;
2489 IOUserServer::setProperties(OSObject
* properties
)
2491 IOReturn kr
= kIOReturnUnsupported
;
2496 IOUserServer::stop(IOService
* provider
)
2498 fOwningTask
= TASK_NULL
;
2502 IOServicePH::serverRemove(this);
2504 OSSafeReleaseNULL(fRootQueue
);
2506 if (fInterruptLock
) {
2507 IOSimpleLockFree(fInterruptLock
);
2512 IOUserServer::free()
2514 OSSafeReleaseNULL(fEntitlements
);
2515 OSSafeReleaseNULL(fClasses
);
2519 OSSafeReleaseNULL(fServices
);
2520 IOUserClient::free();
2524 IOUserServer::registerClass(OSClassDescription
* desc
, uint32_t size
, OSUserMetaClass
** pCls
)
2526 OSUserMetaClass
* cls
;
2527 const OSSymbol
* sym
;
2528 uint64_t * methodOptions
;
2529 const char * queueNames
;
2530 uint32_t methodOptionsEnd
, queueNamesEnd
;
2531 IOReturn ret
= kIOReturnSuccess
;
2533 if (size
< sizeof(OSClassDescription
)) {
2535 return kIOReturnBadArgument
;
2538 if (kIODKLogSetup
& gIODKDebug
) {
2539 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc
->name
, desc
->queueNamesSize
, desc
->methodNamesSize
);
2542 if (desc
->descriptionSize
!= size
) {
2544 return kIOReturnBadArgument
;
2546 if (os_add_overflow(desc
->queueNamesOffset
, desc
->queueNamesSize
, &queueNamesEnd
)) {
2548 return kIOReturnBadArgument
;
2550 if (queueNamesEnd
> size
) {
2552 return kIOReturnBadArgument
;
2554 if (os_add_overflow(desc
->methodOptionsOffset
, desc
->methodOptionsSize
, &methodOptionsEnd
)) {
2556 return kIOReturnBadArgument
;
2558 if (methodOptionsEnd
> size
) {
2560 return kIOReturnBadArgument
;
2563 if ((desc
->queueNamesOffset
>= desc
->methodOptionsOffset
) && (desc
->queueNamesOffset
< methodOptionsEnd
)) {
2565 return kIOReturnBadArgument
;
2567 if ((queueNamesEnd
>= desc
->methodOptionsOffset
) && (queueNamesEnd
< methodOptionsEnd
)) {
2569 return kIOReturnBadArgument
;
2572 if (desc
->methodOptionsSize
& ((2 * sizeof(uint64_t)) - 1)) {
2574 return kIOReturnBadArgument
;
2576 if (sizeof(desc
->name
) == strnlen(desc
->name
, sizeof(desc
->name
))) {
2578 return kIOReturnBadArgument
;
2580 if (sizeof(desc
->superName
) == strnlen(desc
->superName
, sizeof(desc
->superName
))) {
2582 return kIOReturnBadArgument
;
2585 cls
= OSTypeAlloc(OSUserMetaClass
);
2588 return kIOReturnNoMemory
;
2591 cls
->description
= (typeof(cls
->description
))IOMalloc(size
);
2592 assert(cls
->description
);
2593 if (!cls
->description
) {
2596 return kIOReturnNoMemory
;
2598 bcopy(desc
, cls
->description
, size
);
2600 cls
->methodCount
= desc
->methodOptionsSize
/ (2 * sizeof(uint64_t));
2601 cls
->methods
= IONew(uint64_t, 2 * cls
->methodCount
);
2602 if (!cls
->methods
) {
2605 return kIOReturnNoMemory
;
2608 methodOptions
= (typeof(methodOptions
))(((uintptr_t) desc
) + desc
->methodOptionsOffset
);
2609 bcopy(methodOptions
, cls
->methods
, 2 * cls
->methodCount
* sizeof(uint64_t));
2611 queueNames
= (typeof(queueNames
))(((uintptr_t) desc
) + desc
->queueNamesOffset
);
2612 cls
->queueNames
= copyInStringArray(queueNames
, desc
->queueNamesSize
);
2614 sym
= OSSymbol::withCString(desc
->name
);
2619 return kIOReturnNoMemory
;
2623 cls
->meta
= OSMetaClass::copyMetaClassWithName(sym
);
2624 cls
->superMeta
= OSDynamicCast(OSUserMetaClass
, fClasses
->getObject(desc
->superName
));
2625 fClasses
->setObject(sym
, cls
);
2634 IOUserServer::setRootQueue(IODispatchQueue
* queue
)
2636 assert(!fRootQueue
);
2638 return kIOReturnStillOpen
;
2643 return kIOReturnSuccess
;
2647 IOUserServer::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
2648 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
2650 IOReturn ret
= kIOReturnBadArgument
;
2651 mach_port_name_t portname
;
2654 case kIOUserServerMethodRegisterClass
:
2656 OSUserMetaClass
* cls
;
2657 if (!args
->structureInputSize
) {
2658 return kIOReturnBadArgument
;
2660 if (args
->scalarOutputCount
!= 2) {
2661 return kIOReturnBadArgument
;
2663 ret
= registerClass((OSClassDescription
*) args
->structureInput
, args
->structureInputSize
, &cls
);
2664 if (kIOReturnSuccess
== ret
) {
2665 portname
= iokit_make_send_right(fOwningTask
, cls
, IKOT_UEXT_OBJECT
);
2667 args
->scalarOutput
[0] = portname
;
2668 args
->scalarOutput
[1] = kOSObjectRPCRemote
;
2672 case kIOUserServerMethodStart
:
2674 if (args
->scalarOutputCount
!= 1) {
2675 return kIOReturnBadArgument
;
2677 portname
= iokit_make_send_right(fOwningTask
, this, IKOT_UEXT_OBJECT
);
2679 args
->scalarOutput
[0] = portname
;
2680 ret
= kIOReturnSuccess
;
2691 IOUserServer::getTargetAndTrapForIndex( IOService
**targetP
, UInt32 index
)
2693 static const IOExternalTrap trapTemplate
[] = {
2694 { NULL
, (IOTrap
) & IOUserServer::waitInterruptTrap
},
2696 if (index
>= (sizeof(trapTemplate
) / sizeof(IOExternalTrap
))) {
2700 return (IOExternalTrap
*)&trapTemplate
[index
];
2703 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2706 IOUserServer::serviceAttach(IOService
* service
, IOService
* provider
)
2709 OSObjectUserVars
* vars
;
2712 OSSymbolConstPtr bundleID
;
2713 char execPath
[1024];
2715 vars
= IONewZero(OSObjectUserVars
, 1);
2716 service
->reserved
->uvars
= vars
;
2718 vars
->userServer
= this;
2719 vars
->userServer
->retain();
2721 if (-1U == fServices
->getNextIndexOfObject(service
, 0)) {
2722 fServices
->setObject(service
);
2724 IOLockUnlock(fLock
);
2726 prop
= service
->copyProperty(gIOUserClassKey
);
2727 str
= OSDynamicCast(OSString
, prop
);
2729 service
->setName(str
);
2731 OSSafeReleaseNULL(prop
);
2733 prop
= service
->copyProperty(gIOModuleIdentifierKey
);
2734 bundleID
= OSDynamicCast(OSSymbol
, prop
);
2737 bool ok
= OSKext::copyUserExecutablePath(bundleID
, execPath
, sizeof(execPath
));
2739 ret
= LoadModule(execPath
);
2740 if (kIODKLogSetup
& gIODKDebug
) {
2741 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret
, execPath
);
2745 OSSafeReleaseNULL(prop
);
2747 ret
= kIOReturnSuccess
;
2752 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2754 #define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
2757 IOUserServer::serviceNewUserClient(IOService
* service
, task_t owningTask
, void * securityID
,
2758 uint32_t type
, OSDictionary
* properties
, IOUserClient
** handler
)
2762 IOUserUserClient
* userUC
;
2763 OSDictionary
* entitlements
;
2765 OSObject
* bundleID
;
2769 ret
= service
->NewUserClient(type
, &uc
);
2770 if (kIOReturnSuccess
!= ret
) {
2773 userUC
= OSDynamicCast(IOUserUserClient
, uc
);
2776 OSSafeReleaseNULL(uc
);
2777 return kIOReturnUnsupported
;
2779 userUC
->setTask(owningTask
);
2781 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
2782 entitlements
= IOUserClient::copyClientEntitlements(owningTask
);
2783 bundleID
= service
->copyProperty(gIOModuleIdentifierKey
);
2786 && (prop
= entitlements
->getObject(gIODriverKitUserClientEntitlementsKey
)));
2788 bool found __block
= false;
2789 ok
= prop
->iterateObjects(^bool (OSObject
* object
) {
2790 found
= object
->isEqualTo(bundleID
);
2796 prop
= userUC
->copyProperty(gIOServiceDEXTEntitlementsKey
);
2797 ok
= checkEntitlements(entitlements
, prop
, NULL
, NULL
);
2799 OSSafeReleaseNULL(bundleID
);
2800 OSSafeReleaseNULL(entitlements
);
2802 DKLOG(DKS
":UC entitlements check failed\n", DKN(userUC
));
2804 OSSafeReleaseNULL(uc
);
2805 return kIOReturnNotPermitted
;
2809 ret
= userUC
->Start(service
);
2810 if (kIOReturnSuccess
!= ret
) {
2811 userUC
->detach(this);
2821 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2823 static IOPMPowerState
2825 { .version
= kIOPMPowerStateVersion1
,
2826 .capabilityFlags
= 0,
2827 .outputPowerCharacter
= 0,
2828 .inputPowerRequirement
= 0},
2829 { .version
= kIOPMPowerStateVersion1
,
2830 .capabilityFlags
= kIOPMLowPower
,
2831 .outputPowerCharacter
= kIOPMLowPower
,
2832 .inputPowerRequirement
= kIOPMLowPower
},
2833 { .version
= kIOPMPowerStateVersion1
,
2834 .capabilityFlags
= kIOPMPowerOn
,
2835 .outputPowerCharacter
= kIOPMPowerOn
,
2836 .inputPowerRequirement
= kIOPMPowerOn
},
2840 IOUserServer::setPowerState(unsigned long state
, IOService
* service
)
2842 if (kIODKLogPM
& gIODKDebug
) {
2843 DKLOG(DKS
"::setPowerState(%ld) %d\n", DKN(service
), state
, fSystemPowerAck
);
2845 return kIOPMAckImplied
;
2849 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
2853 if (service
->reserved
->uvars
) {
2854 if (!fSystemOff
&& !(kIODKDisablePM
& gIODKDebug
)) {
2855 service
->reserved
->uvars
->willPower
= true;
2856 if (kIODKLogPM
& gIODKDebug
) {
2857 DKLOG(DKS
"::powerStateWillChangeTo(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
2859 ret
= service
->SetPowerState(flags
);
2860 if (kIOReturnSuccess
== ret
) {
2861 return 20 * 1000 * 1000;
2864 service
->reserved
->uvars
->willPower
= false;
2867 return kIOPMAckImplied
;
2871 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
2878 idx
= fServices
->getNextIndexOfObject(service
, 0);
2880 IOLockUnlock(fLock
);
2881 return kIOPMAckImplied
;
2886 fPowerStates
|= (1ULL << idx
);
2888 fPowerStates
&= ~(1ULL << idx
);
2890 if (kIODKLogPM
& gIODKDebug
) {
2891 DKLOG(DKS
"::powerStateDidChangeTo(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
2893 if (!fPowerStates
&& (pmAck
= fSystemPowerAck
)) {
2894 fSystemPowerAck
= false;
2897 IOLockUnlock(fLock
);
2900 IOServicePH::serverAck(this);
2903 return kIOPMAckImplied
;
2907 IMPL(IOService
, SetPowerState
)
2909 if (kIODKLogPM
& gIODKDebug
) {
2910 DKLOG(DKS
"::SetPowerState(%d), %d\n", DKN(this), powerFlags
, reserved
->uvars
->willPower
);
2913 && reserved
->uvars
->userServer
2914 && reserved
->uvars
->willPower
) {
2915 reserved
->uvars
->willPower
= false;
2916 acknowledgePowerChange(reserved
->uvars
->userServer
);
2917 return kIOReturnSuccess
;
2919 return kIOReturnNotReady
;
2923 IMPL(IOService
, ChangePowerState
)
2925 switch (powerFlags
) {
2926 case kIOServicePowerCapabilityOff
:
2927 changePowerStateToPriv(0);
2929 case kIOServicePowerCapabilityLow
:
2930 changePowerStateToPriv(1);
2932 case kIOServicePowerCapabilityOn
:
2933 changePowerStateToPriv(2);
2936 return kIOReturnBadArgument
;
2939 return kIOReturnSuccess
;
2943 IMPL(IOService
, Create
)
2946 IOService
* service
;
2948 const OSSymbol
* sym
;
2950 OSDictionary
* properties
;
2953 if (provider
!= this) {
2954 return kIOReturnUnsupported
;
2957 ret
= kIOReturnUnsupported
;
2961 prop
= copyProperty(propertiesKey
);
2962 properties
= OSDynamicCast(OSDictionary
, prop
);
2965 str
= OSDynamicCast(OSString
, properties
->getObject(gIOClassKey
));
2967 sym
= OSSymbol::withString(str
);
2969 inst
= OSMetaClass::allocClassWithName(sym
);
2970 service
= OSDynamicCast(IOService
, inst
);
2971 if (service
&& service
->init(properties
) && service
->attach(this)) {
2972 reserved
->uvars
->userServer
->serviceAttach(service
, this);
2973 ret
= kIOReturnSuccess
;
2976 OSSafeReleaseNULL(sym
);
2980 OSSafeReleaseNULL(prop
);
2981 if (kIOReturnSuccess
!= ret
) {
2982 OSSafeReleaseNULL(inst
);
2989 IMPL(IOService
, NewUserClient
)
2991 return kIOReturnError
;
2995 IMPL(IOService
, SearchProperty
)
2999 if (kIOServiceSearchPropertyParents
& options
) {
3000 options
= kIORegistryIterateParents
| kIORegistryIterateRecursively
;
3005 object
= copyProperty(name
, IORegistryEntry::getPlane(plane
), options
);
3008 return object
? kIOReturnSuccess
: kIOReturnNotFound
;
3012 IOUserServer::systemPower(bool powerOff
)
3016 if (kIODKLogPM
& gIODKDebug
) {
3017 DKLOG("%s::powerOff(%d) 0x%qx\n", getName(), powerOff
, fPowerStates
);
3021 services
= OSArray::withArray(fServices
);
3024 fSystemPowerAck
= (0 != fPowerStates
);
3025 if (!fSystemPowerAck
) {
3028 IOLockUnlock(fLock
);
3030 if (!fSystemPowerAck
) {
3031 IOServicePH::serverAck(this);
3034 services
->iterateObjects(^bool (OSObject
* obj
) {
3035 IOService
* service
;
3036 service
= (IOService
*) obj
;
3037 if (kIODKLogPM
& gIODKDebug
) {
3038 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), 0);
3040 service
->reserved
->uvars
->powerOverride
= service
->getPowerState();
3041 service
->changePowerStateWithOverrideTo(0, 0);
3048 IOLockUnlock(fLock
);
3050 services
->iterateObjects(^bool (OSObject
* obj
) {
3051 IOService
* service
;
3052 service
= (IOService
*) obj
;
3053 if (-1U != service
->reserved
->uvars
->powerOverride
) {
3054 if (kIODKLogPM
& gIODKDebug
) {
3055 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), service
->reserved
->uvars
->powerOverride
);
3057 service
->changePowerStateWithOverrideTo(service
->reserved
->uvars
->powerOverride
, 0);
3058 service
->reserved
->uvars
->powerOverride
= -1U;
3064 OSSafeReleaseNULL(services
);
3070 IOUserServer::serviceStarted(IOService
* service
, IOService
* provider
, bool result
)
3073 IOService
* pmProvider
;
3075 DKLOG(DKS
"::start(" DKS
") %s\n", DKN(service
), DKN(provider
), result
? "ok" : "fail");
3078 ret
= kIOReturnSuccess
;
3082 if (!fRootNotifier
) {
3083 ret
= registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
3084 assert(kIOReturnSuccess
== ret
);
3085 IOServicePH::serverAdd(this);
3086 fRootNotifier
= true;
3089 if (!(kIODKDisablePM
& gIODKDebug
) && !service
->pm_vars
) {
3091 ret
= service
->registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
3092 assert(kIOReturnSuccess
== ret
);
3094 pmProvider
= service
;
3095 while (pmProvider
&& !pmProvider
->inPlane(gIOPowerPlane
)) {
3096 pmProvider
= pmProvider
->getProvider();
3101 prop
= pmProvider
->copyProperty("non-removable");
3103 str
= OSDynamicCast(OSString
, prop
);
3104 if (str
&& str
->isEqualTo("yes")) {
3112 unsigned int idx
= fServices
->getNextIndexOfObject(service
, 0);
3114 fPowerStates
|= (1ULL << idx
);
3115 IOLockUnlock(fLock
);
3117 pmProvider
->joinPMtree(service
);
3118 service
->reserved
->uvars
->userServerPM
= true;
3122 service
->registerInterestedDriver(this);
3123 service
->reserved
->uvars
->started
= true;
3125 return kIOReturnSuccess
;
3130 IOUserServer::serviceOpen(IOService
* provider
, IOService
* client
)
3132 OSObjectUserVars
* uvars
;
3134 uvars
= client
->reserved
->uvars
;
3135 if (!uvars
->openProviders
) {
3136 uvars
->openProviders
= OSArray::withObjects((const OSObject
**) &provider
, 1);
3137 } else if (-1U == uvars
->openProviders
->getNextIndexOfObject(client
, 0)) {
3138 uvars
->openProviders
->setObject(provider
);
3141 return kIOReturnSuccess
;
3145 IOUserServer::serviceClose(IOService
* provider
, IOService
* client
)
3147 OSObjectUserVars
* uvars
;
3150 uvars
= client
->reserved
->uvars
;
3151 if (!uvars
->openProviders
) {
3152 return kIOReturnNotOpen
;
3154 idx
= uvars
->openProviders
->getNextIndexOfObject(client
, 0);
3156 return kIOReturnNotOpen
;
3158 uvars
->openProviders
->removeObject(idx
);
3160 return kIOReturnSuccess
;
3165 IOUserServer::serviceStop(IOService
* service
, IOService
*)
3168 uint32_t idx
, queueAlloc
;
3169 OSObjectUserVars
* uvars
;
3172 idx
= fServices
->getNextIndexOfObject(service
, 0);
3174 fServices
->removeObject(idx
);
3175 uvars
= service
->reserved
->uvars
;
3176 uvars
->stopped
= true;
3178 IOLockUnlock(fLock
);
3181 return kIOReturnSuccess
;
3184 IOMachPortDestroyUserReferences(service
, IKOT_UEXT_OBJECT
);
3186 if (uvars
->queueArray
&& uvars
->userMeta
) {
3188 if (uvars
->userMeta
->queueNames
) {
3189 queueAlloc
+= uvars
->userMeta
->queueNames
->count
;
3191 for (idx
= 0; idx
< queueAlloc
; idx
++) {
3192 OSSafeReleaseNULL(uvars
->queueArray
[idx
]);
3194 IOSafeDeleteNULL(uvars
->queueArray
, IODispatchQueue
*, queueAlloc
);
3197 (void) service
->deRegisterInterestedDriver(this);
3198 if (uvars
->userServerPM
) {
3202 ret
= kIOReturnSuccess
;
3207 IOUserServer::serviceFree(IOService
* service
)
3209 OSObjectUserVars
* uvars
;
3211 uvars
= service
->reserved
->uvars
;
3215 OSSafeReleaseNULL(uvars
->userServer
);
3216 IOSafeDeleteNULL(service
->reserved
->uvars
, OSObjectUserVars
, 1);
3220 IOUserServer::serviceWillTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
)
3225 willTerminate
= false;
3226 if (client
->lockForArbitration(true)) {
3227 if (!client
->reserved
->uvars
->serverDied
3228 && !client
->reserved
->uvars
->willTerminate
) {
3229 client
->reserved
->uvars
->willTerminate
= true;
3230 willTerminate
= true;
3232 client
->unlockForArbitration();
3235 if (willTerminate
) {
3236 ret
= client
->Stop(provider
);
3237 if (kIOReturnSuccess
!= ret
) {
3238 ret
= client
->IOService::Stop(provider
);
3244 IOUserServer::serviceDidTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
, bool * defer
)
3246 if (client
->lockForArbitration(true)) {
3247 client
->reserved
->uvars
->didTerminate
= true;
3248 if (!client
->reserved
->uvars
->serverDied
3249 && !client
->reserved
->uvars
->stopped
) {
3252 client
->unlockForArbitration();
3257 IOUserServer::serviceDidStop(IOService
* client
, IOService
* provider
)
3260 OSArray
* closeArray
;
3265 if (client
->lockForArbitration(true)) {
3266 if (client
->reserved
->uvars
3267 && client
->reserved
->uvars
->willTerminate
3268 && !client
->reserved
->uvars
->stopped
) {
3269 client
->reserved
->uvars
->stopped
= true;
3270 complete
= client
->reserved
->uvars
->didTerminate
;
3273 if (client
->reserved
->uvars
) {
3274 closeArray
= client
->reserved
->uvars
->openProviders
;
3275 client
->reserved
->uvars
->openProviders
= NULL
;
3277 client
->unlockForArbitration();
3279 closeArray
->iterateObjects(^bool (OSObject
* obj
) {
3280 IOService
* toClose
;
3281 toClose
= OSDynamicCast(IOService
, obj
);
3283 DKLOG(DKS
":force close (" DKS
")\n", DKN(client
), DKN(toClose
));
3284 toClose
->close(client
);
3288 closeArray
->release();
3293 client
->didTerminate(provider
, 0, &defer
);
3298 IMPL(IOService
, Stop
)
3300 IOUserServer::serviceDidStop(this, provider
);
3302 return kIOReturnSuccess
;
3306 IMPL(IOInterruptDispatchSource
, Cancel
)
3308 return kIOReturnUnsupported
;
3311 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3314 #define super IOUserClient
3316 OSDefineMetaClassAndStructors(IOUserUserClient
, IOUserClient
)
3318 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3321 IOUserUserClient::setTask(task_t task
)
3323 task_reference(task
);
3326 return kIOReturnSuccess
;
3330 IOUserUserClient::stop(IOService
* provider
)
3333 task_deallocate(fTask
);
3336 super::stop(provider
);
3340 IOUserUserClient::clientClose(void)
3343 return kIOReturnSuccess
;
3347 IOUserUserClient::setProperties(OSObject
* properties
)
3349 IOReturn ret
= kIOReturnUnsupported
;
3353 struct IOUserUserClientActionRef
{
3354 OSAsyncReference64 asyncRef
;
3358 IMPL(IOUserClient
, KernelCompletion
)
3360 IOUserUserClientActionRef
* ref
;
3362 ref
= (typeof(ref
))action
->GetReference();
3364 IOUserClient::sendAsyncResult64(ref
->asyncRef
, status
, (io_user_reference_t
*) asyncData
, asyncDataCount
);
3368 IMPL(IOUserClient
, _ExternalMethod
)
3370 return kIOReturnUnsupported
;
3374 IOUserUserClient::clientMemoryForType(UInt32 type
,
3375 IOOptionBits
* koptions
,
3376 IOMemoryDescriptor
** kmemory
)
3380 IOMemoryDescriptor
* memory
;
3382 kr
= CopyClientMemoryForType(type
, &options
, &memory
);
3386 if (kIOReturnSuccess
!= kr
) {
3390 if (kIOUserClientMemoryReadOnly
& options
) {
3391 *koptions
|= kIOMapReadOnly
;
3399 IOUserUserClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
3400 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
3403 OSData
* structureInput
;
3404 OSData
* structureOutput
;
3406 uint64_t structureOutputSize
;
3408 IOUserUserClientActionRef
* ref
;
3410 kr
= kIOReturnUnsupported
;
3411 structureInput
= NULL
;
3414 if (args
->structureInputSize
) {
3415 structureInput
= OSData::withBytesNoCopy((void *) args
->structureInput
, args
->structureInputSize
);
3418 if (MACH_PORT_NULL
!= args
->asyncWakePort
) {
3419 kr
= CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef
), &action
);
3420 assert(KERN_SUCCESS
== kr
);
3421 ref
= (typeof(ref
))action
->GetReference();
3422 bcopy(args
->asyncReference
, &ref
->asyncRef
[0], args
->asyncReferenceCount
* sizeof(ref
->asyncRef
[0]));
3425 if (args
->structureVariableOutputData
) {
3426 structureOutputSize
= kIOUserClientVariableStructureSize
;
3427 } else if (args
->structureOutputDescriptor
) {
3428 structureOutputSize
= args
->structureOutputDescriptor
->getLength();
3430 structureOutputSize
= args
->structureOutputSize
;
3433 kr
= _ExternalMethod(selector
, &args
->scalarInput
[0], args
->scalarInputCount
,
3434 structureInput
, args
->structureInputDescriptor
,
3435 args
->scalarOutput
, &args
->scalarOutputCount
,
3436 structureOutputSize
, &structureOutput
, args
->structureOutputDescriptor
,
3439 OSSafeReleaseNULL(structureInput
);
3440 OSSafeReleaseNULL(action
);
3442 if (kIOReturnSuccess
!= kr
) {
3445 if (structureOutput
) {
3446 if (args
->structureVariableOutputData
) {
3447 *args
->structureVariableOutputData
= structureOutput
;
3449 copylen
= structureOutput
->getLength();
3450 if (copylen
> args
->structureOutputSize
) {
3451 kr
= kIOReturnBadArgument
;
3453 bcopy((const void *) structureOutput
->getBytesNoCopy(), args
->structureOutput
, copylen
);
3455 OSSafeReleaseNULL(structureOutput
);
3462 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */