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 options
|= kIOMemoryKernelUserShared
;
457 bmd
= IOBufferMemoryDescriptor::inTaskWithOptions(
458 kernel_task
, options
, capacity
, alignment
);
463 return kIOReturnNoMemory
;
466 reserved
= bmd
->getKernelReserved();
467 reserved
->creator
= current_task();
468 task_reference(reserved
->creator
);
470 ret
= kIOReturnSuccess
;
476 IMPL(IOBufferMemoryDescriptor
, SetLength
)
479 return kIOReturnSuccess
;
482 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
485 OSAction::Create(OSAction_Create_Args
)
488 ret
= OSAction::Create_Call(target
, targetmsgid
, msgid
, referenceSize
, action
);
493 IMPL(OSAction
, Create
)
498 if (os_add_overflow(referenceSize
, sizeof(OSAction_IVars
), &allocsize
)) {
499 return kIOReturnBadArgument
;
501 inst
= OSTypeAlloc(OSAction
);
503 return kIOReturnNoMemory
;
505 inst
->ivars
= (typeof(inst
->ivars
))(uintptr_t) IONewZero(uint8_t, allocsize
);
508 return kIOReturnNoMemory
;
511 inst
->ivars
->target
= target
;
512 inst
->ivars
->targetmsgid
= targetmsgid
;
513 inst
->ivars
->msgid
= msgid
;
514 inst
->ivars
->referenceSize
= referenceSize
;
518 return kIOReturnSuccess
;
525 if (ivars
->abortedHandler
) {
526 Block_release(ivars
->abortedHandler
);
527 ivars
->abortedHandler
= NULL
;
529 OSSafeReleaseNULL(ivars
->target
);
530 IOSafeDeleteNULL(ivars
, uint8_t, ivars
->referenceSize
+ sizeof(OSAction_IVars
));
532 return super::free();
536 OSAction::GetReference()
538 assert(ivars
&& ivars
->referenceSize
);
539 return &ivars
->reference
[0];
543 OSAction::SetAbortedHandler(OSActionAbortedHandler handler
)
545 ivars
->abortedHandler
= Block_copy(handler
);
546 return kIOReturnSuccess
;
550 OSAction::Aborted_Impl(void)
552 if (ivars
->abortedHandler
) {
553 ivars
->abortedHandler();
557 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
559 struct IODispatchSource_IVars
{
561 IODispatchSource
* source
;
562 IOUserServer
* server
;
563 IODispatchQueue_IVars
* queue
;
568 IODispatchSource::init()
570 if (!super::init()) {
574 ivars
= IONewZero(IODispatchSource_IVars
, 1);
576 ivars
->source
= this;
582 IODispatchSource::free()
584 IOSafeDeleteNULL(ivars
, IODispatchSource_IVars
, 1);
588 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
590 struct IOInterruptDispatchSource_IVars
{
591 IOService
* provider
;
602 IOInterruptDispatchSourceInterrupt(OSObject
* target
, void * refCon
,
603 IOService
* nub
, int source
)
605 IOInterruptDispatchSource_IVars
* ivars
= (typeof(ivars
))refCon
;
608 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
611 ivars
->time
= mach_absolute_time();
612 thread_wakeup_thread((event_t
) ivars
, ivars
->waiter
);
613 ivars
->waiter
= NULL
;
615 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
619 IMPL(IOInterruptDispatchSource
, Create
)
622 IOInterruptDispatchSource
* inst
;
624 inst
= OSTypeAlloc(IOInterruptDispatchSource
);
627 return kIOReturnNoMemory
;
630 inst
->ivars
->lock
= IOSimpleLockAlloc();
632 ret
= provider
->registerInterrupt(index
, inst
, IOInterruptDispatchSourceInterrupt
, inst
->ivars
);
633 if (kIOReturnSuccess
== ret
) {
634 inst
->ivars
->intIndex
= index
;
635 inst
->ivars
->provider
= provider
;
642 IOInterruptDispatchSource::init()
644 if (!super::init()) {
647 ivars
= IONewZero(IOInterruptDispatchSource_IVars
, 1);
656 IOInterruptDispatchSource::free()
660 if (ivars
&& ivars
->provider
) {
661 ret
= ivars
->provider
->unregisterInterrupt(ivars
->intIndex
);
662 assert(kIOReturnSuccess
== ret
);
665 IOSafeDeleteNULL(ivars
, IOInterruptDispatchSource_IVars
, 1);
671 IMPL(IOInterruptDispatchSource
, SetHandler
)
674 OSAction
* oldAction
;
676 oldAction
= (typeof(oldAction
))ivars
->action
;
677 if (oldAction
&& OSCompareAndSwapPtr(oldAction
, NULL
, &ivars
->action
)) {
678 oldAction
->release();
681 ivars
->action
= action
;
683 ret
= kIOReturnSuccess
;
689 IMPL(IOInterruptDispatchSource
, SetEnableWithCompletion
)
694 if (enable
== ivars
->enable
) {
695 return kIOReturnSuccess
;
699 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
700 ivars
->enable
= enable
;
701 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
702 ret
= ivars
->provider
->enableInterrupt(ivars
->intIndex
);
704 ret
= ivars
->provider
->disableInterrupt(ivars
->intIndex
);
705 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
706 ivars
->enable
= enable
;
707 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
714 IMPL(IODispatchSource
, SetEnable
)
716 return SetEnableWithCompletion(enable
, NULL
);
720 IMPL(IOInterruptDispatchSource
, CheckForWork
)
722 IOReturn ret
= kIOReturnNotReady
;
724 wait_result_t waitResult
;
729 self
= current_thread();
732 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
733 if ((icount
= ivars
->count
)) {
736 waitResult
= THREAD_AWAKENED
;
737 } else if (synchronous
) {
738 assert(NULL
== ivars
->waiter
);
739 ivars
->waiter
= self
;
740 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
742 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
743 if (synchronous
&& (waitResult
== THREAD_WAITING
)) {
744 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
745 if (THREAD_INTERRUPTED
== waitResult
) {
749 } while (synchronous
&& !icount
);
751 if (icount
&& ivars
->action
) {
752 ret
= InterruptOccurred(rpc
, ivars
->action
, icount
, itime
);
759 IMPL(IOInterruptDispatchSource
, InterruptOccurred
)
763 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
766 IOUserServer::waitInterruptTrap(void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
768 IOReturn ret
= kIOReturnBadArgument
;
770 IOInterruptDispatchSource
* interrupt
;
771 IOInterruptDispatchSource_IVars
* ivars
;
772 IOInterruptDispatchSourcePayload payload
;
774 wait_result_t waitResult
;
779 object
= iokit_lookup_object_with_port_name((mach_port_name_t
)(uintptr_t)p1
, IKOT_UEXT_OBJECT
, current_task());
782 return kIOReturnBadArgument
;
784 if (!(interrupt
= OSDynamicCast(IOInterruptDispatchSource
, object
))) {
785 ret
= kIOReturnBadArgument
;
787 self
= current_thread();
788 ivars
= interrupt
->ivars
;
791 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
792 if ((payload
.count
= ivars
->count
)) {
793 payload
.time
= ivars
->time
;
795 waitResult
= THREAD_AWAKENED
;
797 assert(NULL
== ivars
->waiter
);
798 ivars
->waiter
= self
;
799 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
801 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
802 if (waitResult
== THREAD_WAITING
) {
803 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
804 if (THREAD_INTERRUPTED
== waitResult
) {
808 } while (!payload
.count
);
809 ret
= (payload
.count
? kIOReturnSuccess
: kIOReturnAborted
);
812 if (kIOReturnSuccess
== ret
) {
813 int copyerr
= copyout(&payload
, (user_addr_t
) p2
, sizeof(payload
));
815 ret
= kIOReturnVMError
;
824 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
827 IMPL(IOUserServer
, Create
)
831 const OSSymbol
* sym
;
832 OSNumber
* serverTag
;
835 us
= (typeof(us
))thread_iokit_tls_get(0);
836 assert(OSDynamicCast(IOUserServer
, us
));
837 if (kIODKLogSetup
& gIODKDebug
) {
838 DKLOG(DKS
"::Create(" DKS
") %p\n", DKN(us
), name
, tag
, us
);
841 return kIOReturnError
;
844 sym
= OSSymbol::withCString(name
);
845 serverTag
= OSNumber::withNumber(tag
, 64);
847 us
->setProperty(gIOUserServerNameKey
, (OSObject
*) sym
);
848 us
->setProperty(gIOUserServerTagKey
, serverTag
);
850 serverTag
->release();
851 OSSafeReleaseNULL(sym
);
853 snprintf(rname
, sizeof(rname
), "IOUserServer(%s-0x%qx)", name
, tag
);
858 ret
= kIOReturnSuccess
;
864 IMPL(IOUserServer
, Exit
)
866 return kIOReturnUnsupported
;
870 IMPL(IOUserServer
, LoadModule
)
872 return kIOReturnUnsupported
;
876 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
879 IMPL(IODispatchQueue
, Create
)
881 IODispatchQueue
* result
;
884 result
= OSTypeAlloc(IODispatchQueue
);
886 return kIOReturnNoMemory
;
888 if (!result
->init()) {
889 return kIOReturnNoMemory
;
894 if (!strcmp("Root", name
)) {
895 us
= (typeof(us
))thread_iokit_tls_get(0);
896 assert(OSDynamicCast(IOUserServer
, us
));
897 us
->setRootQueue(result
);
900 if (kIODKLogSetup
& gIODKDebug
) {
901 DKLOG("IODispatchQueue::Create %s %p\n", name
, result
);
904 return kIOReturnSuccess
;
908 IMPL(IODispatchQueue
, SetPort
)
910 ivars
->serverPort
= port
;
911 return kIOReturnSuccess
;
915 IODispatchQueue::init()
917 ivars
= IONewZero(IODispatchQueue_IVars
, 1);
927 IODispatchQueue::free()
929 IOSafeDeleteNULL(ivars
, IODispatchQueue_IVars
, 1);
934 IODispatchQueue::OnQueue()
939 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
943 OSMetaClassBase::Dispatch(IORPC rpc
)
945 return kIOReturnUnsupported
;
949 OSMetaClassBase::Invoke(IORPC rpc
)
951 IOReturn ret
= kIOReturnUnsupported
;
952 OSMetaClassBase
* object
;
956 IORPCMessage
* message
;
958 assert(rpc
.sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
959 message
= IORPCMessageFromMach(rpc
.message
, false);
961 return kIOReturnIPCError
;
963 message
->flags
|= kIORPCMessageKernel
;
966 if (!(kIORPCMessageLocalHost
& message
->flags
)) {
967 us
= OSDynamicCast(IOUserServer
, this);
969 if ((action
= OSDynamicCast(OSAction
, this))) {
970 object
= IOUserServer::target(action
, message
);
974 if ((service
= OSDynamicCast(IOService
, object
))
975 && service
->reserved
->uvars
) {
977 us
= service
->reserved
->uvars
->userServer
;
982 message
->flags
|= kIORPCMessageRemote
;
984 if (kIOReturnSuccess
!= ret
) {
985 if (kIODKLogIPC
& gIODKDebug
) {
986 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret
);
990 if (kIODKLogIPC
& gIODKDebug
) {
991 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message
->msgid
);
999 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1004 const char strings
[0];
1008 OSUserMetaClass::Dispatch(IORPC rpc
)
1010 return const_cast<OSMetaClass
*>(meta
)->Dispatch(rpc
);
1014 OSUserMetaClass::free()
1017 IOFree(queueNames
, sizeof(IOPStrings
) + queueNames
->dataSize
* sizeof(char));
1021 IOFree(description
, description
->descriptionSize
);
1024 IOSafeDeleteNULL(methods
, uint64_t, 2 * methodCount
);
1026 meta
->releaseMetaClass();
1035 * Sets the loadTag of the associated OSKext
1037 * NOTE: different instances of the same OSKext
1038 * (so same BounleID but different tasks)
1039 * will have the same loadTag.
1042 IOUserServer::setTaskLoadTag(OSKext
*kext
)
1045 uint32_t loadTag
, prev_taskloadTag
;
1047 owningTask
= this->fOwningTask
;
1049 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1053 loadTag
= kext
->getLoadTag();
1054 prev_taskloadTag
= set_task_loadTag(owningTask
, loadTag
);
1055 if (prev_taskloadTag
) {
1056 printf("%s: found the task loadTag already set to %u (set to %u)\n",
1057 __FUNCTION__
, prev_taskloadTag
, loadTag
);
1062 * Sets the OSKext uuid as the uuid of the userspace
1066 IOUserServer::setDriverKitUUID(OSKext
*kext
)
1070 uuid_t p_uuid
, k_uuid
;
1071 OSData
*k_data_uuid
;
1073 uuid_string_t uuid_string
= "";
1075 task
= this->fOwningTask
;
1077 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1081 p
= (proc_t
)(get_bsdtask_info(task
));
1083 printf("%s: proc not found\n", __FUNCTION__
);
1086 proc_getexecutableuuid(p
, p_uuid
, sizeof(p_uuid
));
1088 k_data_uuid
= kext
->copyUUID();
1090 memcpy(&k_uuid
, k_data_uuid
->getBytesNoCopy(), sizeof(k_uuid
));
1091 OSSafeReleaseNULL(k_data_uuid
);
1092 if (uuid_compare(k_uuid
, p_uuid
) != 0) {
1093 printf("%s: uuid not matching\n", __FUNCTION__
);
1098 uuid_unparse(p_uuid
, uuid_string
);
1099 new_uuid
= OSData::withBytes(p_uuid
, sizeof(p_uuid
));
1100 kext
->setDriverKitUUID(new_uuid
);
1104 IOUserServer::serviceMatchesCDHash(IOService
*service
)
1106 OSObject
*obj
= NULL
;
1107 bool result
= false;
1108 OSString
*requiredCDHashStr
= NULL
;
1109 const char *requiredCDHash
= NULL
;
1110 char taskCDHash
[CS_CDHASH_LEN
];
1112 task_t owningTask
= this->fOwningTask
;
1114 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1118 obj
= service
->copyProperty(gIOUserServerCDHashKey
);
1119 requiredCDHashStr
= OSDynamicCast(OSString
, obj
);
1120 if (!requiredCDHashStr
) {
1121 printf("%s: required cdhash not found as property of personality\n", __FUNCTION__
);
1125 requiredCDHash
= requiredCDHashStr
->getCStringNoCopy();
1126 if (!requiredCDHash
) {
1127 printf("%s: required cdhash unable to be read as string\n", __FUNCTION__
);
1131 if (strlen(requiredCDHash
) != CS_CDHASH_LEN
* 2) {
1132 printf("%s: required cdhash string has incorrect length\n", __FUNCTION__
);
1136 get_task_cdhash(owningTask
, taskCDHash
);
1137 for (int i
= 0; i
< (int)CS_CDHASH_LEN
* 2; i
++) {
1138 uint8_t which
= (i
+ 1) & 0x1; /* 1 for upper nibble, 0 for lower */
1139 uint8_t nibble
= requiredCDHash
[i
];
1140 uint8_t byte
= taskCDHash
[i
/ 2];
1141 if ('0' <= nibble
&& nibble
<= '9') {
1143 } else if ('a' <= nibble
&& nibble
<= 'f') {
1145 } else if ('A' <= nibble
&& nibble
<= 'F') {
1148 printf("%s: required cdhash contains invalid token '%c'\n", __FUNCTION__
, nibble
);
1153 * Decide which half of the byte to compare
1155 if (nibble
!= (which
? (byte
>> 4) : (byte
& 0x0f))) {
1156 printf("%s: required cdhash %s in personality does not match service\n", __FUNCTION__
, requiredCDHash
);
1163 OSSafeReleaseNULL(obj
);
1168 IOUserServer::checkEntitlements(
1169 OSDictionary
* entitlements
, OSObject
* prop
,
1170 IOService
* provider
, IOService
* dext
)
1172 OSDictionary
* matching
;
1177 if (!entitlements
) {
1183 matching
= dext
->dictionaryWithProperties();
1189 bool allPresent __block
;
1190 prop
->iterateObjects(^bool (OSObject
* object
) {
1192 object
->iterateObjects(^bool (OSObject
* object
) {
1195 string
= OSDynamicCast(OSString
, object
);
1196 value
= entitlements
->getObject(string
);
1197 if (matching
&& value
) {
1198 matching
->setObject(string
, value
);
1200 allPresent
= (NULL
!= value
);
1206 if (allPresent
&& matching
&& provider
) {
1207 allPresent
= provider
->matchPropertyTable(matching
);
1210 OSSafeReleaseNULL(matching
);
1211 OSSafeReleaseNULL(prop
);
1217 IOUserServer::checkEntitlements(IOService
* provider
, IOService
* dext
)
1226 prop
= provider
->copyProperty(gIOServiceDEXTEntitlementsKey
);
1227 ok
= checkEntitlements(fEntitlements
, prop
, provider
, dext
);
1229 DKLOG(DKS
": provider entitlements check failed\n", DKN(dext
));
1232 prop
= dext
->copyProperty(gIOServiceDEXTEntitlementsKey
);
1233 ok
= checkEntitlements(fEntitlements
, prop
, NULL
, NULL
);
1235 DKLOG(DKS
": family entitlements check failed\n", DKN(dext
));
1243 IOUserServer::exit(const char * reason
)
1245 DKLOG("%s::exit(%s)\n", getName(), reason
);
1247 return kIOReturnSuccess
;
1251 IOUserServer::varsForObject(OSObject
* obj
)
1253 IOService
* service
;
1255 if ((service
= OSDynamicCast(IOService
, obj
))) {
1256 return service
->reserved
->uvars
;
1263 IOUserServer::copyInStringArray(const char * string
, uint32_t userSize
)
1271 if (userSize
<= 1) {
1275 if (os_add_overflow(sizeof(IOPStrings
), userSize
, &alloc
)) {
1279 if (alloc
> 16384) {
1283 array
= (typeof(array
))IOMalloc(alloc
);
1287 array
->dataSize
= userSize
;
1288 bcopy(string
, (void *) &array
->strings
[0], userSize
);
1291 cstr
= &array
->strings
[0];
1292 end
= &array
->strings
[array
->dataSize
];
1293 while ((len
= cstr
[0])) {
1295 if ((cstr
+ len
) >= end
) {
1302 IOFree(array
, alloc
);
1310 IOUserServer::stringArrayIndex(IOPStrings
* array
, const char * look
)
1318 cstr
= &array
->strings
[0];
1319 end
= &array
->strings
[array
->dataSize
];
1320 llen
= strlen(look
);
1321 while ((len
= cstr
[0])) {
1323 if ((cstr
+ len
) >= end
) {
1326 if ((len
== llen
) && !strncmp(cstr
, look
, len
)) {
1335 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
1338 IOUserServer::queueForObject(OSObject
* obj
, uint64_t msgid
)
1340 IODispatchQueue
* queue
;
1341 OSObjectUserVars
* uvars
;
1344 uvars
= varsForObject(obj
);
1348 if (!uvars
->queueArray
) {
1349 if (uvars
->stopped
) {
1350 return kIODispatchQueueStopped
;
1354 queue
= uvars
->queueArray
[0];
1357 && uvars
->userMeta
->methods
) {
1358 uint32_t idx
, baseIdx
;
1361 for (baseIdx
= 0, lim
= uvars
->userMeta
->methodCount
; lim
; lim
>>= 1) {
1362 idx
= baseIdx
+ (lim
>> 1);
1363 if (msgid
== uvars
->userMeta
->methods
[idx
]) {
1364 option
= uvars
->userMeta
->methods
[uvars
->userMeta
->methodCount
+ idx
];
1366 if (option
< uvars
->userMeta
->queueNames
->count
) {
1367 queue
= uvars
->queueArray
[option
+ 1];
1370 } else if (msgid
> uvars
->userMeta
->methods
[idx
]) {
1372 baseIdx
+= (lim
>> 1) + 1;
1382 IOUserServer::objectInstantiate(OSObject
* obj
, IORPC rpc
, IORPCMessage
* message
)
1387 IOService
* service
;
1391 uint32_t queueCount
, queueAlloc
;
1392 const char * resultClassName
;
1393 uint64_t resultFlags
;
1396 uint32_t methodCount
;
1397 const uint64_t * methods
;
1398 IODispatchQueue
* queue
;
1399 OSUserMetaClass
* userMeta
;
1400 OSObjectUserVars
* uvars
;
1402 ipc_port_t sendPort
;
1404 OSObject_Instantiate_Rpl_Content
* reply
;
1412 resultClassName
= NULL
;
1414 ret
= kIOReturnUnsupportedMode
;
1416 service
= OSDynamicCast(IOService
, obj
);
1418 // xxx other classes hosted
1419 resultFlags
|= kOSObjectRPCKernel
;
1420 resultFlags
|= kOSObjectRPCRemote
;
1422 if (service
->isInactive()) {
1423 DKLOG(DKS
"::instantiate inactive\n", DKN(service
));
1424 return kIOReturnOffline
;
1426 prop
= service
->copyProperty(gIOUserClassKey
);
1427 str
= OSDynamicCast(OSString
, prop
);
1428 if (!service
->reserved
->uvars
) {
1429 resultFlags
|= kOSObjectRPCRemote
;
1430 resultFlags
|= kOSObjectRPCKernel
;
1431 } else if (this != service
->reserved
->uvars
->userServer
) {
1432 // remote, use base class
1433 resultFlags
|= kOSObjectRPCRemote
;
1435 if (service
->reserved
->uvars
&& service
->reserved
->uvars
->userServer
) {
1436 userMeta
= (typeof(userMeta
))service
->reserved
->uvars
->userServer
->fClasses
->getObject(str
);
1439 if (!str
&& !userMeta
) {
1440 const OSMetaClass
* meta
;
1441 meta
= obj
->getMetaClass();
1442 while (meta
&& !userMeta
) {
1443 str
= (OSString
*) meta
->getClassNameSymbol();
1444 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
1446 meta
= meta
->getSuperClass();
1452 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
1454 if (kIODKLogSetup
& gIODKDebug
) {
1455 DKLOG("userMeta %s %p\n", str
->getCStringNoCopy(), userMeta
);
1458 if (kOSObjectRPCRemote
& resultFlags
) {
1459 while (userMeta
&& !(kOSClassCanRemote
& userMeta
->description
->flags
)) {
1460 userMeta
= userMeta
->superMeta
;
1463 resultClassName
= userMeta
->description
->name
;
1464 ret
= kIOReturnSuccess
;
1467 service
->reserved
->uvars
->userMeta
= userMeta
;
1469 if (userMeta
->queueNames
) {
1470 queueAlloc
+= userMeta
->queueNames
->count
;
1472 service
->reserved
->uvars
->queueArray
=
1473 IONewZero(IODispatchQueue
*, queueAlloc
);
1474 resultClassName
= str
->getCStringNoCopy();
1475 ret
= kIOReturnSuccess
;
1479 OSSafeReleaseNULL(prop
);
1481 IORPCMessageMach
* machReply
= rpc
.reply
;
1482 replySize
= sizeof(OSObject_Instantiate_Rpl
);
1484 if ((kIOReturnSuccess
== ret
) && (kOSObjectRPCRemote
& resultFlags
)) {
1486 if ((action
= OSDynamicCast(OSAction
, obj
))) {
1487 if (action
->ivars
->referenceSize
) {
1488 resultFlags
|= kOSObjectRPCKernel
;
1490 resultFlags
&= ~kOSObjectRPCKernel
;
1491 target
= action
->ivars
->target
;
1494 queue
= queueForObject(target
, action
->ivars
->targetmsgid
);
1497 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
1498 sendPort
= ipc_port_make_send(queue
->ivars
->serverPort
);
1500 replySize
= sizeof(OSObject_Instantiate_Rpl
)
1501 + queueCount
* sizeof(machReply
->objects
[0])
1502 + 2 * methodCount
* sizeof(reply
->methods
[0]);
1503 if (replySize
> rpc
.replySize
) {
1505 return kIOReturnIPCError
;
1507 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
1508 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1509 machReply
->objects
[idx
].name
= sendPort
;
1510 machReply
->objects
[idx
].pad2
= 0;
1511 machReply
->objects
[idx
].pad_end
= 0;
1514 uvars
= varsForObject(target
);
1515 if (uvars
&& uvars
->userMeta
) {
1517 if (uvars
->userMeta
->queueNames
) {
1518 queueCount
+= uvars
->userMeta
->queueNames
->count
;
1520 methods
= &uvars
->userMeta
->methods
[0];
1521 methodCount
= uvars
->userMeta
->methodCount
;
1522 replySize
= sizeof(OSObject_Instantiate_Rpl
)
1523 + queueCount
* sizeof(machReply
->objects
[0])
1524 + 2 * methodCount
* sizeof(reply
->methods
[0]);
1525 if (replySize
> rpc
.replySize
) {
1527 return kIOReturnIPCError
;
1529 for (idx
= 0; idx
< queueCount
; idx
++) {
1530 queue
= uvars
->queueArray
[idx
];
1533 sendPort
= ipc_port_make_send(queue
->ivars
->serverPort
);
1535 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
1536 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1537 machReply
->objects
[idx
].name
= sendPort
;
1538 machReply
->objects
[idx
].pad2
= 0;
1539 machReply
->objects
[idx
].pad_end
= 0;
1545 if (kIODKLogIPC
& gIODKDebug
) {
1546 DKLOG("instantiate %s\n", obj
->getMetaClass()->getClassName());
1549 if (kIOReturnSuccess
!= ret
) {
1550 DKLOG("%s: no user class found\n", str
? str
->getCStringNoCopy() : obj
->getMetaClass()->getClassName());
1551 resultClassName
= "unknown";
1554 machReply
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
1555 machReply
->msgh
.msgh_size
= replySize
;
1556 machReply
->msgh_body
.msgh_descriptor_count
= queueCount
;
1558 reply
= (typeof(reply
))IORPCMessageFromMach(machReply
, true);
1560 return kIOReturnIPCError
;
1563 bcopy(methods
, &reply
->methods
[0], methodCount
* 2 * sizeof(reply
->methods
[0]));
1565 reply
->__hdr
.msgid
= OSObject_Instantiate_ID
;
1566 reply
->__hdr
.flags
= kIORPCMessageOneway
;
1567 reply
->__hdr
.objectRefs
= 0;
1569 reply
->flags
= resultFlags
;
1570 strlcpy(reply
->classname
, resultClassName
, sizeof(reply
->classname
));
1571 reply
->__result
= ret
;
1573 ret
= kIOReturnSuccess
;
1578 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1581 IOUserServer::kernelDispatch(OSObject
* obj
, IORPC rpc
)
1584 IORPCMessage
* message
;
1586 message
= IORPCMessageFromMach(rpc
.message
, false);
1588 return kIOReturnIPCError
;
1591 if (OSObject_Instantiate_ID
== message
->msgid
) {
1592 ret
= objectInstantiate(obj
, rpc
, message
);
1593 if (kIOReturnSuccess
!= ret
) {
1594 DKLOG("%s: instantiate failed 0x%x\n", obj
->getMetaClass()->getClassName(), ret
);
1597 if (kIODKLogIPC
& gIODKDebug
) {
1598 DKLOG("%s::Dispatch kernel 0x%qx\n", obj
->getMetaClass()->getClassName(), message
->msgid
);
1600 ret
= obj
->Dispatch(rpc
);
1601 if (kIODKLogIPC
& gIODKDebug
) {
1602 DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj
->getMetaClass()->getClassName(), message
->msgid
, ret
);
1610 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1613 IOUserServer::target(OSAction
* action
, IORPCMessage
* message
)
1617 if (message
->msgid
!= action
->ivars
->msgid
) {
1620 object
= action
->ivars
->target
;
1621 message
->msgid
= action
->ivars
->targetmsgid
;
1622 message
->objects
[0] = (OSObjectRef
) object
;
1623 if (kIORPCMessageRemote
& message
->flags
) {
1627 if (kIODKLogIPC
& gIODKDebug
) {
1628 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
, action
->ivars
->msgid
);
1634 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1637 uext_server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
1640 IORPCMessageMach
* msgin
;
1642 IOUserServer
* server
;
1644 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
1646 object
= IOUserServer::copyObjectForSendRight(msgin
->msgh
.msgh_remote_port
, IKOT_UEXT_OBJECT
);
1647 server
= OSDynamicCast(IOUserServer
, object
);
1649 OSSafeReleaseNULL(object
);
1650 return KERN_INVALID_NAME
;
1652 ret
= server
->server(requestkmsg
, pReply
);
1658 #define MAX_UEXT_REPLY_SIZE 0x17c0
1661 IOUserServer::server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
1664 mach_msg_size_t replyAlloc
;
1665 ipc_kmsg_t replykmsg
;
1666 IORPCMessageMach
* msgin
;
1667 IORPCMessage
* message
;
1668 IORPCMessageMach
* msgout
;
1669 IORPCMessage
* reply
;
1676 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
1681 if (msgin
->msgh
.msgh_size
< (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
1682 if (kIODKLogIPC
& gIODKDebug
) {
1683 DKLOG("UEXT notify %o\n", msgin
->msgh
.msgh_id
);
1685 return KERN_NOT_SUPPORTED
;
1688 if (!(MACH_MSGH_BITS_COMPLEX
& msgin
->msgh
.msgh_bits
)) {
1689 msgin
->msgh_body
.msgh_descriptor_count
= 0;
1691 message
= IORPCMessageFromMach(msgin
, false);
1693 return kIOReturnIPCError
;
1695 ret
= copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, true, false);
1696 if (kIOReturnSuccess
!= ret
) {
1697 if (kIODKLogIPC
& gIODKDebug
) {
1698 DKLOG("UEXT copyin(0x%x) %x\n", ret
, msgin
->msgh
.msgh_id
);
1700 return KERN_NOT_SUPPORTED
;
1703 if (msgin
->msgh_body
.msgh_descriptor_count
< 1) {
1704 return KERN_NOT_SUPPORTED
;
1706 object
= (OSObject
*) message
->objects
[0];
1707 msgid
= message
->msgid
;
1708 message
->flags
&= ~kIORPCMessageKernel
;
1709 message
->flags
|= kIORPCMessageRemote
;
1711 if ((action
= OSDynamicCast(OSAction
, object
))) {
1712 object
= target(action
, message
);
1713 msgid
= message
->msgid
;
1716 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
1717 assert(oneway
|| (MACH_PORT_NULL
!= msgin
->msgh
.msgh_local_port
));
1719 // includes trailer size
1720 replyAlloc
= oneway
? 0 : MAX_UEXT_REPLY_SIZE
;
1722 replykmsg
= ipc_kmsg_alloc(replyAlloc
);
1723 if (replykmsg
== NULL
) {
1724 // printf("uext_server: dropping request\n");
1725 // ipc_kmsg_trace_send(request, option);
1726 consumeObjects(message
, msgin
->msgh
.msgh_size
);
1727 ipc_kmsg_destroy(requestkmsg
);
1728 return KERN_MEMORY_FAILURE
;
1731 msgout
= (typeof(msgout
))ipc_kmsg_msg_header(replykmsg
);
1733 * MIG should really assure no data leakage -
1734 * but until it does, pessimistically zero the
1735 * whole reply buffer.
1737 bzero((void *)msgout
, replyAlloc
);
1740 IORPC rpc
= { .message
= msgin
, .sendSize
= msgin
->msgh
.msgh_size
, .reply
= msgout
, .replySize
= replyAlloc
};
1743 thread_iokit_tls_set(0, this);
1744 ret
= kernelDispatch(object
, rpc
);
1745 thread_iokit_tls_set(0, NULL
);
1747 ret
= kIOReturnBadArgument
;
1751 consumeObjects(message
, msgin
->msgh
.msgh_size
);
1754 copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, false, true);
1757 if (kIOReturnSuccess
== ret
) {
1758 replySize
= msgout
->msgh
.msgh_size
;
1759 reply
= IORPCMessageFromMach(msgout
, true);
1761 ret
= kIOReturnIPCError
;
1763 ret
= copyOutObjects(msgout
, reply
, replySize
, (kIORPCVersionCurrentReply
== msgout
->msgh
.msgh_id
) /* =>!InvokeReply */);
1766 if (kIOReturnSuccess
!= ret
) {
1767 IORPCMessageErrorReturnContent
* errorMsg
;
1769 msgout
->msgh_body
.msgh_descriptor_count
= 0;
1770 msgout
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
1771 errorMsg
= (typeof(errorMsg
))IORPCMessageFromMach(msgout
, true);
1772 errorMsg
->hdr
.msgid
= message
->msgid
;
1773 errorMsg
->hdr
.flags
= kIORPCMessageOneway
| kIORPCMessageError
;
1774 errorMsg
->hdr
.objectRefs
= 0;
1775 errorMsg
->result
= ret
;
1777 replySize
= sizeof(IORPCMessageErrorReturn
);
1780 msgout
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
1781 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin
->msgh
.msgh_bits
) /*remote*/, 0 /*local*/, 0, 0);
1783 msgout
->msgh
.msgh_remote_port
= msgin
->msgh
.msgh_local_port
;
1784 msgout
->msgh
.msgh_local_port
= MACH_PORT_NULL
;
1785 msgout
->msgh
.msgh_voucher_port
= (mach_port_name_t
) 0;
1786 msgout
->msgh
.msgh_reserved
= 0;
1787 msgout
->msgh
.msgh_size
= replySize
;
1790 *pReply
= replykmsg
;
1792 return oneway
? MIG_NO_REPLY
: KERN_SUCCESS
;
1795 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1797 #define MAX_OBJECT_COUNT(mach, size, message) \
1798 ((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))
1801 IOUserServerUEXTTrap(OSObject
* object
, void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
1803 const user_addr_t msg
= (uintptr_t) p1
;
1804 size_t inSize
= (uintptr_t) p2
;
1805 user_addr_t out
= (uintptr_t) p3
;
1806 size_t outSize
= (uintptr_t) p4
;
1807 mach_port_name_t objectName1
= (uintptr_t) p5
;
1809 OSObject
* objectArg1
;
1811 IORPCMessageMach
* mach
;
1812 mach_msg_port_descriptor_t
* descs
;
1817 IORPCMessageMach mach
;
1818 mach_msg_port_descriptor_t objects
[2];
1819 IOTrapMessageBuffer buffer
;
1826 IORPCMessage
* message
;
1827 IORPCMessage
* reply
;
1830 uint32_t maxObjectCount
;
1832 uint64_t * replyHdr
;
1835 bzero(&buffer
, sizeof(buffer
));
1837 p
= (typeof(p
)) & buffer
.buffer
[0];
1838 if (os_add_overflow(inSize
, outSize
, &totalSize
)) {
1839 return kIOReturnMessageTooLarge
;
1841 if (totalSize
> sizeof(buffer
.buffer
)) {
1842 return kIOReturnMessageTooLarge
;
1844 if (inSize
< sizeof(IORPCMessage
)) {
1845 return kIOReturnIPCError
;
1847 copyerr
= copyin(msg
, &buffer
.buffer
[0], inSize
);
1849 return kIOReturnVMError
;
1852 message
= (typeof(message
))p
;
1853 refs
= message
->objectRefs
;
1854 if ((refs
> 2) || !refs
) {
1855 return kIOReturnUnsupported
;
1857 if (!(kIORPCMessageSimpleReply
& message
->flags
)) {
1858 return kIOReturnUnsupported
;
1861 descs
= (typeof(descs
))(p
- refs
* sizeof(*descs
));
1862 mach
= (typeof(mach
))(p
- refs
* sizeof(*descs
) - sizeof(*mach
));
1864 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
1865 mach
->msgh
.msgh_size
= sizeof(IORPCMessageMach
) + refs
* sizeof(*descs
) + inSize
;
1866 mach
->msgh_body
.msgh_descriptor_count
= refs
;
1869 rpc
.sendSize
= mach
->msgh
.msgh_size
;
1870 rpc
.reply
= (IORPCMessageMach
*) (p
+ inSize
);
1871 rpc
.replySize
= sizeof(buffer
.buffer
) - inSize
;
1873 message
->objects
[0] = 0;
1874 if ((action
= OSDynamicCast(OSAction
, object
))) {
1875 maxObjectCount
= MAX_OBJECT_COUNT(rpc
.message
, rpc
.sendSize
, message
);
1876 if (refs
> maxObjectCount
) {
1877 return kIOReturnBadArgument
;
1879 object
= IOUserServer::target(action
, message
);
1880 message
->objects
[1] = (OSObjectRef
) action
;
1881 if (kIODKLogIPC
& gIODKDebug
) {
1882 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
1884 ret
= object
->Dispatch(rpc
);
1888 objectArg1
= iokit_lookup_uext_ref_current_task(objectName1
);
1890 return kIOReturnIPCError
;
1892 message
->objects
[1] = (OSObjectRef
) objectArg1
;
1894 if (kIODKLogIPC
& gIODKDebug
) {
1895 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
1897 ret
= object
->Dispatch(rpc
);
1898 if (kIODKLogIPC
& gIODKDebug
) {
1899 DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object
->getMetaClass()->getClassName(), message
->msgid
, ret
);
1901 OSSafeReleaseNULL(objectArg1
);
1903 if (kIOReturnSuccess
== ret
) {
1904 if (rpc
.reply
->msgh_body
.msgh_descriptor_count
) {
1905 return kIOReturnIPCError
;
1907 reply
= IORPCMessageFromMach(rpc
.reply
, rpc
.reply
->msgh
.msgh_size
);
1909 return kIOReturnIPCError
;
1911 copySize
= rpc
.reply
->msgh
.msgh_size
- (((uintptr_t) reply
) - ((uintptr_t) rpc
.reply
)) + sizeof(uint64_t);
1912 if (copySize
> outSize
) {
1913 return kIOReturnIPCError
;
1915 replyHdr
= (uint64_t *) reply
;
1917 replyHdr
[0] = copySize
;
1918 copyerr
= copyout(replyHdr
, out
, copySize
);
1920 return kIOReturnVMError
;
1928 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1931 IOUserServer::rpc(IORPC rpc
)
1933 if (isInactive() && !fRootQueue
) {
1934 return kIOReturnOffline
;
1938 IORPCMessage
* message
;
1939 IORPCMessageMach
* mach
;
1940 mach_msg_id_t machid
;
1941 uint32_t sendSize
, replySize
;
1944 IODispatchQueue
* queue
;
1945 IOService
* service
;
1947 ipc_port_t sendPort
;
1954 sendSize
= rpc
.sendSize
;
1955 replySize
= rpc
.replySize
;
1957 assert(sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
1959 message
= IORPCMessageFromMach(mach
, false);
1961 ret
= kIOReturnIPCError
;
1963 msgid
= message
->msgid
;
1964 machid
= (msgid
>> 32);
1966 if (mach
->msgh_body
.msgh_descriptor_count
< 1) {
1967 return kIOReturnNoMedia
;
1970 IOLockLock(gIOUserServerLock
);
1971 if ((service
= OSDynamicCast(IOService
, (OSObject
*) message
->objects
[0]))) {
1972 queue
= queueForObject(service
, msgid
);
1977 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
1978 port
= queue
->ivars
->serverPort
;
1981 sendPort
= ipc_port_make_send(port
);
1983 IOLockUnlock(gIOUserServerLock
);
1985 return kIOReturnNotReady
;
1988 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
1990 ret
= copyOutObjects(mach
, message
, sendSize
, false);
1992 mach
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
1993 MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND
, (oneway
? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE
));
1994 mach
->msgh
.msgh_remote_port
= sendPort
;
1995 mach
->msgh
.msgh_local_port
= (oneway
? MACH_PORT_NULL
: mig_get_reply_port());
1996 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
1997 mach
->msgh
.msgh_reserved
= 0;
2000 ret
= mach_msg_send_from_kernel(&mach
->msgh
, sendSize
);
2002 assert(replySize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
2003 ret
= mach_msg_rpc_from_kernel(&mach
->msgh
, sendSize
, replySize
);
2004 if (KERN_SUCCESS
== ret
) {
2005 if (kIORPCVersionCurrentReply
!= mach
->msgh
.msgh_id
) {
2006 ret
= (MACH_NOTIFY_SEND_ONCE
== mach
->msgh
.msgh_id
) ? MIG_SERVER_DIED
: MIG_REPLY_MISMATCH
;
2007 } else if ((replySize
= mach
->msgh
.msgh_size
) < (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
2008 // printf("BAD REPLY SIZE\n");
2009 ret
= MIG_BAD_ARGUMENTS
;
2011 if (!(MACH_MSGH_BITS_COMPLEX
& mach
->msgh
.msgh_bits
)) {
2012 mach
->msgh_body
.msgh_descriptor_count
= 0;
2014 message
= IORPCMessageFromMach(mach
, true);
2016 ret
= kIOReturnIPCError
;
2017 } else if (message
->msgid
!= msgid
) {
2018 // printf("BAD REPLY ID\n");
2019 ret
= MIG_BAD_ARGUMENTS
;
2021 bool isError
= (0 != (kIORPCMessageError
& message
->flags
));
2022 ret
= copyInObjects(mach
, message
, replySize
, !isError
, true);
2023 if (kIOReturnSuccess
!= ret
) {
2024 if (kIODKLogIPC
& gIODKDebug
) {
2025 DKLOG("rpc copyin(0x%x) %x\n", ret
, mach
->msgh
.msgh_id
);
2027 return KERN_NOT_SUPPORTED
;
2030 IORPCMessageErrorReturnContent
* errorMsg
= (typeof(errorMsg
))message
;
2031 ret
= errorMsg
->result
;
2041 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2044 IORPCMessageFromMach(IORPCMessageMach
* msg
, bool reply
)
2046 mach_msg_size_t idx
, count
;
2047 mach_msg_port_descriptor_t
* desc
;
2048 mach_msg_port_descriptor_t
* maxDesc
;
2049 size_t size
, msgsize
;
2052 msgsize
= msg
->msgh
.msgh_size
;
2053 count
= msg
->msgh_body
.msgh_descriptor_count
;
2054 desc
= &msg
->objects
[0];
2055 maxDesc
= (typeof(maxDesc
))(((uintptr_t) msg
) + msgsize
);
2056 upgrade
= (msg
->msgh
.msgh_id
!= (reply
? kIORPCVersionCurrentReply
: kIORPCVersionCurrent
));
2059 OSReportWithBacktrace("obsolete message");
2063 for (idx
= 0; idx
< count
; idx
++) {
2064 if (desc
>= maxDesc
) {
2067 switch (desc
->type
) {
2068 case MACH_MSG_PORT_DESCRIPTOR
:
2069 size
= sizeof(mach_msg_port_descriptor_t
);
2071 case MACH_MSG_OOL_DESCRIPTOR
:
2072 size
= sizeof(mach_msg_ool_descriptor_t
);
2077 desc
= (typeof(desc
))(((uintptr_t) desc
) + size
);
2079 return (IORPCMessage
*)(uintptr_t) desc
;
2083 IOUserServer::copySendRightForObject(OSObject
* object
, ipc_kobject_type_t type
)
2086 ipc_port_t sendPort
= NULL
;
2088 port
= iokit_port_for_object(object
, type
);
2090 sendPort
= ipc_port_make_send(port
);
2091 iokit_release_port(port
);
2098 IOUserServer::copyObjectForSendRight(ipc_port_t port
, ipc_kobject_type_t type
)
2101 object
= iokit_lookup_io_object(port
, type
);
2105 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2107 // Create a vm_map_copy_t or kalloc'ed data for memory
2108 // to be copied out. ipc will free after the copyout.
2110 static kern_return_t
2111 copyoutkdata(const void * data
, vm_size_t len
, void ** buf
)
2116 err
= vm_map_copyin( kernel_map
, CAST_USER_ADDR_T(data
), len
,
2117 false /* src_destroy */, ©
);
2119 assert( err
== KERN_SUCCESS
);
2120 if (err
== KERN_SUCCESS
) {
2121 *buf
= (char *) copy
;
2127 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2130 IOUserServer::copyOutObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
2131 size_t size
, bool consume
)
2134 uint32_t idx
, maxObjectCount
;
2138 mach_msg_port_descriptor_t
* desc
;
2139 mach_msg_ool_descriptor_t
* ool
;
2142 mach_msg_size_t length
;
2146 refs
= message
->objectRefs
;
2147 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
2148 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2149 // assert(refs <= maxObjectCount);
2150 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
2151 return kIOReturnBadArgument
;
2153 if (refs
> maxObjectCount
) {
2154 return kIOReturnBadArgument
;
2157 desc
= &mach
->objects
[0];
2158 for (idx
= 0; idx
< refs
; idx
++) {
2159 object
= (OSObject
*) message
->objects
[idx
];
2161 switch (desc
->type
) {
2162 case MACH_MSG_PORT_DESCRIPTOR
:
2163 descsize
= sizeof(mach_msg_port_descriptor_t
);
2166 port
= copySendRightForObject(object
, IKOT_UEXT_OBJECT
);
2173 message
->objects
[idx
] = 0;
2175 // desc->type = MACH_MSG_PORT_DESCRIPTOR;
2176 desc
->disposition
= MACH_MSG_TYPE_MOVE_SEND
;
2182 case MACH_MSG_OOL_DESCRIPTOR
:
2183 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2188 s
= OSSerialize::binaryWithCapacity(4096);
2193 s
->setIndexed(true);
2194 if (!object
->serialize(s
)) {
2200 length
= s
->getLength();
2201 kr
= copyoutkdata(s
->text(), length
, &address
);
2203 if (KERN_SUCCESS
!= kr
) {
2211 message
->objects
[idx
] = 0;
2213 ool
= (typeof(ool
))desc
;
2214 // ool->type = MACH_MSG_OOL_DESCRIPTOR;
2215 ool
->deallocate
= false;
2216 ool
->copy
= MACH_MSG_PHYSICAL_COPY
;
2218 ool
->address
= address
;
2225 if (-1UL == descsize
) {
2228 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2232 return kIOReturnSuccess
;
2235 desc
= &mach
->objects
[0];
2237 switch (desc
->type
) {
2238 case MACH_MSG_PORT_DESCRIPTOR
:
2239 descsize
= sizeof(mach_msg_port_descriptor_t
);
2242 ipc_port_release_send(port
);
2246 case MACH_MSG_OOL_DESCRIPTOR
:
2247 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2248 ool
= (typeof(ool
))desc
;
2249 copy
= (vm_map_copy_t
) ool
->address
;
2251 vm_map_copy_discard(copy
);
2259 if (-1UL == descsize
) {
2262 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2265 return kIOReturnBadArgument
;
2269 IOUserServer::copyInObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
2270 size_t size
, bool copyObjects
, bool consumePorts
)
2273 uint32_t idx
, maxObjectCount
;
2277 mach_msg_port_descriptor_t
* desc
;
2278 mach_msg_ool_descriptor_t
* ool
;
2279 vm_map_address_t copyoutdata
;
2282 refs
= message
->objectRefs
;
2283 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
2284 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
2285 // assert(refs <= maxObjectCount);
2286 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
2287 return kIOReturnBadArgument
;
2289 if (refs
> maxObjectCount
) {
2290 return kIOReturnBadArgument
;
2293 desc
= &mach
->objects
[0];
2294 for (idx
= 0; idx
< refs
; idx
++) {
2295 switch (desc
->type
) {
2296 case MACH_MSG_PORT_DESCRIPTOR
:
2297 descsize
= sizeof(mach_msg_port_descriptor_t
);
2303 object
= copyObjectForSendRight(port
, IKOT_UEXT_OBJECT
);
2310 ipc_port_release_send(port
);
2315 case MACH_MSG_OOL_DESCRIPTOR
:
2316 descsize
= sizeof(mach_msg_ool_descriptor_t
);
2317 ool
= (typeof(ool
))desc
;
2320 if (copyObjects
&& ool
->size
&& ool
->address
) {
2321 kr
= vm_map_copyout(kernel_map
, ©outdata
, (vm_map_copy_t
) ool
->address
);
2322 if (KERN_SUCCESS
== kr
) {
2323 object
= OSUnserializeXML((const char *) copyoutdata
, ool
->size
);
2324 // vm_map_copyout() has consumed the vm_map_copy_t in the message
2326 ool
->address
= NULL
;
2327 kr
= vm_deallocate(kernel_map
, copyoutdata
, ool
->size
);
2328 assert(KERN_SUCCESS
== kr
);
2341 if (-1UL == descsize
) {
2345 message
->objects
[idx
] = (OSObjectRef
) object
;
2347 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
2351 return kIOReturnSuccess
;
2355 object
= (OSObject
*) message
->objects
[idx
];
2357 message
->objects
[idx
] = 0;
2360 return kIOReturnBadArgument
;
2364 IOUserServer::consumeObjects(IORPCMessage
* message
, size_t messageSize
)
2369 refs
= message
->objectRefs
;
2370 for (idx
= 0; idx
< refs
; idx
++) {
2371 object
= (OSObject
*) message
->objects
[idx
];
2374 message
->objects
[idx
] = 0;
2378 return kIOReturnSuccess
;
2381 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2384 IOUserServer::finalize(IOOptionBits options
)
2388 if (kIODKLogSetup
& gIODKDebug
) {
2389 DKLOG("%s::finalize(%p)\n", getName(), this);
2392 IOLockLock(gIOUserServerLock
);
2393 OSSafeReleaseNULL(fRootQueue
);
2394 IOLockUnlock(gIOUserServerLock
);
2399 services
= OSArray::withArray(fServices
);
2401 IOLockUnlock(fLock
);
2404 services
->iterateObjects(^bool (OSObject
* obj
) {
2405 IOService
* service
;
2406 IOService
* provider
;
2407 bool started
= false;
2409 service
= (IOService
*) obj
;
2410 if (kIODKLogSetup
& gIODKDebug
) {
2411 DKLOG("%s::terminate(" DKS
")\n", getName(), DKN(service
));
2413 if (service
->reserved
->uvars
) {
2414 started
= service
->reserved
->uvars
->started
;
2415 service
->reserved
->uvars
->serverDied
= true;
2417 provider
= service
->getProvider();
2418 serviceDidStop(service
, provider
);
2419 service
->terminate(kIOServiceTerminateNeedWillTerminate
| kIOServiceTerminateWithRematch
);
2423 DKLOG("%s::terminate(" DKS
") server exit before start()\n", getName(), DKN(service
));
2424 serviceStop(service
, NULL
);
2428 services
->release();
2431 return IOUserClient::finalize(options
);
2434 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2437 #define super IOUserClient
2439 OSDefineMetaClassAndStructors(IOUserServer
, IOUserClient
)
2441 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2443 IOUserClient
* IOUserServer::withTask(task_t owningTask
)
2445 IOUserServer
* inst
;
2447 inst
= new IOUserServer
;
2448 if (inst
&& !inst
->init()) {
2455 inst
->fOwningTask
= current_task();
2456 inst
->fEntitlements
= IOUserClient::copyClientEntitlements(inst
->fOwningTask
);
2458 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
2459 if (!inst
->fEntitlements
|| !inst
->fEntitlements
->getObject(gIODriverKitEntitlementKey
)) {
2463 p
= (proc_t
)get_bsdtask_info(inst
->fOwningTask
);
2466 IOLog(kIODriverKitEntitlementKey
" entitlement check failed for %s[%d]\n", proc_best_name(p
), pid
);
2474 inst
->fLock
= IOLockAlloc();
2475 inst
->fServices
= OSArray::withCapacity(4);
2476 inst
->fClasses
= OSDictionary::withCapacity(16);
2477 inst
->fClasses
->setOptions(OSCollection::kSort
, OSCollection::kSort
);
2483 IOUserServer::clientClose(void)
2486 return kIOReturnSuccess
;
2490 IOUserServer::setProperties(OSObject
* properties
)
2492 IOReturn kr
= kIOReturnUnsupported
;
2497 IOUserServer::stop(IOService
* provider
)
2499 fOwningTask
= TASK_NULL
;
2503 IOServicePH::serverRemove(this);
2505 OSSafeReleaseNULL(fRootQueue
);
2507 if (fInterruptLock
) {
2508 IOSimpleLockFree(fInterruptLock
);
2513 IOUserServer::free()
2515 OSSafeReleaseNULL(fEntitlements
);
2516 OSSafeReleaseNULL(fClasses
);
2520 OSSafeReleaseNULL(fServices
);
2521 IOUserClient::free();
2525 IOUserServer::registerClass(OSClassDescription
* desc
, uint32_t size
, OSUserMetaClass
** pCls
)
2527 OSUserMetaClass
* cls
;
2528 const OSSymbol
* sym
;
2529 uint64_t * methodOptions
;
2530 const char * queueNames
;
2531 uint32_t methodOptionsEnd
, queueNamesEnd
;
2532 IOReturn ret
= kIOReturnSuccess
;
2534 if (size
< sizeof(OSClassDescription
)) {
2536 return kIOReturnBadArgument
;
2539 if (kIODKLogSetup
& gIODKDebug
) {
2540 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc
->name
, desc
->queueNamesSize
, desc
->methodNamesSize
);
2543 if (desc
->descriptionSize
!= size
) {
2545 return kIOReturnBadArgument
;
2547 if (os_add_overflow(desc
->queueNamesOffset
, desc
->queueNamesSize
, &queueNamesEnd
)) {
2549 return kIOReturnBadArgument
;
2551 if (queueNamesEnd
> size
) {
2553 return kIOReturnBadArgument
;
2555 if (os_add_overflow(desc
->methodOptionsOffset
, desc
->methodOptionsSize
, &methodOptionsEnd
)) {
2557 return kIOReturnBadArgument
;
2559 if (methodOptionsEnd
> size
) {
2561 return kIOReturnBadArgument
;
2564 if ((desc
->queueNamesOffset
>= desc
->methodOptionsOffset
) && (desc
->queueNamesOffset
< methodOptionsEnd
)) {
2566 return kIOReturnBadArgument
;
2568 if ((queueNamesEnd
>= desc
->methodOptionsOffset
) && (queueNamesEnd
< methodOptionsEnd
)) {
2570 return kIOReturnBadArgument
;
2573 if (desc
->methodOptionsSize
& ((2 * sizeof(uint64_t)) - 1)) {
2575 return kIOReturnBadArgument
;
2577 if (sizeof(desc
->name
) == strnlen(desc
->name
, sizeof(desc
->name
))) {
2579 return kIOReturnBadArgument
;
2581 if (sizeof(desc
->superName
) == strnlen(desc
->superName
, sizeof(desc
->superName
))) {
2583 return kIOReturnBadArgument
;
2586 cls
= OSTypeAlloc(OSUserMetaClass
);
2589 return kIOReturnNoMemory
;
2592 cls
->description
= (typeof(cls
->description
))IOMalloc(size
);
2593 assert(cls
->description
);
2594 if (!cls
->description
) {
2597 return kIOReturnNoMemory
;
2599 bcopy(desc
, cls
->description
, size
);
2601 cls
->methodCount
= desc
->methodOptionsSize
/ (2 * sizeof(uint64_t));
2602 cls
->methods
= IONew(uint64_t, 2 * cls
->methodCount
);
2603 if (!cls
->methods
) {
2606 return kIOReturnNoMemory
;
2609 methodOptions
= (typeof(methodOptions
))(((uintptr_t) desc
) + desc
->methodOptionsOffset
);
2610 bcopy(methodOptions
, cls
->methods
, 2 * cls
->methodCount
* sizeof(uint64_t));
2612 queueNames
= (typeof(queueNames
))(((uintptr_t) desc
) + desc
->queueNamesOffset
);
2613 cls
->queueNames
= copyInStringArray(queueNames
, desc
->queueNamesSize
);
2615 sym
= OSSymbol::withCString(desc
->name
);
2620 return kIOReturnNoMemory
;
2624 cls
->meta
= OSMetaClass::copyMetaClassWithName(sym
);
2625 cls
->superMeta
= OSDynamicCast(OSUserMetaClass
, fClasses
->getObject(desc
->superName
));
2626 fClasses
->setObject(sym
, cls
);
2635 IOUserServer::setRootQueue(IODispatchQueue
* queue
)
2637 assert(!fRootQueue
);
2639 return kIOReturnStillOpen
;
2644 return kIOReturnSuccess
;
2648 IOUserServer::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
2649 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
2651 IOReturn ret
= kIOReturnBadArgument
;
2652 mach_port_name_t portname
;
2655 case kIOUserServerMethodRegisterClass
:
2657 OSUserMetaClass
* cls
;
2658 if (!args
->structureInputSize
) {
2659 return kIOReturnBadArgument
;
2661 if (args
->scalarOutputCount
!= 2) {
2662 return kIOReturnBadArgument
;
2664 ret
= registerClass((OSClassDescription
*) args
->structureInput
, args
->structureInputSize
, &cls
);
2665 if (kIOReturnSuccess
== ret
) {
2666 portname
= iokit_make_send_right(fOwningTask
, cls
, IKOT_UEXT_OBJECT
);
2668 args
->scalarOutput
[0] = portname
;
2669 args
->scalarOutput
[1] = kOSObjectRPCRemote
;
2673 case kIOUserServerMethodStart
:
2675 if (args
->scalarOutputCount
!= 1) {
2676 return kIOReturnBadArgument
;
2678 portname
= iokit_make_send_right(fOwningTask
, this, IKOT_UEXT_OBJECT
);
2680 args
->scalarOutput
[0] = portname
;
2681 ret
= kIOReturnSuccess
;
2692 IOUserServer::getTargetAndTrapForIndex( IOService
**targetP
, UInt32 index
)
2694 static const IOExternalTrap trapTemplate
[] = {
2695 { NULL
, (IOTrap
) & IOUserServer::waitInterruptTrap
},
2697 if (index
>= (sizeof(trapTemplate
) / sizeof(IOExternalTrap
))) {
2701 return (IOExternalTrap
*)&trapTemplate
[index
];
2704 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2707 IOUserServer::serviceAttach(IOService
* service
, IOService
* provider
)
2710 OSObjectUserVars
* vars
;
2713 OSSymbolConstPtr bundleID
;
2714 char execPath
[1024];
2716 vars
= IONewZero(OSObjectUserVars
, 1);
2717 service
->reserved
->uvars
= vars
;
2719 vars
->userServer
= this;
2720 vars
->userServer
->retain();
2722 if (-1U == fServices
->getNextIndexOfObject(service
, 0)) {
2723 fServices
->setObject(service
);
2725 IOLockUnlock(fLock
);
2727 prop
= service
->copyProperty(gIOUserClassKey
);
2728 str
= OSDynamicCast(OSString
, prop
);
2730 service
->setName(str
);
2732 OSSafeReleaseNULL(prop
);
2734 prop
= service
->copyProperty(gIOModuleIdentifierKey
);
2735 bundleID
= OSDynamicCast(OSSymbol
, prop
);
2738 bool ok
= OSKext::copyUserExecutablePath(bundleID
, execPath
, sizeof(execPath
));
2740 ret
= LoadModule(execPath
);
2741 if (kIODKLogSetup
& gIODKDebug
) {
2742 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret
, execPath
);
2746 OSSafeReleaseNULL(prop
);
2748 ret
= kIOReturnSuccess
;
2753 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2755 #define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
2758 IOUserServer::serviceNewUserClient(IOService
* service
, task_t owningTask
, void * securityID
,
2759 uint32_t type
, OSDictionary
* properties
, IOUserClient
** handler
)
2763 IOUserUserClient
* userUC
;
2764 OSDictionary
* entitlements
;
2766 OSObject
* bundleID
;
2770 ret
= service
->NewUserClient(type
, &uc
);
2771 if (kIOReturnSuccess
!= ret
) {
2774 userUC
= OSDynamicCast(IOUserUserClient
, uc
);
2777 OSSafeReleaseNULL(uc
);
2778 return kIOReturnUnsupported
;
2780 userUC
->setTask(owningTask
);
2782 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
2783 entitlements
= IOUserClient::copyClientEntitlements(owningTask
);
2784 bundleID
= service
->copyProperty(gIOModuleIdentifierKey
);
2787 && (prop
= entitlements
->getObject(gIODriverKitUserClientEntitlementsKey
)));
2789 bool found __block
= false;
2790 ok
= prop
->iterateObjects(^bool (OSObject
* object
) {
2791 found
= object
->isEqualTo(bundleID
);
2797 prop
= userUC
->copyProperty(gIOServiceDEXTEntitlementsKey
);
2798 ok
= checkEntitlements(entitlements
, prop
, NULL
, NULL
);
2800 OSSafeReleaseNULL(bundleID
);
2801 OSSafeReleaseNULL(entitlements
);
2803 DKLOG(DKS
":UC entitlements check failed\n", DKN(userUC
));
2805 OSSafeReleaseNULL(uc
);
2806 return kIOReturnNotPermitted
;
2810 ret
= userUC
->Start(service
);
2811 if (kIOReturnSuccess
!= ret
) {
2812 userUC
->detach(this);
2822 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2824 static IOPMPowerState
2826 { .version
= kIOPMPowerStateVersion1
,
2827 .capabilityFlags
= 0,
2828 .outputPowerCharacter
= 0,
2829 .inputPowerRequirement
= 0},
2830 { .version
= kIOPMPowerStateVersion1
,
2831 .capabilityFlags
= kIOPMLowPower
,
2832 .outputPowerCharacter
= kIOPMLowPower
,
2833 .inputPowerRequirement
= kIOPMLowPower
},
2834 { .version
= kIOPMPowerStateVersion1
,
2835 .capabilityFlags
= kIOPMPowerOn
,
2836 .outputPowerCharacter
= kIOPMPowerOn
,
2837 .inputPowerRequirement
= kIOPMPowerOn
},
2841 IOUserServer::setPowerState(unsigned long state
, IOService
* service
)
2843 if (kIODKLogPM
& gIODKDebug
) {
2844 DKLOG(DKS
"::setPowerState(%ld) %d\n", DKN(service
), state
, fSystemPowerAck
);
2846 return kIOPMAckImplied
;
2850 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
2854 if (service
->reserved
->uvars
) {
2855 if (!fSystemOff
&& !(kIODKDisablePM
& gIODKDebug
)) {
2856 service
->reserved
->uvars
->willPower
= true;
2857 if (kIODKLogPM
& gIODKDebug
) {
2858 DKLOG(DKS
"::powerStateWillChangeTo(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
2860 ret
= service
->SetPowerState(flags
);
2861 if (kIOReturnSuccess
== ret
) {
2862 return 20 * 1000 * 1000;
2865 service
->reserved
->uvars
->willPower
= false;
2868 return kIOPMAckImplied
;
2872 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
2879 idx
= fServices
->getNextIndexOfObject(service
, 0);
2881 IOLockUnlock(fLock
);
2882 return kIOPMAckImplied
;
2887 fPowerStates
|= (1ULL << idx
);
2889 fPowerStates
&= ~(1ULL << idx
);
2891 if (kIODKLogPM
& gIODKDebug
) {
2892 DKLOG(DKS
"::powerStateDidChangeTo(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
2894 if (!fPowerStates
&& (pmAck
= fSystemPowerAck
)) {
2895 fSystemPowerAck
= false;
2898 IOLockUnlock(fLock
);
2901 IOServicePH::serverAck(this);
2904 return kIOPMAckImplied
;
2908 IMPL(IOService
, SetPowerState
)
2910 if (kIODKLogPM
& gIODKDebug
) {
2911 DKLOG(DKS
"::SetPowerState(%d), %d\n", DKN(this), powerFlags
, reserved
->uvars
->willPower
);
2914 && reserved
->uvars
->userServer
2915 && reserved
->uvars
->willPower
) {
2916 reserved
->uvars
->willPower
= false;
2917 acknowledgePowerChange(reserved
->uvars
->userServer
);
2918 return kIOReturnSuccess
;
2920 return kIOReturnNotReady
;
2924 IMPL(IOService
, ChangePowerState
)
2926 switch (powerFlags
) {
2927 case kIOServicePowerCapabilityOff
:
2928 changePowerStateToPriv(0);
2930 case kIOServicePowerCapabilityLow
:
2931 changePowerStateToPriv(1);
2933 case kIOServicePowerCapabilityOn
:
2934 changePowerStateToPriv(2);
2937 return kIOReturnBadArgument
;
2940 return kIOReturnSuccess
;
2944 IMPL(IOService
, Create
)
2947 IOService
* service
;
2949 const OSSymbol
* sym
;
2951 OSDictionary
* properties
;
2954 if (provider
!= this) {
2955 return kIOReturnUnsupported
;
2958 ret
= kIOReturnUnsupported
;
2962 prop
= copyProperty(propertiesKey
);
2963 properties
= OSDynamicCast(OSDictionary
, prop
);
2966 str
= OSDynamicCast(OSString
, properties
->getObject(gIOClassKey
));
2968 sym
= OSSymbol::withString(str
);
2970 inst
= OSMetaClass::allocClassWithName(sym
);
2971 service
= OSDynamicCast(IOService
, inst
);
2972 if (service
&& service
->init(properties
) && service
->attach(this)) {
2973 reserved
->uvars
->userServer
->serviceAttach(service
, this);
2974 ret
= kIOReturnSuccess
;
2977 OSSafeReleaseNULL(sym
);
2981 OSSafeReleaseNULL(prop
);
2982 if (kIOReturnSuccess
!= ret
) {
2983 OSSafeReleaseNULL(inst
);
2990 IMPL(IOService
, NewUserClient
)
2992 return kIOReturnError
;
2996 IMPL(IOService
, SearchProperty
)
3000 if (kIOServiceSearchPropertyParents
& options
) {
3001 options
= kIORegistryIterateParents
| kIORegistryIterateRecursively
;
3006 object
= copyProperty(name
, IORegistryEntry::getPlane(plane
), options
);
3009 return object
? kIOReturnSuccess
: kIOReturnNotFound
;
3013 IOUserServer::systemPower(bool powerOff
)
3017 if (kIODKLogPM
& gIODKDebug
) {
3018 DKLOG("%s::powerOff(%d) 0x%qx\n", getName(), powerOff
, fPowerStates
);
3022 services
= OSArray::withArray(fServices
);
3025 fSystemPowerAck
= (0 != fPowerStates
);
3026 if (!fSystemPowerAck
) {
3029 IOLockUnlock(fLock
);
3031 if (!fSystemPowerAck
) {
3032 IOServicePH::serverAck(this);
3035 services
->iterateObjects(^bool (OSObject
* obj
) {
3036 IOService
* service
;
3037 service
= (IOService
*) obj
;
3038 if (kIODKLogPM
& gIODKDebug
) {
3039 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), 0);
3041 service
->reserved
->uvars
->powerOverride
= service
->getPowerState();
3042 service
->changePowerStateWithOverrideTo(0, 0);
3049 IOLockUnlock(fLock
);
3051 services
->iterateObjects(^bool (OSObject
* obj
) {
3052 IOService
* service
;
3053 service
= (IOService
*) obj
;
3054 if (-1U != service
->reserved
->uvars
->powerOverride
) {
3055 if (kIODKLogPM
& gIODKDebug
) {
3056 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), service
->reserved
->uvars
->powerOverride
);
3058 service
->changePowerStateWithOverrideTo(service
->reserved
->uvars
->powerOverride
, 0);
3059 service
->reserved
->uvars
->powerOverride
= -1U;
3065 OSSafeReleaseNULL(services
);
3071 IOUserServer::serviceStarted(IOService
* service
, IOService
* provider
, bool result
)
3074 IOService
* pmProvider
;
3076 DKLOG(DKS
"::start(" DKS
") %s\n", DKN(service
), DKN(provider
), result
? "ok" : "fail");
3079 ret
= kIOReturnSuccess
;
3083 if (!fRootNotifier
) {
3084 ret
= registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
3085 assert(kIOReturnSuccess
== ret
);
3086 IOServicePH::serverAdd(this);
3087 fRootNotifier
= true;
3090 if (!(kIODKDisablePM
& gIODKDebug
) && !service
->pm_vars
) {
3092 ret
= service
->registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
3093 assert(kIOReturnSuccess
== ret
);
3095 pmProvider
= service
;
3096 while (pmProvider
&& !pmProvider
->inPlane(gIOPowerPlane
)) {
3097 pmProvider
= pmProvider
->getProvider();
3102 prop
= pmProvider
->copyProperty("non-removable");
3104 str
= OSDynamicCast(OSString
, prop
);
3105 if (str
&& str
->isEqualTo("yes")) {
3113 unsigned int idx
= fServices
->getNextIndexOfObject(service
, 0);
3115 fPowerStates
|= (1ULL << idx
);
3116 IOLockUnlock(fLock
);
3118 pmProvider
->joinPMtree(service
);
3119 service
->reserved
->uvars
->userServerPM
= true;
3123 service
->registerInterestedDriver(this);
3124 service
->reserved
->uvars
->started
= true;
3126 return kIOReturnSuccess
;
3131 IOUserServer::serviceOpen(IOService
* provider
, IOService
* client
)
3133 OSObjectUserVars
* uvars
;
3135 uvars
= client
->reserved
->uvars
;
3136 if (!uvars
->openProviders
) {
3137 uvars
->openProviders
= OSArray::withObjects((const OSObject
**) &provider
, 1);
3138 } else if (-1U == uvars
->openProviders
->getNextIndexOfObject(client
, 0)) {
3139 uvars
->openProviders
->setObject(provider
);
3142 return kIOReturnSuccess
;
3146 IOUserServer::serviceClose(IOService
* provider
, IOService
* client
)
3148 OSObjectUserVars
* uvars
;
3151 uvars
= client
->reserved
->uvars
;
3152 if (!uvars
->openProviders
) {
3153 return kIOReturnNotOpen
;
3155 idx
= uvars
->openProviders
->getNextIndexOfObject(client
, 0);
3157 return kIOReturnNotOpen
;
3159 uvars
->openProviders
->removeObject(idx
);
3161 return kIOReturnSuccess
;
3166 IOUserServer::serviceStop(IOService
* service
, IOService
*)
3169 uint32_t idx
, queueAlloc
;
3170 OSObjectUserVars
* uvars
;
3173 idx
= fServices
->getNextIndexOfObject(service
, 0);
3175 fServices
->removeObject(idx
);
3176 uvars
= service
->reserved
->uvars
;
3177 uvars
->stopped
= true;
3179 IOLockUnlock(fLock
);
3182 return kIOReturnSuccess
;
3185 IOMachPortDestroyUserReferences(service
, IKOT_UEXT_OBJECT
);
3187 if (uvars
->queueArray
&& uvars
->userMeta
) {
3189 if (uvars
->userMeta
->queueNames
) {
3190 queueAlloc
+= uvars
->userMeta
->queueNames
->count
;
3192 for (idx
= 0; idx
< queueAlloc
; idx
++) {
3193 OSSafeReleaseNULL(uvars
->queueArray
[idx
]);
3195 IOSafeDeleteNULL(uvars
->queueArray
, IODispatchQueue
*, queueAlloc
);
3198 (void) service
->deRegisterInterestedDriver(this);
3199 if (uvars
->userServerPM
) {
3203 ret
= kIOReturnSuccess
;
3208 IOUserServer::serviceFree(IOService
* service
)
3210 OSObjectUserVars
* uvars
;
3212 uvars
= service
->reserved
->uvars
;
3216 OSSafeReleaseNULL(uvars
->userServer
);
3217 IOSafeDeleteNULL(service
->reserved
->uvars
, OSObjectUserVars
, 1);
3221 IOUserServer::serviceWillTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
)
3226 willTerminate
= false;
3227 if (client
->lockForArbitration(true)) {
3228 if (!client
->reserved
->uvars
->serverDied
3229 && !client
->reserved
->uvars
->willTerminate
) {
3230 client
->reserved
->uvars
->willTerminate
= true;
3231 willTerminate
= true;
3233 client
->unlockForArbitration();
3236 if (willTerminate
) {
3237 ret
= client
->Stop(provider
);
3238 if (kIOReturnSuccess
!= ret
) {
3239 ret
= client
->IOService::Stop(provider
);
3245 IOUserServer::serviceDidTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
, bool * defer
)
3247 if (client
->lockForArbitration(true)) {
3248 client
->reserved
->uvars
->didTerminate
= true;
3249 if (!client
->reserved
->uvars
->serverDied
3250 && !client
->reserved
->uvars
->stopped
) {
3253 client
->unlockForArbitration();
3258 IOUserServer::serviceDidStop(IOService
* client
, IOService
* provider
)
3261 OSArray
* closeArray
;
3266 if (client
->lockForArbitration(true)) {
3267 if (client
->reserved
->uvars
3268 && client
->reserved
->uvars
->willTerminate
3269 && !client
->reserved
->uvars
->stopped
) {
3270 client
->reserved
->uvars
->stopped
= true;
3271 complete
= client
->reserved
->uvars
->didTerminate
;
3274 if (client
->reserved
->uvars
) {
3275 closeArray
= client
->reserved
->uvars
->openProviders
;
3276 client
->reserved
->uvars
->openProviders
= NULL
;
3278 client
->unlockForArbitration();
3280 closeArray
->iterateObjects(^bool (OSObject
* obj
) {
3281 IOService
* toClose
;
3282 toClose
= OSDynamicCast(IOService
, obj
);
3284 DKLOG(DKS
":force close (" DKS
")\n", DKN(client
), DKN(toClose
));
3285 toClose
->close(client
);
3289 closeArray
->release();
3294 client
->didTerminate(provider
, 0, &defer
);
3299 IMPL(IOService
, Stop
)
3301 IOUserServer::serviceDidStop(this, provider
);
3303 return kIOReturnSuccess
;
3307 IMPL(IOInterruptDispatchSource
, Cancel
)
3309 return kIOReturnUnsupported
;
3312 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3315 #define super IOUserClient
3317 OSDefineMetaClassAndStructors(IOUserUserClient
, IOUserClient
)
3319 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3322 IOUserUserClient::setTask(task_t task
)
3324 task_reference(task
);
3327 return kIOReturnSuccess
;
3331 IOUserUserClient::stop(IOService
* provider
)
3334 task_deallocate(fTask
);
3337 super::stop(provider
);
3341 IOUserUserClient::clientClose(void)
3344 return kIOReturnSuccess
;
3348 IOUserUserClient::setProperties(OSObject
* properties
)
3350 IOReturn ret
= kIOReturnUnsupported
;
3354 struct IOUserUserClientActionRef
{
3355 OSAsyncReference64 asyncRef
;
3359 IMPL(IOUserClient
, KernelCompletion
)
3361 IOUserUserClientActionRef
* ref
;
3363 ref
= (typeof(ref
))action
->GetReference();
3365 IOUserClient::sendAsyncResult64(ref
->asyncRef
, status
, (io_user_reference_t
*) asyncData
, asyncDataCount
);
3369 IMPL(IOUserClient
, _ExternalMethod
)
3371 return kIOReturnUnsupported
;
3375 IOUserUserClient::clientMemoryForType(UInt32 type
,
3376 IOOptionBits
* koptions
,
3377 IOMemoryDescriptor
** kmemory
)
3381 IOMemoryDescriptor
* memory
;
3383 kr
= CopyClientMemoryForType(type
, &options
, &memory
);
3387 if (kIOReturnSuccess
!= kr
) {
3391 if (kIOUserClientMemoryReadOnly
& options
) {
3392 *koptions
|= kIOMapReadOnly
;
3400 IOUserUserClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
3401 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
3404 OSData
* structureInput
;
3405 OSData
* structureOutput
;
3407 uint64_t structureOutputSize
;
3409 IOUserUserClientActionRef
* ref
;
3411 kr
= kIOReturnUnsupported
;
3412 structureInput
= NULL
;
3415 if (args
->structureInputSize
) {
3416 structureInput
= OSData::withBytesNoCopy((void *) args
->structureInput
, args
->structureInputSize
);
3419 if (MACH_PORT_NULL
!= args
->asyncWakePort
) {
3420 kr
= CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef
), &action
);
3421 assert(KERN_SUCCESS
== kr
);
3422 ref
= (typeof(ref
))action
->GetReference();
3423 bcopy(args
->asyncReference
, &ref
->asyncRef
[0], args
->asyncReferenceCount
* sizeof(ref
->asyncRef
[0]));
3426 if (args
->structureVariableOutputData
) {
3427 structureOutputSize
= kIOUserClientVariableStructureSize
;
3428 } else if (args
->structureOutputDescriptor
) {
3429 structureOutputSize
= args
->structureOutputDescriptor
->getLength();
3431 structureOutputSize
= args
->structureOutputSize
;
3434 kr
= _ExternalMethod(selector
, &args
->scalarInput
[0], args
->scalarInputCount
,
3435 structureInput
, args
->structureInputDescriptor
,
3436 args
->scalarOutput
, &args
->scalarOutputCount
,
3437 structureOutputSize
, &structureOutput
, args
->structureOutputDescriptor
,
3440 OSSafeReleaseNULL(structureInput
);
3441 OSSafeReleaseNULL(action
);
3443 if (kIOReturnSuccess
!= kr
) {
3446 if (structureOutput
) {
3447 if (args
->structureVariableOutputData
) {
3448 *args
->structureVariableOutputData
= structureOutput
;
3450 copylen
= structureOutput
->getLength();
3451 if (copylen
> args
->structureOutputSize
) {
3452 kr
= kIOReturnBadArgument
;
3454 bcopy((const void *) structureOutput
->getBytesNoCopy(), args
->structureOutput
, copylen
);
3456 OSSafeReleaseNULL(structureOutput
);
3463 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */