2 * Copyright (c) 1998-2019 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@
30 #include <libkern/c++/OSKext.h>
31 #include <IOKit/IOKitServer.h>
32 #include <IOKit/IOKitKeysPrivate.h>
33 #include <IOKit/IOUserClient.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IORegistryEntry.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOMemoryDescriptor.h>
38 #include <IOKit/IOBufferMemoryDescriptor.h>
39 #include <IOKit/IOLib.h>
40 #include <IOKit/IOBSD.h>
41 #include <IOKit/IOStatisticsPrivate.h>
42 #include <IOKit/IOTimeStamp.h>
43 #include <IOKit/IODeviceTreeSupport.h>
44 #include <IOKit/IOUserServer.h>
45 #include <IOKit/system.h>
46 #include <libkern/OSDebug.h>
47 #include <DriverKit/OSAction.h>
49 #include <sys/kauth.h>
50 #include <sys/codesign.h>
58 #include <security/mac_framework.h>
60 #include <sys/kauth.h>
64 #endif /* CONFIG_MACF */
66 #include <IOKit/assert.h>
68 #include "IOServicePrivate.h"
69 #include "IOKitKernelInternal.h"
71 #define SCALAR64(x) ((io_user_scalar_t)((unsigned int)x))
72 #define SCALAR32(x) ((uint32_t )x)
73 #define ARG32(x) ((void *)(uintptr_t)SCALAR32(x))
74 #define REF64(x) ((io_user_reference_t)((UInt64)(x)))
75 #define REF32(x) ((int)(x))
78 kIOUCAsync0Flags
= 3ULL,
79 kIOUCAsync64Flag
= 1ULL,
80 kIOUCAsyncErrorLoggedFlag
= 2ULL
85 #define IOStatisticsRegisterCounter() \
87 reserved->counter = IOStatistics::registerUserClient(this); \
90 #define IOStatisticsUnregisterCounter() \
93 IOStatistics::unregisterUserClient(reserved->counter); \
96 #define IOStatisticsClientCall() \
98 IOStatistics::countUserClientCall(client); \
103 #define IOStatisticsRegisterCounter()
104 #define IOStatisticsUnregisterCounter()
105 #define IOStatisticsClientCall()
107 #endif /* IOKITSTATS */
109 #if DEVELOPMENT || DEBUG
111 #define FAKE_STACK_FRAME(a) \
112 const void ** __frameptr; \
113 const void * __retaddr; \
114 __frameptr = (typeof(__frameptr)) __builtin_frame_address(0); \
115 __retaddr = __frameptr[1]; \
118 #define FAKE_STACK_FRAME_END() \
119 __frameptr[1] = __retaddr;
121 #else /* DEVELOPMENT || DEBUG */
123 #define FAKE_STACK_FRAME(a)
124 #define FAKE_STACK_FRAME_END()
126 #endif /* DEVELOPMENT || DEBUG */
128 #define ASYNC_REF_COUNT (sizeof(io_async_ref_t) / sizeof(natural_t))
129 #define ASYNC_REF64_COUNT (sizeof(io_async_ref64_t) / sizeof(io_user_reference_t))
131 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
134 #include <mach/mach_traps.h>
135 #include <vm/vm_map.h>
138 struct IOMachPortHashList
;
140 static_assert(IKOT_MAX_TYPE
<= 255);
142 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
144 // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
145 class IOMachPort
: public OSObject
147 OSDeclareDefaultStructors(IOMachPort
);
149 SLIST_ENTRY(IOMachPort
) link
;
156 static IOMachPort
* withObjectAndType(OSObject
*obj
, ipc_kobject_type_t type
);
158 static IOMachPortHashList
* bucketForObject(OSObject
*obj
,
159 ipc_kobject_type_t type
);
161 static IOMachPort
* portForObjectInBucket(IOMachPortHashList
*bucket
, OSObject
*obj
, ipc_kobject_type_t type
);
163 static bool noMoreSendersForObject( OSObject
* obj
,
164 ipc_kobject_type_t type
, mach_port_mscount_t
* mscount
);
165 static void releasePortForObject( OSObject
* obj
,
166 ipc_kobject_type_t type
);
167 static void setHoldDestroy( OSObject
* obj
, ipc_kobject_type_t type
);
169 static mach_port_name_t
makeSendRightForTask( task_t task
,
170 io_object_t obj
, ipc_kobject_type_t type
);
172 virtual void free() APPLE_KEXT_OVERRIDE
;
175 #define super OSObject
176 OSDefineMetaClassAndStructors(IOMachPort
, OSObject
)
178 static IOLock
* gIOObjectPortLock
;
179 IOLock
* gIOUserServerLock
;
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
183 SLIST_HEAD(IOMachPortHashList
, IOMachPort
);
186 #define PORT_HASH_SIZE 256
188 #define PORT_HASH_SIZE 4096
189 #endif /* CONFIG_EMBEDDED */
191 IOMachPortHashList ports
[PORT_HASH_SIZE
];
194 IOMachPortInitialize(void)
196 for (size_t i
= 0; i
< PORT_HASH_SIZE
; i
++) {
197 SLIST_INIT(&ports
[i
]);
202 IOMachPort::bucketForObject(OSObject
*obj
, ipc_kobject_type_t type
)
204 return &ports
[os_hash_kernel_pointer(obj
) % PORT_HASH_SIZE
];
208 IOMachPort::portForObjectInBucket(IOMachPortHashList
*bucket
, OSObject
*obj
, ipc_kobject_type_t type
)
210 IOMachPort
*machPort
;
212 SLIST_FOREACH(machPort
, bucket
, link
) {
213 if (machPort
->object
== obj
&& machPort
->type
== type
) {
221 IOMachPort::withObjectAndType(OSObject
*obj
, ipc_kobject_type_t type
)
223 IOMachPort
*machPort
= NULL
;
225 machPort
= new IOMachPort
;
226 if (__improbable(machPort
&& !machPort
->init())) {
230 machPort
->object
= obj
;
231 machPort
->type
= (typeof(machPort
->type
))type
;
232 machPort
->port
= iokit_alloc_object_port(obj
, type
);
234 obj
->taggedRetain(OSTypeID(OSCollection
));
241 IOMachPort::noMoreSendersForObject( OSObject
* obj
,
242 ipc_kobject_type_t type
, mach_port_mscount_t
* mscount
)
244 IOMachPort
*machPort
= NULL
;
247 bool destroyed
= true;
249 IOMachPortHashList
*bucket
= IOMachPort::bucketForObject(obj
, type
);
253 lck_mtx_lock(gIOObjectPortLock
);
255 machPort
= IOMachPort::portForObjectInBucket(bucket
, obj
, type
);
258 destroyed
= (machPort
->mscount
<= *mscount
);
260 *mscount
= machPort
->mscount
;
261 lck_mtx_unlock(gIOObjectPortLock
);
263 if ((IKOT_IOKIT_CONNECT
== type
) && (uc
= OSDynamicCast(IOUserClient
, obj
))) {
266 SLIST_REMOVE(bucket
, machPort
, IOMachPort
, link
);
268 lck_mtx_unlock(gIOObjectPortLock
);
271 obj
->taggedRelease(OSTypeID(OSCollection
));
274 lck_mtx_unlock(gIOObjectPortLock
);
277 if ((IKOT_UEXT_OBJECT
== type
) && (action
= OSDynamicCast(OSAction
, obj
))) {
287 IOMachPort::releasePortForObject( OSObject
* obj
,
288 ipc_kobject_type_t type
)
290 IOMachPort
*machPort
;
291 IOMachPortHashList
*bucket
= IOMachPort::bucketForObject(obj
, type
);
293 assert(IKOT_IOKIT_CONNECT
!= type
);
295 lck_mtx_lock(gIOObjectPortLock
);
297 machPort
= IOMachPort::portForObjectInBucket(bucket
, obj
, type
);
299 if (machPort
&& !machPort
->holdDestroy
) {
301 SLIST_REMOVE(bucket
, machPort
, IOMachPort
, link
);
303 lck_mtx_unlock(gIOObjectPortLock
);
306 obj
->taggedRelease(OSTypeID(OSCollection
));
309 lck_mtx_unlock(gIOObjectPortLock
);
314 IOMachPort::setHoldDestroy( OSObject
* obj
, ipc_kobject_type_t type
)
316 IOMachPort
* machPort
;
318 IOMachPortHashList
*bucket
= IOMachPort::bucketForObject(obj
, type
);
319 lck_mtx_lock(gIOObjectPortLock
);
321 machPort
= IOMachPort::portForObjectInBucket(bucket
, obj
, type
);
324 machPort
->holdDestroy
= true;
327 lck_mtx_unlock(gIOObjectPortLock
);
331 IOMachPortDestroyUserReferences(OSObject
* obj
, natural_t type
)
333 IOMachPort::releasePortForObject(obj
, type
);
337 IOUserClient::destroyUserReferences( OSObject
* obj
)
339 IOMachPort
*machPort
;
341 IOMachPort::releasePortForObject( obj
, IKOT_IOKIT_OBJECT
);
344 // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT );
347 IOMachPortHashList
*bucket
= IOMachPort::bucketForObject(obj
, IKOT_IOKIT_CONNECT
);
348 IOMachPortHashList
*mappingBucket
= NULL
;
350 lck_mtx_lock(gIOObjectPortLock
);
352 IOUserClient
* uc
= OSDynamicCast(IOUserClient
, obj
);
353 if (uc
&& uc
->mappings
) {
354 mappingBucket
= IOMachPort::bucketForObject(uc
->mappings
, IKOT_IOKIT_CONNECT
);
357 machPort
= IOMachPort::portForObjectInBucket(bucket
, obj
, IKOT_IOKIT_CONNECT
);
359 if (machPort
== NULL
) {
360 lck_mtx_unlock(gIOObjectPortLock
);
364 SLIST_REMOVE(bucket
, machPort
, IOMachPort
, link
);
365 obj
->taggedRelease(OSTypeID(OSCollection
));
370 uc
->mappings
->taggedRetain(OSTypeID(OSCollection
));
371 machPort
->object
= uc
->mappings
;
372 SLIST_INSERT_HEAD(mappingBucket
, machPort
, link
);
373 iokit_switch_object_port(machPort
->port
, uc
->mappings
, IKOT_IOKIT_CONNECT
);
375 lck_mtx_unlock(gIOObjectPortLock
);
377 uc
->mappings
->release();
380 lck_mtx_unlock(gIOObjectPortLock
);
384 lck_mtx_unlock(gIOObjectPortLock
);
395 IOMachPort::makeSendRightForTask( task_t task
,
396 io_object_t obj
, ipc_kobject_type_t type
)
398 return iokit_make_send_right( task
, obj
, type
);
402 IOMachPort::free( void )
405 iokit_destroy_object_port( port
);
410 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
412 class IOUserIterator
: public OSIterator
414 OSDeclareDefaultStructors(IOUserIterator
);
416 OSObject
* userIteratorObject
;
419 static IOUserIterator
* withIterator(LIBKERN_CONSUMED OSIterator
* iter
);
420 virtual bool init( void ) APPLE_KEXT_OVERRIDE
;
421 virtual void free() APPLE_KEXT_OVERRIDE
;
423 virtual void reset() APPLE_KEXT_OVERRIDE
;
424 virtual bool isValid() APPLE_KEXT_OVERRIDE
;
425 virtual OSObject
* getNextObject() APPLE_KEXT_OVERRIDE
;
426 virtual OSObject
* copyNextObject();
429 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
431 class IOUserNotification
: public IOUserIterator
433 OSDeclareDefaultStructors(IOUserNotification
);
435 #define holdNotify userIteratorObject
439 virtual void free() APPLE_KEXT_OVERRIDE
;
441 virtual void setNotification( IONotifier
* obj
);
443 virtual void reset() APPLE_KEXT_OVERRIDE
;
444 virtual bool isValid() APPLE_KEXT_OVERRIDE
;
447 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
449 OSDefineMetaClassAndStructors( IOUserIterator
, OSIterator
)
452 IOUserIterator::withIterator(OSIterator
* iter
)
460 me
= new IOUserIterator
;
461 if (me
&& !me
->init()) {
468 me
->userIteratorObject
= iter
;
474 IOUserIterator::init( void )
476 if (!OSObject::init()) {
480 lock
= IOLockAlloc();
489 IOUserIterator::free()
491 if (userIteratorObject
) {
492 userIteratorObject
->release();
501 IOUserIterator::reset()
504 assert(OSDynamicCast(OSIterator
, userIteratorObject
));
505 ((OSIterator
*)userIteratorObject
)->reset();
510 IOUserIterator::isValid()
515 assert(OSDynamicCast(OSIterator
, userIteratorObject
));
516 ret
= ((OSIterator
*)userIteratorObject
)->isValid();
523 IOUserIterator::getNextObject()
530 IOUserIterator::copyNextObject()
532 OSObject
* ret
= NULL
;
535 if (userIteratorObject
) {
536 ret
= ((OSIterator
*)userIteratorObject
)->getNextObject();
546 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
548 // functions called from osfmk/device/iokit_rpc.c
551 iokit_add_reference( io_object_t obj
, ipc_kobject_type_t type
)
559 if ((IKOT_IOKIT_CONNECT
== type
)
560 && (uc
= OSDynamicCast(IOUserClient
, obj
))) {
561 OSIncrementAtomic(&uc
->__ipc
);
568 iokit_remove_reference( io_object_t obj
)
576 iokit_remove_connect_reference( io_object_t obj
)
579 bool finalize
= false;
585 if ((uc
= OSDynamicCast(IOUserClient
, obj
))) {
586 if (1 == OSDecrementAtomic(&uc
->__ipc
) && uc
->isInactive()) {
587 IOLockLock(gIOObjectPortLock
);
588 if ((finalize
= uc
->__ipcFinal
)) {
589 uc
->__ipcFinal
= false;
591 IOLockUnlock(gIOObjectPortLock
);
594 uc
->scheduleFinalize(true);
602 IOUserClient::finalizeUserReferences(OSObject
* obj
)
607 if ((uc
= OSDynamicCast(IOUserClient
, obj
))) {
608 IOLockLock(gIOObjectPortLock
);
609 if ((uc
->__ipcFinal
= (0 != uc
->__ipc
))) {
612 IOLockUnlock(gIOObjectPortLock
);
618 iokit_port_for_object( io_object_t obj
, ipc_kobject_type_t type
)
620 IOMachPort
*machPort
= NULL
;
621 ipc_port_t port
= NULL
;
623 IOMachPortHashList
*bucket
= IOMachPort::bucketForObject(obj
, type
);
625 lck_mtx_lock(gIOObjectPortLock
);
627 machPort
= IOMachPort::portForObjectInBucket(bucket
, obj
, type
);
629 if (__improbable(machPort
== NULL
)) {
630 machPort
= IOMachPort::withObjectAndType(obj
, type
);
631 if (__improbable(machPort
== NULL
)) {
634 SLIST_INSERT_HEAD(bucket
, machPort
, link
);
639 iokit_retain_port(machPort
->port
);
640 port
= machPort
->port
;
643 lck_mtx_unlock(gIOObjectPortLock
);
649 iokit_client_died( io_object_t obj
, ipc_port_t
/* port */,
650 ipc_kobject_type_t type
, mach_port_mscount_t
* mscount
)
652 IOUserClient
* client
;
654 IOUserNotification
* notify
;
656 if (!IOMachPort::noMoreSendersForObject( obj
, type
, mscount
)) {
657 return kIOReturnNotReady
;
660 if (IKOT_IOKIT_CONNECT
== type
) {
661 if ((client
= OSDynamicCast( IOUserClient
, obj
))) {
662 IOStatisticsClientCall();
663 IOLockLock(client
->lock
);
664 client
->clientDied();
665 IOLockUnlock(client
->lock
);
667 } else if (IKOT_IOKIT_OBJECT
== type
) {
668 if ((map
= OSDynamicCast( IOMemoryMap
, obj
))) {
670 } else if ((notify
= OSDynamicCast( IOUserNotification
, obj
))) {
671 notify
->setNotification( NULL
);
675 return kIOReturnSuccess
;
679 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
681 class IOServiceUserNotification
: public IOUserNotification
683 OSDeclareDefaultStructors(IOServiceUserNotification
);
686 mach_msg_header_t msgHdr
;
687 OSNotificationHeader64 notifyHeader
;
690 enum { kMaxOutstanding
= 1024 };
700 virtual bool init( mach_port_t port
, natural_t type
,
701 void * reference
, vm_size_t referenceSize
,
703 virtual void free() APPLE_KEXT_OVERRIDE
;
704 void invalidatePort(void);
706 static bool _handler( void * target
,
707 void * ref
, IOService
* newService
, IONotifier
* notifier
);
708 virtual bool handler( void * ref
, IOService
* newService
);
710 virtual OSObject
* getNextObject() APPLE_KEXT_OVERRIDE
;
711 virtual OSObject
* copyNextObject() APPLE_KEXT_OVERRIDE
;
714 class IOServiceMessageUserNotification
: public IOUserNotification
716 OSDeclareDefaultStructors(IOServiceMessageUserNotification
);
719 mach_msg_header_t msgHdr
;
720 mach_msg_body_t msgBody
;
721 mach_msg_port_descriptor_t ports
[1];
722 OSNotificationHeader64 notifyHeader
__attribute__ ((packed
));
733 virtual bool init( mach_port_t port
, natural_t type
,
734 void * reference
, vm_size_t referenceSize
,
738 virtual void free() APPLE_KEXT_OVERRIDE
;
739 void invalidatePort(void);
741 static IOReturn
_handler( void * target
, void * ref
,
742 UInt32 messageType
, IOService
* provider
,
743 void * messageArgument
, vm_size_t argSize
);
744 virtual IOReturn
handler( void * ref
,
745 UInt32 messageType
, IOService
* provider
,
746 void * messageArgument
, vm_size_t argSize
);
748 virtual OSObject
* getNextObject() APPLE_KEXT_OVERRIDE
;
749 virtual OSObject
* copyNextObject() APPLE_KEXT_OVERRIDE
;
752 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
755 #define super IOUserIterator
756 OSDefineMetaClass( IOUserNotification
, IOUserIterator
);
757 OSDefineAbstractStructors( IOUserNotification
, IOUserIterator
);
759 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
762 IOUserNotification::free( void )
765 assert(OSDynamicCast(IONotifier
, holdNotify
));
766 ((IONotifier
*)holdNotify
)->remove();
769 // can't be in handler now
776 IOUserNotification::setNotification( IONotifier
* notify
)
778 OSObject
* previousNotify
;
780 IOLockLock( gIOObjectPortLock
);
782 previousNotify
= holdNotify
;
785 IOLockUnlock( gIOObjectPortLock
);
787 if (previousNotify
) {
788 assert(OSDynamicCast(IONotifier
, previousNotify
));
789 ((IONotifier
*)previousNotify
)->remove();
794 IOUserNotification::reset()
800 IOUserNotification::isValid()
805 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
808 #define super IOUserNotification
809 OSDefineMetaClassAndStructors(IOServiceUserNotification
, IOUserNotification
)
811 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
814 IOServiceUserNotification::init( mach_port_t port
, natural_t type
,
815 void * reference
, vm_size_t referenceSize
,
818 if (!super::init()) {
822 newSet
= OSArray::withCapacity( 1 );
827 if (referenceSize
> sizeof(OSAsyncReference64
)) {
831 msgSize
= sizeof(PingMsg
) - sizeof(OSAsyncReference64
) + referenceSize
;
832 pingMsg
= (PingMsg
*) IOMalloc( msgSize
);
837 bzero( pingMsg
, msgSize
);
839 pingMsg
->msgHdr
.msgh_remote_port
= port
;
840 pingMsg
->msgHdr
.msgh_bits
= MACH_MSGH_BITS(
841 MACH_MSG_TYPE_COPY_SEND
/*remote*/,
842 MACH_MSG_TYPE_MAKE_SEND
/*local*/);
843 pingMsg
->msgHdr
.msgh_size
= msgSize
;
844 pingMsg
->msgHdr
.msgh_id
= kOSNotificationMessageID
;
846 pingMsg
->notifyHeader
.size
= 0;
847 pingMsg
->notifyHeader
.type
= type
;
848 bcopy( reference
, pingMsg
->notifyHeader
.reference
, referenceSize
);
854 IOServiceUserNotification::invalidatePort(void)
857 pingMsg
->msgHdr
.msgh_remote_port
= MACH_PORT_NULL
;
862 IOServiceUserNotification::free( void )
874 if (_pingMsg
&& _msgSize
) {
875 if (_pingMsg
->msgHdr
.msgh_remote_port
) {
876 iokit_release_port_send(_pingMsg
->msgHdr
.msgh_remote_port
);
878 IOFree(_pingMsg
, _msgSize
);
887 IOServiceUserNotification::_handler( void * target
,
888 void * ref
, IOService
* newService
, IONotifier
* notifier
)
890 return ((IOServiceUserNotification
*) target
)->handler( ref
, newService
);
894 IOServiceUserNotification::handler( void * ref
,
895 IOService
* newService
)
899 ipc_port_t port
= NULL
;
900 bool sendPing
= false;
904 count
= newSet
->getCount();
905 if (count
< kMaxOutstanding
) {
906 newSet
->setObject( newService
);
907 if ((sendPing
= (armed
&& (0 == count
)))) {
914 if (kIOServiceTerminatedNotificationType
== pingMsg
->notifyHeader
.type
) {
915 IOMachPort::setHoldDestroy( newService
, IKOT_IOKIT_OBJECT
);
919 if ((port
= iokit_port_for_object( this, IKOT_IOKIT_OBJECT
))) {
920 pingMsg
->msgHdr
.msgh_local_port
= port
;
922 pingMsg
->msgHdr
.msgh_local_port
= NULL
;
925 kr
= mach_msg_send_from_kernel_with_options( &pingMsg
->msgHdr
,
926 pingMsg
->msgHdr
.msgh_size
,
927 (MACH_SEND_MSG
| MACH_SEND_ALWAYS
| MACH_SEND_IMPORTANCE
),
930 iokit_release_port( port
);
933 if ((KERN_SUCCESS
!= kr
) && !ipcLogged
) {
935 IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__
, kr
);
942 IOServiceUserNotification::getNextObject()
949 IOServiceUserNotification::copyNextObject()
956 count
= newSet
->getCount();
958 result
= newSet
->getObject( count
- 1 );
960 newSet
->removeObject( count
- 1);
971 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
973 OSDefineMetaClassAndStructors(IOServiceMessageUserNotification
, IOUserNotification
)
975 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
978 IOServiceMessageUserNotification::init( mach_port_t port
, natural_t type
,
979 void * reference
, vm_size_t referenceSize
, vm_size_t extraSize
,
982 if (!super::init()) {
986 if (referenceSize
> sizeof(OSAsyncReference64
)) {
990 clientIs64
= client64
;
992 owningPID
= proc_selfpid();
994 extraSize
+= sizeof(IOServiceInterestContent64
);
995 msgSize
= sizeof(PingMsg
) - sizeof(OSAsyncReference64
) + referenceSize
;
996 pingMsg
= (PingMsg
*) IOMalloc( msgSize
);
1001 bzero( pingMsg
, msgSize
);
1003 pingMsg
->msgHdr
.msgh_remote_port
= port
;
1004 pingMsg
->msgHdr
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
1006 MACH_MSG_TYPE_COPY_SEND
/*remote*/,
1007 MACH_MSG_TYPE_MAKE_SEND
/*local*/);
1008 pingMsg
->msgHdr
.msgh_size
= msgSize
;
1009 pingMsg
->msgHdr
.msgh_id
= kOSNotificationMessageID
;
1011 pingMsg
->msgBody
.msgh_descriptor_count
= 1;
1013 pingMsg
->ports
[0].name
= NULL
;
1014 pingMsg
->ports
[0].disposition
= MACH_MSG_TYPE_MAKE_SEND
;
1015 pingMsg
->ports
[0].type
= MACH_MSG_PORT_DESCRIPTOR
;
1017 pingMsg
->notifyHeader
.size
= extraSize
;
1018 pingMsg
->notifyHeader
.type
= type
;
1019 bcopy( reference
, pingMsg
->notifyHeader
.reference
, referenceSize
);
1025 IOServiceMessageUserNotification::invalidatePort(void)
1028 pingMsg
->msgHdr
.msgh_remote_port
= MACH_PORT_NULL
;
1033 IOServiceMessageUserNotification::free( void )
1043 if (_pingMsg
&& _msgSize
) {
1044 if (_pingMsg
->msgHdr
.msgh_remote_port
) {
1045 iokit_release_port_send(_pingMsg
->msgHdr
.msgh_remote_port
);
1047 IOFree( _pingMsg
, _msgSize
);
1052 IOServiceMessageUserNotification::_handler( void * target
, void * ref
,
1053 UInt32 messageType
, IOService
* provider
,
1054 void * argument
, vm_size_t argSize
)
1056 return ((IOServiceMessageUserNotification
*) target
)->handler(
1057 ref
, messageType
, provider
, argument
, argSize
);
1061 IOServiceMessageUserNotification::handler( void * ref
,
1062 UInt32 messageType
, IOService
* provider
,
1063 void * messageArgument
, vm_size_t callerArgSize
)
1065 enum { kLocalMsgSize
= 0x100 };
1066 uint64_t stackMsg
[kLocalMsgSize
/ sizeof(uint64_t)];
1070 vm_size_t thisMsgSize
;
1071 ipc_port_t thisPort
, providerPort
;
1072 struct PingMsg
* thisMsg
;
1073 IOServiceInterestContent64
* data
;
1075 if (kIOMessageCopyClientID
== messageType
) {
1076 *((void **) messageArgument
) = OSNumber::withNumber(owningPID
, 32);
1077 return kIOReturnSuccess
;
1080 if (callerArgSize
== 0) {
1082 argSize
= sizeof(data
->messageArgument
[0]);
1084 argSize
= sizeof(uint32_t);
1087 if (callerArgSize
> kIOUserNotifyMaxMessageSize
) {
1088 callerArgSize
= kIOUserNotifyMaxMessageSize
;
1090 argSize
= callerArgSize
;
1093 // adjust message size for ipc restrictions
1095 type
= pingMsg
->notifyHeader
.type
;
1096 type
&= ~(kIOKitNoticationMsgSizeMask
<< kIOKitNoticationTypeSizeAdjShift
);
1097 type
|= ((argSize
& kIOKitNoticationMsgSizeMask
) << kIOKitNoticationTypeSizeAdjShift
);
1098 argSize
= (argSize
+ kIOKitNoticationMsgSizeMask
) & ~kIOKitNoticationMsgSizeMask
;
1100 thisMsgSize
= msgSize
1101 + sizeof(IOServiceInterestContent64
)
1102 - sizeof(data
->messageArgument
)
1105 if (thisMsgSize
> sizeof(stackMsg
)) {
1106 allocMsg
= IOMalloc(thisMsgSize
);
1108 return kIOReturnNoMemory
;
1110 thisMsg
= (typeof(thisMsg
))allocMsg
;
1113 thisMsg
= (typeof(thisMsg
))stackMsg
;
1116 bcopy(pingMsg
, thisMsg
, msgSize
);
1117 thisMsg
->notifyHeader
.type
= type
;
1118 data
= (IOServiceInterestContent64
*) (((uint8_t *) thisMsg
) + msgSize
);
1119 // == pingMsg->notifyHeader.content;
1120 data
->messageType
= messageType
;
1122 if (callerArgSize
== 0) {
1123 data
->messageArgument
[0] = (io_user_reference_t
) messageArgument
;
1125 data
->messageArgument
[0] |= (data
->messageArgument
[0] << 32);
1128 bcopy( messageArgument
, data
->messageArgument
, callerArgSize
);
1129 bzero((void *)(((uintptr_t) &data
->messageArgument
[0]) + callerArgSize
), argSize
- callerArgSize
);
1132 thisMsg
->notifyHeader
.type
= type
;
1133 thisMsg
->msgHdr
.msgh_size
= thisMsgSize
;
1135 providerPort
= iokit_port_for_object( provider
, IKOT_IOKIT_OBJECT
);
1136 thisMsg
->ports
[0].name
= providerPort
;
1137 thisPort
= iokit_port_for_object( this, IKOT_IOKIT_OBJECT
);
1138 thisMsg
->msgHdr
.msgh_local_port
= thisPort
;
1140 kr
= mach_msg_send_from_kernel_with_options( &thisMsg
->msgHdr
,
1141 thisMsg
->msgHdr
.msgh_size
,
1142 (MACH_SEND_MSG
| MACH_SEND_ALWAYS
| MACH_SEND_IMPORTANCE
),
1145 iokit_release_port( thisPort
);
1148 iokit_release_port( providerPort
);
1152 IOFree(allocMsg
, thisMsgSize
);
1155 if ((KERN_SUCCESS
!= kr
) && !ipcLogged
) {
1157 IOLog("%s: mach_msg_send_from_kernel_proper (0x%x)\n", __PRETTY_FUNCTION__
, kr
);
1160 return kIOReturnSuccess
;
1164 IOServiceMessageUserNotification::getNextObject()
1170 IOServiceMessageUserNotification::copyNextObject()
1175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1178 #define super IOService
1179 OSDefineMetaClassAndAbstractStructors( IOUserClient
, IOService
)
1181 IOLock
* gIOUserClientOwnersLock
;
1184 IOUserClient::initialize( void )
1186 gIOObjectPortLock
= IOLockAlloc();
1187 gIOUserClientOwnersLock
= IOLockAlloc();
1188 gIOUserServerLock
= IOLockAlloc();
1189 assert(gIOObjectPortLock
&& gIOUserClientOwnersLock
);
1193 IOUserClient::setAsyncReference(OSAsyncReference asyncRef
,
1194 mach_port_t wakePort
,
1195 void *callback
, void *refcon
)
1197 asyncRef
[kIOAsyncReservedIndex
] = ((uintptr_t) wakePort
)
1198 | (kIOUCAsync0Flags
& asyncRef
[kIOAsyncReservedIndex
]);
1199 asyncRef
[kIOAsyncCalloutFuncIndex
] = (uintptr_t) callback
;
1200 asyncRef
[kIOAsyncCalloutRefconIndex
] = (uintptr_t) refcon
;
1204 IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef
,
1205 mach_port_t wakePort
,
1206 mach_vm_address_t callback
, io_user_reference_t refcon
)
1208 asyncRef
[kIOAsyncReservedIndex
] = ((io_user_reference_t
) wakePort
)
1209 | (kIOUCAsync0Flags
& asyncRef
[kIOAsyncReservedIndex
]);
1210 asyncRef
[kIOAsyncCalloutFuncIndex
] = (io_user_reference_t
) callback
;
1211 asyncRef
[kIOAsyncCalloutRefconIndex
] = refcon
;
1215 IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef
,
1216 mach_port_t wakePort
,
1217 mach_vm_address_t callback
, io_user_reference_t refcon
, task_t task
)
1219 setAsyncReference64(asyncRef
, wakePort
, callback
, refcon
);
1220 if (vm_map_is_64bit(get_task_map(task
))) {
1221 asyncRef
[kIOAsyncReservedIndex
] |= kIOUCAsync64Flag
;
1225 static OSDictionary
*
1226 CopyConsoleUser(UInt32 uid
)
1229 OSDictionary
* user
= NULL
;
1231 if ((array
= OSDynamicCast(OSArray
,
1232 IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey
)))) {
1233 for (unsigned int idx
= 0;
1234 (user
= OSDynamicCast(OSDictionary
, array
->getObject(idx
)));
1238 if ((num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionUIDKey
)))
1239 && (uid
== num
->unsigned32BitValue())) {
1249 static OSDictionary
*
1250 CopyUserOnConsole(void)
1253 OSDictionary
* user
= NULL
;
1255 if ((array
= OSDynamicCast(OSArray
,
1256 IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey
)))) {
1257 for (unsigned int idx
= 0;
1258 (user
= OSDynamicCast(OSDictionary
, array
->getObject(idx
)));
1260 if (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
)) {
1271 IOUserClient::clientHasAuthorization( task_t task
,
1272 IOService
* service
)
1276 p
= (proc_t
) get_bsdtask_info(task
);
1278 uint64_t authorizationID
;
1280 authorizationID
= proc_uniqueid(p
);
1281 if (authorizationID
) {
1282 if (service
->getAuthorizationID() == authorizationID
) {
1283 return kIOReturnSuccess
;
1288 return kIOReturnNotPermitted
;
1292 IOUserClient::clientHasPrivilege( void * securityToken
,
1293 const char * privilegeName
)
1296 security_token_t token
;
1297 mach_msg_type_number_t count
;
1299 OSDictionary
* user
;
1303 if (!strncmp(privilegeName
, kIOClientPrivilegeForeground
,
1304 sizeof(kIOClientPrivilegeForeground
))) {
1305 if (task_is_gpu_denied(current_task())) {
1306 return kIOReturnNotPrivileged
;
1308 return kIOReturnSuccess
;
1312 if (!strncmp(privilegeName
, kIOClientPrivilegeConsoleSession
,
1313 sizeof(kIOClientPrivilegeConsoleSession
))) {
1317 task
= (task_t
) securityToken
;
1319 task
= current_task();
1321 p
= (proc_t
) get_bsdtask_info(task
);
1322 kr
= kIOReturnNotPrivileged
;
1324 if (p
&& (cred
= kauth_cred_proc_ref(p
))) {
1325 user
= CopyUserOnConsole();
1328 if ((num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionAuditIDKey
)))
1329 && (cred
->cr_audit
.as_aia_p
->ai_asid
== (au_asid_t
) num
->unsigned32BitValue())) {
1330 kr
= kIOReturnSuccess
;
1334 kauth_cred_unref(&cred
);
1339 if ((secureConsole
= !strncmp(privilegeName
, kIOClientPrivilegeSecureConsoleProcess
,
1340 sizeof(kIOClientPrivilegeSecureConsoleProcess
)))) {
1341 task
= (task_t
)((IOUCProcessToken
*)securityToken
)->token
;
1343 task
= (task_t
)securityToken
;
1346 count
= TASK_SECURITY_TOKEN_COUNT
;
1347 kr
= task_info( task
, TASK_SECURITY_TOKEN
, (task_info_t
) &token
, &count
);
1349 if (KERN_SUCCESS
!= kr
) {
1350 } else if (!strncmp(privilegeName
, kIOClientPrivilegeAdministrator
,
1351 sizeof(kIOClientPrivilegeAdministrator
))) {
1352 if (0 != token
.val
[0]) {
1353 kr
= kIOReturnNotPrivileged
;
1355 } else if (!strncmp(privilegeName
, kIOClientPrivilegeLocalUser
,
1356 sizeof(kIOClientPrivilegeLocalUser
))) {
1357 user
= CopyConsoleUser(token
.val
[0]);
1361 kr
= kIOReturnNotPrivileged
;
1363 } else if (secureConsole
|| !strncmp(privilegeName
, kIOClientPrivilegeConsoleUser
,
1364 sizeof(kIOClientPrivilegeConsoleUser
))) {
1365 user
= CopyConsoleUser(token
.val
[0]);
1367 if (user
->getObject(gIOConsoleSessionOnConsoleKey
) != kOSBooleanTrue
) {
1368 kr
= kIOReturnNotPrivileged
;
1369 } else if (secureConsole
) {
1370 OSNumber
* pid
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionSecureInputPIDKey
));
1371 if (pid
&& pid
->unsigned32BitValue() != ((IOUCProcessToken
*)securityToken
)->pid
) {
1372 kr
= kIOReturnNotPrivileged
;
1377 kr
= kIOReturnNotPrivileged
;
1380 kr
= kIOReturnUnsupported
;
1387 IOUserClient::copyClientEntitlements(task_t task
)
1389 #define MAX_ENTITLEMENTS_LEN (128 * 1024)
1394 void *entitlements_blob
= NULL
;
1395 char *entitlements_data
= NULL
;
1396 OSObject
*entitlements_obj
= NULL
;
1397 OSDictionary
*entitlements
= NULL
;
1398 OSString
*errorString
= NULL
;
1400 p
= (proc_t
)get_bsdtask_info(task
);
1406 if (cs_entitlements_dictionary_copy(p
, (void **)&entitlements
) == 0) {
1408 return entitlements
;
1412 if (cs_entitlements_blob_get(p
, &entitlements_blob
, &len
) != 0) {
1416 if (len
<= offsetof(CS_GenericBlob
, data
)) {
1421 * Per <rdar://problem/11593877>, enforce a limit on the amount of XML
1422 * we'll try to parse in the kernel.
1424 len
-= offsetof(CS_GenericBlob
, data
);
1425 if (len
> MAX_ENTITLEMENTS_LEN
) {
1426 IOLog("failed to parse entitlements for %s[%u]: %lu bytes of entitlements exceeds maximum of %u\n",
1427 proc_best_name(p
), pid
, len
, MAX_ENTITLEMENTS_LEN
);
1432 * OSUnserializeXML() expects a nul-terminated string, but that isn't
1433 * what is stored in the entitlements blob. Copy the string and
1436 entitlements_data
= (char *)IOMalloc(len
+ 1);
1437 if (entitlements_data
== NULL
) {
1440 memcpy(entitlements_data
, ((CS_GenericBlob
*)entitlements_blob
)->data
, len
);
1441 entitlements_data
[len
] = '\0';
1443 entitlements_obj
= OSUnserializeXML(entitlements_data
, len
+ 1, &errorString
);
1444 if (errorString
!= NULL
) {
1445 IOLog("failed to parse entitlements for %s[%u]: %s\n",
1446 proc_best_name(p
), pid
, errorString
->getCStringNoCopy());
1449 if (entitlements_obj
== NULL
) {
1453 entitlements
= OSDynamicCast(OSDictionary
, entitlements_obj
);
1454 if (entitlements
== NULL
) {
1457 entitlements_obj
= NULL
;
1460 if (entitlements_data
!= NULL
) {
1461 IOFree(entitlements_data
, len
+ 1);
1463 if (entitlements_obj
!= NULL
) {
1464 entitlements_obj
->release();
1466 if (errorString
!= NULL
) {
1467 errorString
->release();
1469 return entitlements
;
1473 IOUserClient::copyClientEntitlement( task_t task
,
1474 const char * entitlement
)
1476 OSDictionary
*entitlements
;
1479 entitlements
= copyClientEntitlements(task
);
1480 if (entitlements
== NULL
) {
1484 /* Fetch the entitlement value from the dictionary. */
1485 value
= entitlements
->getObject(entitlement
);
1486 if (value
!= NULL
) {
1490 entitlements
->release();
1495 IOUserClient::init()
1497 if (getPropertyTable() || super::init()) {
1505 IOUserClient::init(OSDictionary
* dictionary
)
1507 if (getPropertyTable() || super::init(dictionary
)) {
1515 IOUserClient::initWithTask(task_t owningTask
,
1519 if (getPropertyTable() || super::init()) {
1527 IOUserClient::initWithTask(task_t owningTask
,
1530 OSDictionary
* properties
)
1534 ok
= super::init( properties
);
1535 ok
&= initWithTask( owningTask
, securityID
, type
);
1541 IOUserClient::reserve()
1544 reserved
= IONew(ExpansionData
, 1);
1549 setTerminateDefer(NULL
, true);
1550 IOStatisticsRegisterCounter();
1555 struct IOUserClientOwner
{
1557 queue_chain_t taskLink
;
1559 queue_chain_t ucLink
;
1563 IOUserClient::registerOwner(task_t task
)
1565 IOUserClientOwner
* owner
;
1569 IOLockLock(gIOUserClientOwnersLock
);
1572 ret
= kIOReturnSuccess
;
1575 queue_init(&owners
);
1577 queue_iterate(&owners
, owner
, IOUserClientOwner
*, ucLink
)
1579 if (task
!= owner
->task
) {
1587 owner
= IONew(IOUserClientOwner
, 1);
1589 ret
= kIOReturnNoMemory
;
1593 queue_enter_first(&owners
, owner
, IOUserClientOwner
*, ucLink
);
1594 queue_enter_first(task_io_user_clients(task
), owner
, IOUserClientOwner
*, taskLink
);
1595 if (messageAppSuspended
) {
1596 task_set_message_app_suspended(task
, true);
1601 IOLockUnlock(gIOUserClientOwnersLock
);
1607 IOUserClient::noMoreSenders(void)
1609 IOUserClientOwner
* owner
;
1610 IOUserClientOwner
* iter
;
1611 queue_head_t
* taskque
;
1612 bool hasMessageAppSuspended
;
1614 IOLockLock(gIOUserClientOwnersLock
);
1617 while (!queue_empty(&owners
)) {
1618 owner
= (IOUserClientOwner
*)(void *) queue_first(&owners
);
1619 taskque
= task_io_user_clients(owner
->task
);
1620 queue_remove(taskque
, owner
, IOUserClientOwner
*, taskLink
);
1621 hasMessageAppSuspended
= false;
1622 queue_iterate(taskque
, iter
, IOUserClientOwner
*, taskLink
) {
1623 hasMessageAppSuspended
= iter
->uc
->messageAppSuspended
;
1624 if (hasMessageAppSuspended
) {
1628 task_set_message_app_suspended(owner
->task
, hasMessageAppSuspended
);
1629 queue_remove(&owners
, owner
, IOUserClientOwner
*, ucLink
);
1630 IODelete(owner
, IOUserClientOwner
, 1);
1632 owners
.next
= owners
.prev
= NULL
;
1635 IOLockUnlock(gIOUserClientOwnersLock
);
1640 iokit_task_app_suspended_changed(task_t task
)
1642 queue_head_t
* taskque
;
1643 IOUserClientOwner
* owner
;
1646 IOLockLock(gIOUserClientOwnersLock
);
1648 taskque
= task_io_user_clients(task
);
1650 queue_iterate(taskque
, owner
, IOUserClientOwner
*, taskLink
) {
1651 if (!owner
->uc
->messageAppSuspended
) {
1655 set
= OSSet::withCapacity(4);
1660 set
->setObject(owner
->uc
);
1663 IOLockUnlock(gIOUserClientOwnersLock
);
1666 set
->iterateObjects(^bool (OSObject
* obj
) {
1669 uc
= (typeof(uc
))obj
;
1673 str
= IOCopyLogNameForPID(task_pid(task
));
1674 IOLog("iokit_task_app_suspended_changed(%s) %s %d\n", str
? str
->getCStringNoCopy() : "",
1675 uc
->getName(), task_is_app_suspended(task
));
1676 OSSafeReleaseNULL(str
);
1679 uc
->message(kIOMessageTaskAppSuspendedChange
, NULL
);
1687 extern "C" kern_return_t
1688 iokit_task_terminate(task_t task
)
1690 IOUserClientOwner
* owner
;
1691 IOUserClient
* dead
;
1693 queue_head_t
* taskque
;
1695 IOLockLock(gIOUserClientOwnersLock
);
1697 taskque
= task_io_user_clients(task
);
1699 while (!queue_empty(taskque
)) {
1700 owner
= (IOUserClientOwner
*)(void *) queue_first(taskque
);
1702 queue_remove(taskque
, owner
, IOUserClientOwner
*, taskLink
);
1703 queue_remove(&uc
->owners
, owner
, IOUserClientOwner
*, ucLink
);
1704 if (queue_empty(&uc
->owners
)) {
1706 IOLog("destroying out of band connect for %s\n", uc
->getName());
1707 // now using the uc queue head as a singly linked queue,
1708 // leaving .next as NULL to mark it empty
1709 uc
->owners
.next
= NULL
;
1710 uc
->owners
.prev
= (queue_entry_t
) dead
;
1713 IODelete(owner
, IOUserClientOwner
, 1);
1716 IOLockUnlock(gIOUserClientOwnersLock
);
1720 dead
= (IOUserClient
*)(void *) dead
->owners
.prev
;
1721 uc
->owners
.prev
= NULL
;
1722 if (uc
->sharedInstance
|| !uc
->closed
) {
1728 return KERN_SUCCESS
;
1732 IOUserClient::free()
1735 mappings
->release();
1741 IOStatisticsUnregisterCounter();
1743 assert(!owners
.next
);
1744 assert(!owners
.prev
);
1747 IODelete(reserved
, ExpansionData
, 1);
1754 IOUserClient::clientDied( void )
1756 IOReturn ret
= kIOReturnNotReady
;
1758 if (sharedInstance
|| OSCompareAndSwap8(0, 1, &closed
)) {
1759 ret
= clientClose();
1766 IOUserClient::clientClose( void )
1768 return kIOReturnUnsupported
;
1772 IOUserClient::getService( void )
1778 IOUserClient::registerNotificationPort(
1779 mach_port_t
/* port */,
1781 UInt32
/* refCon */)
1783 return kIOReturnUnsupported
;
1787 IOUserClient::registerNotificationPort(
1790 io_user_reference_t refCon
)
1792 return registerNotificationPort(port
, type
, (UInt32
) refCon
);
1796 IOUserClient::getNotificationSemaphore( UInt32 notification_type
,
1797 semaphore_t
* semaphore
)
1799 return kIOReturnUnsupported
;
1803 IOUserClient::connectClient( IOUserClient
* /* client */ )
1805 return kIOReturnUnsupported
;
1809 IOUserClient::clientMemoryForType( UInt32 type
,
1810 IOOptionBits
* options
,
1811 IOMemoryDescriptor
** memory
)
1813 return kIOReturnUnsupported
;
1818 IOUserClient::mapClientMemory(
1821 IOOptionBits mapFlags
,
1822 IOVirtualAddress atAddress
)
1829 IOUserClient::mapClientMemory64(
1832 IOOptionBits mapFlags
,
1833 mach_vm_address_t atAddress
)
1836 IOOptionBits options
= 0;
1837 IOMemoryDescriptor
* memory
= NULL
;
1838 IOMemoryMap
* map
= NULL
;
1840 err
= clientMemoryForType((UInt32
) type
, &options
, &memory
);
1842 if (memory
&& (kIOReturnSuccess
== err
)) {
1843 FAKE_STACK_FRAME(getMetaClass());
1845 options
= (options
& ~kIOMapUserOptionsMask
)
1846 | (mapFlags
& kIOMapUserOptionsMask
);
1847 map
= memory
->createMappingInTask( task
, atAddress
, options
);
1850 FAKE_STACK_FRAME_END();
1857 IOUserClient::exportObjectToClient(task_t task
,
1858 OSObject
*obj
, io_object_t
*clientObj
)
1860 mach_port_name_t name
;
1862 name
= IOMachPort::makeSendRightForTask( task
, obj
, IKOT_IOKIT_OBJECT
);
1864 *clientObj
= (io_object_t
)(uintptr_t) name
;
1870 return kIOReturnSuccess
;
1874 IOUserClient::copyPortNameForObjectInTask(task_t task
,
1875 OSObject
*obj
, mach_port_name_t
* port_name
)
1877 mach_port_name_t name
;
1879 name
= IOMachPort::makeSendRightForTask( task
, obj
, IKOT_IOKIT_IDENT
);
1881 *(mach_port_name_t
*) port_name
= name
;
1883 return kIOReturnSuccess
;
1887 IOUserClient::copyObjectForPortNameInTask(task_t task
, mach_port_name_t port_name
,
1892 object
= iokit_lookup_object_with_port_name(port_name
, IKOT_IOKIT_IDENT
, task
);
1896 return object
? kIOReturnSuccess
: kIOReturnIPCError
;
1900 IOUserClient::adjustPortNameReferencesInTask(task_t task
, mach_port_name_t port_name
, mach_port_delta_t delta
)
1902 return iokit_mod_send_right(task
, port_name
, delta
);
1906 IOUserClient::getExternalMethodForIndex( UInt32
/* index */)
1911 IOExternalAsyncMethod
*
1912 IOUserClient::getExternalAsyncMethodForIndex( UInt32
/* index */)
1919 getExternalTrapForIndex(UInt32 index
)
1924 #pragma clang diagnostic push
1925 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1927 // Suppressing the deprecated-declarations warning. Avoiding the use of deprecated
1928 // functions can break clients of kexts implementing getExternalMethodForIndex()
1931 getTargetAndMethodForIndex(IOService
**targetP
, UInt32 index
)
1933 IOExternalMethod
*method
= getExternalMethodForIndex(index
);
1936 *targetP
= (IOService
*) method
->object
;
1942 IOExternalAsyncMethod
*
1944 getAsyncTargetAndMethodForIndex(IOService
** targetP
, UInt32 index
)
1946 IOExternalAsyncMethod
*method
= getExternalAsyncMethodForIndex(index
);
1949 *targetP
= (IOService
*) method
->object
;
1957 getTargetAndTrapForIndex(IOService
** targetP
, UInt32 index
)
1959 IOExternalTrap
*trap
= getExternalTrapForIndex(index
);
1962 *targetP
= trap
->object
;
1967 #pragma clang diagnostic pop
1970 IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference
)
1973 port
= (mach_port_t
) (reference
[0] & ~kIOUCAsync0Flags
);
1975 if (MACH_PORT_NULL
!= port
) {
1976 iokit_release_port_send(port
);
1979 return kIOReturnSuccess
;
1983 IOUserClient::releaseNotificationPort(mach_port_t port
)
1985 if (MACH_PORT_NULL
!= port
) {
1986 iokit_release_port_send(port
);
1989 return kIOReturnSuccess
;
1993 IOUserClient::sendAsyncResult(OSAsyncReference reference
,
1994 IOReturn result
, void *args
[], UInt32 numArgs
)
1996 OSAsyncReference64 reference64
;
1997 io_user_reference_t args64
[kMaxAsyncArgs
];
2000 if (numArgs
> kMaxAsyncArgs
) {
2001 return kIOReturnMessageTooLarge
;
2004 for (idx
= 0; idx
< kOSAsyncRef64Count
; idx
++) {
2005 reference64
[idx
] = REF64(reference
[idx
]);
2008 for (idx
= 0; idx
< numArgs
; idx
++) {
2009 args64
[idx
] = REF64(args
[idx
]);
2012 return sendAsyncResult64(reference64
, result
, args64
, numArgs
);
2016 IOUserClient::sendAsyncResult64WithOptions(OSAsyncReference64 reference
,
2017 IOReturn result
, io_user_reference_t args
[], UInt32 numArgs
, IOOptionBits options
)
2019 return _sendAsyncResult64(reference
, result
, args
, numArgs
, options
);
2023 IOUserClient::sendAsyncResult64(OSAsyncReference64 reference
,
2024 IOReturn result
, io_user_reference_t args
[], UInt32 numArgs
)
2026 return _sendAsyncResult64(reference
, result
, args
, numArgs
, 0);
2030 IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference
,
2031 IOReturn result
, io_user_reference_t args
[], UInt32 numArgs
, IOOptionBits options
)
2034 mach_msg_header_t msgHdr
;
2037 OSNotificationHeader notifyHdr
;
2038 IOAsyncCompletionContent asyncContent
;
2039 uint32_t args
[kMaxAsyncArgs
];
2042 OSNotificationHeader64 notifyHdr
;
2043 IOAsyncCompletionContent asyncContent
;
2044 io_user_reference_t args
[kMaxAsyncArgs
] __attribute__ ((packed
));
2049 mach_port_t replyPort
;
2052 // If no reply port, do nothing.
2053 replyPort
= (mach_port_t
) (reference
[0] & ~kIOUCAsync0Flags
);
2054 if (replyPort
== MACH_PORT_NULL
) {
2055 return kIOReturnSuccess
;
2058 if (numArgs
> kMaxAsyncArgs
) {
2059 return kIOReturnMessageTooLarge
;
2062 bzero(&replyMsg
, sizeof(replyMsg
));
2063 replyMsg
.msgHdr
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
/*remote*/,
2065 replyMsg
.msgHdr
.msgh_remote_port
= replyPort
;
2066 replyMsg
.msgHdr
.msgh_local_port
= NULL
;
2067 replyMsg
.msgHdr
.msgh_id
= kOSNotificationMessageID
;
2068 if (kIOUCAsync64Flag
& reference
[0]) {
2069 replyMsg
.msgHdr
.msgh_size
=
2070 sizeof(replyMsg
.msgHdr
) + sizeof(replyMsg
.m
.msg64
)
2071 - (kMaxAsyncArgs
- numArgs
) * sizeof(io_user_reference_t
);
2072 replyMsg
.m
.msg64
.notifyHdr
.size
= sizeof(IOAsyncCompletionContent
)
2073 + numArgs
* sizeof(io_user_reference_t
);
2074 replyMsg
.m
.msg64
.notifyHdr
.type
= kIOAsyncCompletionNotificationType
;
2075 bcopy(reference
, replyMsg
.m
.msg64
.notifyHdr
.reference
, sizeof(OSAsyncReference64
));
2077 replyMsg
.m
.msg64
.asyncContent
.result
= result
;
2079 bcopy(args
, replyMsg
.m
.msg64
.args
, numArgs
* sizeof(io_user_reference_t
));
2084 replyMsg
.msgHdr
.msgh_size
=
2085 sizeof(replyMsg
.msgHdr
) + sizeof(replyMsg
.m
.msg32
)
2086 - (kMaxAsyncArgs
- numArgs
) * sizeof(uint32_t);
2088 replyMsg
.m
.msg32
.notifyHdr
.size
= sizeof(IOAsyncCompletionContent
)
2089 + numArgs
* sizeof(uint32_t);
2090 replyMsg
.m
.msg32
.notifyHdr
.type
= kIOAsyncCompletionNotificationType
;
2092 for (idx
= 0; idx
< kOSAsyncRefCount
; idx
++) {
2093 replyMsg
.m
.msg32
.notifyHdr
.reference
[idx
] = REF32(reference
[idx
]);
2096 replyMsg
.m
.msg32
.asyncContent
.result
= result
;
2098 for (idx
= 0; idx
< numArgs
; idx
++) {
2099 replyMsg
.m
.msg32
.args
[idx
] = REF32(args
[idx
]);
2103 if ((options
& kIOUserNotifyOptionCanDrop
) != 0) {
2104 kr
= mach_msg_send_from_kernel_with_options( &replyMsg
.msgHdr
,
2105 replyMsg
.msgHdr
.msgh_size
, MACH_SEND_TIMEOUT
, MACH_MSG_TIMEOUT_NONE
);
2107 /* Fail on full queue. */
2108 kr
= mach_msg_send_from_kernel_proper( &replyMsg
.msgHdr
,
2109 replyMsg
.msgHdr
.msgh_size
);
2111 if ((KERN_SUCCESS
!= kr
) && (MACH_SEND_TIMED_OUT
!= kr
) && !(kIOUCAsyncErrorLoggedFlag
& reference
[0])) {
2112 reference
[0] |= kIOUCAsyncErrorLoggedFlag
;
2113 IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__
, kr
);
2119 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2122 #define CHECK(cls, obj, out) \
2124 if( !(out = OSDynamicCast( cls, obj))) \
2125 return( kIOReturnBadArgument )
2127 #define CHECKLOCKED(cls, obj, out) \
2128 IOUserIterator * oIter; \
2130 if( !(oIter = OSDynamicCast(IOUserIterator, obj))) \
2131 return (kIOReturnBadArgument); \
2132 if( !(out = OSDynamicCast(cls, oIter->userIteratorObject))) \
2133 return (kIOReturnBadArgument)
2135 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2137 // Create a vm_map_copy_t or kalloc'ed data for memory
2138 // to be copied out. ipc will free after the copyout.
2140 static kern_return_t
2141 copyoutkdata( const void * data
, vm_size_t len
,
2142 io_buf_ptr_t
* buf
)
2147 err
= vm_map_copyin( kernel_map
, CAST_USER_ADDR_T(data
), len
,
2148 false /* src_destroy */, ©
);
2150 assert( err
== KERN_SUCCESS
);
2151 if (err
== KERN_SUCCESS
) {
2152 *buf
= (char *) copy
;
2158 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2160 /* Routine io_server_version */
2162 is_io_server_version(
2163 mach_port_t master_port
,
2166 *version
= IOKIT_SERVER_VERSION
;
2167 return kIOReturnSuccess
;
2170 /* Routine io_object_get_class */
2172 is_io_object_get_class(
2174 io_name_t className
)
2176 const OSMetaClass
* my_obj
= NULL
;
2179 return kIOReturnBadArgument
;
2182 my_obj
= object
->getMetaClass();
2184 return kIOReturnNotFound
;
2187 strlcpy( className
, my_obj
->getClassName(), sizeof(io_name_t
));
2189 return kIOReturnSuccess
;
2192 /* Routine io_object_get_superclass */
2194 is_io_object_get_superclass(
2195 mach_port_t master_port
,
2197 io_name_t class_name
)
2200 const OSMetaClass
* meta
;
2201 const OSMetaClass
* super
;
2202 const OSSymbol
* name
;
2205 if (!obj_name
|| !class_name
) {
2206 return kIOReturnBadArgument
;
2208 if (master_port
!= master_device_port
) {
2209 return kIOReturnNotPrivileged
;
2212 ret
= kIOReturnNotFound
;
2215 name
= OSSymbol::withCString(obj_name
);
2219 meta
= OSMetaClass::copyMetaClassWithName(name
);
2223 super
= meta
->getSuperClass();
2227 cstr
= super
->getClassName();
2231 strlcpy(class_name
, cstr
, sizeof(io_name_t
));
2232 ret
= kIOReturnSuccess
;
2235 OSSafeReleaseNULL(name
);
2237 meta
->releaseMetaClass();
2243 /* Routine io_object_get_bundle_identifier */
2245 is_io_object_get_bundle_identifier(
2246 mach_port_t master_port
,
2248 io_name_t bundle_name
)
2251 const OSMetaClass
* meta
;
2252 const OSSymbol
* name
;
2253 const OSSymbol
* identifier
;
2256 if (!obj_name
|| !bundle_name
) {
2257 return kIOReturnBadArgument
;
2259 if (master_port
!= master_device_port
) {
2260 return kIOReturnNotPrivileged
;
2263 ret
= kIOReturnNotFound
;
2266 name
= OSSymbol::withCString(obj_name
);
2270 meta
= OSMetaClass::copyMetaClassWithName(name
);
2274 identifier
= meta
->getKmodName();
2278 cstr
= identifier
->getCStringNoCopy();
2282 strlcpy(bundle_name
, identifier
->getCStringNoCopy(), sizeof(io_name_t
));
2283 ret
= kIOReturnSuccess
;
2286 OSSafeReleaseNULL(name
);
2288 meta
->releaseMetaClass();
2294 /* Routine io_object_conforms_to */
2296 is_io_object_conforms_to(
2298 io_name_t className
,
2299 boolean_t
*conforms
)
2302 return kIOReturnBadArgument
;
2305 *conforms
= (NULL
!= object
->metaCast( className
));
2307 return kIOReturnSuccess
;
2310 /* Routine io_object_get_retain_count */
2312 is_io_object_get_retain_count(
2314 uint32_t *retainCount
)
2317 return kIOReturnBadArgument
;
2320 *retainCount
= object
->getRetainCount();
2321 return kIOReturnSuccess
;
2324 /* Routine io_iterator_next */
2326 is_io_iterator_next(
2327 io_object_t iterator
,
2328 io_object_t
*object
)
2333 IOUserIterator
* uiter
;
2335 if ((uiter
= OSDynamicCast(IOUserIterator
, iterator
))) {
2336 obj
= uiter
->copyNextObject();
2337 } else if ((iter
= OSDynamicCast(OSIterator
, iterator
))) {
2338 obj
= iter
->getNextObject();
2343 return kIOReturnBadArgument
;
2348 ret
= kIOReturnSuccess
;
2350 ret
= kIOReturnNoDevice
;
2356 /* Routine io_iterator_reset */
2358 is_io_iterator_reset(
2359 io_object_t iterator
)
2361 CHECK( OSIterator
, iterator
, iter
);
2365 return kIOReturnSuccess
;
2368 /* Routine io_iterator_is_valid */
2370 is_io_iterator_is_valid(
2371 io_object_t iterator
,
2372 boolean_t
*is_valid
)
2374 CHECK( OSIterator
, iterator
, iter
);
2376 *is_valid
= iter
->isValid();
2378 return kIOReturnSuccess
;
2382 static kern_return_t
2383 internal_io_service_match_property_table(
2384 io_service_t _service
,
2385 const char * matching
,
2386 mach_msg_type_number_t matching_size
,
2389 CHECK( IOService
, _service
, service
);
2393 OSDictionary
* dict
;
2395 assert(matching_size
);
2396 obj
= OSUnserializeXML(matching
, matching_size
);
2398 if ((dict
= OSDynamicCast( OSDictionary
, obj
))) {
2399 *matches
= service
->passiveMatch( dict
);
2400 kr
= kIOReturnSuccess
;
2402 kr
= kIOReturnBadArgument
;
2412 /* Routine io_service_match_property_table */
2414 is_io_service_match_property_table(
2415 io_service_t service
,
2416 io_string_t matching
,
2417 boolean_t
*matches
)
2419 return kIOReturnUnsupported
;
2423 /* Routine io_service_match_property_table_ool */
2425 is_io_service_match_property_table_ool(
2426 io_object_t service
,
2427 io_buf_ptr_t matching
,
2428 mach_msg_type_number_t matchingCnt
,
2429 kern_return_t
*result
,
2430 boolean_t
*matches
)
2434 vm_map_offset_t map_data
;
2436 kr
= vm_map_copyout( kernel_map
, &map_data
, (vm_map_copy_t
) matching
);
2437 data
= CAST_DOWN(vm_offset_t
, map_data
);
2439 if (KERN_SUCCESS
== kr
) {
2440 // must return success after vm_map_copyout() succeeds
2441 *result
= internal_io_service_match_property_table(service
,
2442 (const char *)data
, matchingCnt
, matches
);
2443 vm_deallocate( kernel_map
, data
, matchingCnt
);
2449 /* Routine io_service_match_property_table_bin */
2451 is_io_service_match_property_table_bin(
2452 io_object_t service
,
2453 io_struct_inband_t matching
,
2454 mach_msg_type_number_t matchingCnt
,
2457 return internal_io_service_match_property_table(service
, matching
, matchingCnt
, matches
);
2460 static kern_return_t
2461 internal_io_service_get_matching_services(
2462 mach_port_t master_port
,
2463 const char * matching
,
2464 mach_msg_type_number_t matching_size
,
2465 io_iterator_t
*existing
)
2469 OSDictionary
* dict
;
2471 if (master_port
!= master_device_port
) {
2472 return kIOReturnNotPrivileged
;
2475 assert(matching_size
);
2476 obj
= OSUnserializeXML(matching
, matching_size
);
2478 if ((dict
= OSDynamicCast( OSDictionary
, obj
))) {
2479 *existing
= IOUserIterator::withIterator(IOService::getMatchingServices( dict
));
2480 kr
= kIOReturnSuccess
;
2482 kr
= kIOReturnBadArgument
;
2492 /* Routine io_service_get_matching_services */
2494 is_io_service_get_matching_services(
2495 mach_port_t master_port
,
2496 io_string_t matching
,
2497 io_iterator_t
*existing
)
2499 return kIOReturnUnsupported
;
2502 /* Routine io_service_get_matching_services_ool */
2504 is_io_service_get_matching_services_ool(
2505 mach_port_t master_port
,
2506 io_buf_ptr_t matching
,
2507 mach_msg_type_number_t matchingCnt
,
2508 kern_return_t
*result
,
2509 io_object_t
*existing
)
2513 vm_map_offset_t map_data
;
2515 kr
= vm_map_copyout( kernel_map
, &map_data
, (vm_map_copy_t
) matching
);
2516 data
= CAST_DOWN(vm_offset_t
, map_data
);
2518 if (KERN_SUCCESS
== kr
) {
2519 // must return success after vm_map_copyout() succeeds
2520 // and mig will copy out objects on success
2522 *result
= internal_io_service_get_matching_services(master_port
,
2523 (const char *) data
, matchingCnt
, existing
);
2524 vm_deallocate( kernel_map
, data
, matchingCnt
);
2530 /* Routine io_service_get_matching_services_bin */
2532 is_io_service_get_matching_services_bin(
2533 mach_port_t master_port
,
2534 io_struct_inband_t matching
,
2535 mach_msg_type_number_t matchingCnt
,
2536 io_object_t
*existing
)
2538 return internal_io_service_get_matching_services(master_port
, matching
, matchingCnt
, existing
);
2542 static kern_return_t
2543 internal_io_service_get_matching_service(
2544 mach_port_t master_port
,
2545 const char * matching
,
2546 mach_msg_type_number_t matching_size
,
2547 io_service_t
*service
)
2551 OSDictionary
* dict
;
2553 if (master_port
!= master_device_port
) {
2554 return kIOReturnNotPrivileged
;
2557 assert(matching_size
);
2558 obj
= OSUnserializeXML(matching
, matching_size
);
2560 if ((dict
= OSDynamicCast( OSDictionary
, obj
))) {
2561 *service
= IOService::copyMatchingService( dict
);
2562 kr
= *service
? kIOReturnSuccess
: kIOReturnNotFound
;
2564 kr
= kIOReturnBadArgument
;
2574 /* Routine io_service_get_matching_service */
2576 is_io_service_get_matching_service(
2577 mach_port_t master_port
,
2578 io_string_t matching
,
2579 io_service_t
*service
)
2581 return kIOReturnUnsupported
;
2584 /* Routine io_service_get_matching_services_ool */
2586 is_io_service_get_matching_service_ool(
2587 mach_port_t master_port
,
2588 io_buf_ptr_t matching
,
2589 mach_msg_type_number_t matchingCnt
,
2590 kern_return_t
*result
,
2591 io_object_t
*service
)
2595 vm_map_offset_t map_data
;
2597 kr
= vm_map_copyout( kernel_map
, &map_data
, (vm_map_copy_t
) matching
);
2598 data
= CAST_DOWN(vm_offset_t
, map_data
);
2600 if (KERN_SUCCESS
== kr
) {
2601 // must return success after vm_map_copyout() succeeds
2602 // and mig will copy out objects on success
2604 *result
= internal_io_service_get_matching_service(master_port
,
2605 (const char *) data
, matchingCnt
, service
);
2606 vm_deallocate( kernel_map
, data
, matchingCnt
);
2612 /* Routine io_service_get_matching_service_bin */
2614 is_io_service_get_matching_service_bin(
2615 mach_port_t master_port
,
2616 io_struct_inband_t matching
,
2617 mach_msg_type_number_t matchingCnt
,
2618 io_object_t
*service
)
2620 return internal_io_service_get_matching_service(master_port
, matching
, matchingCnt
, service
);
2623 static kern_return_t
2624 internal_io_service_add_notification(
2625 mach_port_t master_port
,
2626 io_name_t notification_type
,
2627 const char * matching
,
2628 size_t matching_size
,
2631 vm_size_t referenceSize
,
2633 io_object_t
* notification
)
2635 IOServiceUserNotification
* userNotify
= NULL
;
2636 IONotifier
* notify
= NULL
;
2637 const OSSymbol
* sym
;
2638 OSDictionary
* dict
;
2640 unsigned long int userMsgType
;
2642 if (master_port
!= master_device_port
) {
2643 return kIOReturnNotPrivileged
;
2647 err
= kIOReturnNoResources
;
2649 if (matching_size
> (sizeof(io_struct_inband_t
) * 1024)) {
2650 return kIOReturnMessageTooLarge
;
2653 if (!(sym
= OSSymbol::withCString( notification_type
))) {
2654 err
= kIOReturnNoResources
;
2657 assert(matching_size
);
2658 dict
= OSDynamicCast(OSDictionary
, OSUnserializeXML(matching
, matching_size
));
2660 err
= kIOReturnBadArgument
;
2664 if ((sym
== gIOPublishNotification
)
2665 || (sym
== gIOFirstPublishNotification
)) {
2666 userMsgType
= kIOServicePublishNotificationType
;
2667 } else if ((sym
== gIOMatchedNotification
)
2668 || (sym
== gIOFirstMatchNotification
)) {
2669 userMsgType
= kIOServiceMatchedNotificationType
;
2670 } else if ((sym
== gIOTerminatedNotification
)
2671 || (sym
== gIOWillTerminateNotification
)) {
2672 userMsgType
= kIOServiceTerminatedNotificationType
;
2674 userMsgType
= kLastIOKitNotificationType
;
2677 userNotify
= new IOServiceUserNotification
;
2679 if (userNotify
&& !userNotify
->init( port
, userMsgType
,
2680 reference
, referenceSize
, client64
)) {
2681 userNotify
->release();
2688 notify
= IOService::addMatchingNotification( sym
, dict
,
2689 &userNotify
->_handler
, userNotify
);
2691 *notification
= userNotify
;
2692 userNotify
->setNotification( notify
);
2693 err
= kIOReturnSuccess
;
2695 err
= kIOReturnUnsupported
;
2699 if ((kIOReturnSuccess
!= err
) && userNotify
) {
2700 userNotify
->invalidatePort();
2701 userNotify
->release();
2716 /* Routine io_service_add_notification */
2718 is_io_service_add_notification(
2719 mach_port_t master_port
,
2720 io_name_t notification_type
,
2721 io_string_t matching
,
2723 io_async_ref_t reference
,
2724 mach_msg_type_number_t referenceCnt
,
2725 io_object_t
* notification
)
2727 return kIOReturnUnsupported
;
2730 /* Routine io_service_add_notification_64 */
2732 is_io_service_add_notification_64(
2733 mach_port_t master_port
,
2734 io_name_t notification_type
,
2735 io_string_t matching
,
2736 mach_port_t wake_port
,
2737 io_async_ref64_t reference
,
2738 mach_msg_type_number_t referenceCnt
,
2739 io_object_t
*notification
)
2741 return kIOReturnUnsupported
;
2744 /* Routine io_service_add_notification_bin */
2746 is_io_service_add_notification_bin
2748 mach_port_t master_port
,
2749 io_name_t notification_type
,
2750 io_struct_inband_t matching
,
2751 mach_msg_type_number_t matchingCnt
,
2752 mach_port_t wake_port
,
2753 io_async_ref_t reference
,
2754 mach_msg_type_number_t referenceCnt
,
2755 io_object_t
*notification
)
2757 io_async_ref_t zreference
;
2759 if (referenceCnt
> ASYNC_REF_COUNT
) {
2760 return kIOReturnBadArgument
;
2762 bcopy(&reference
[0], &zreference
[0], referenceCnt
* sizeof(zreference
[0]));
2763 bzero(&zreference
[referenceCnt
], (ASYNC_REF_COUNT
- referenceCnt
) * sizeof(zreference
[0]));
2765 return internal_io_service_add_notification(master_port
, notification_type
,
2766 matching
, matchingCnt
, wake_port
, &zreference
[0], sizeof(io_async_ref_t
),
2767 false, notification
);
2770 /* Routine io_service_add_notification_bin_64 */
2772 is_io_service_add_notification_bin_64
2774 mach_port_t master_port
,
2775 io_name_t notification_type
,
2776 io_struct_inband_t matching
,
2777 mach_msg_type_number_t matchingCnt
,
2778 mach_port_t wake_port
,
2779 io_async_ref64_t reference
,
2780 mach_msg_type_number_t referenceCnt
,
2781 io_object_t
*notification
)
2783 io_async_ref64_t zreference
;
2785 if (referenceCnt
> ASYNC_REF64_COUNT
) {
2786 return kIOReturnBadArgument
;
2788 bcopy(&reference
[0], &zreference
[0], referenceCnt
* sizeof(zreference
[0]));
2789 bzero(&zreference
[referenceCnt
], (ASYNC_REF64_COUNT
- referenceCnt
) * sizeof(zreference
[0]));
2791 return internal_io_service_add_notification(master_port
, notification_type
,
2792 matching
, matchingCnt
, wake_port
, &zreference
[0], sizeof(io_async_ref64_t
),
2793 true, notification
);
2796 static kern_return_t
2797 internal_io_service_add_notification_ool(
2798 mach_port_t master_port
,
2799 io_name_t notification_type
,
2800 io_buf_ptr_t matching
,
2801 mach_msg_type_number_t matchingCnt
,
2802 mach_port_t wake_port
,
2804 vm_size_t referenceSize
,
2806 kern_return_t
*result
,
2807 io_object_t
*notification
)
2811 vm_map_offset_t map_data
;
2813 kr
= vm_map_copyout( kernel_map
, &map_data
, (vm_map_copy_t
) matching
);
2814 data
= CAST_DOWN(vm_offset_t
, map_data
);
2816 if (KERN_SUCCESS
== kr
) {
2817 // must return success after vm_map_copyout() succeeds
2818 // and mig will copy out objects on success
2819 *notification
= NULL
;
2820 *result
= internal_io_service_add_notification( master_port
, notification_type
,
2821 (char *) data
, matchingCnt
, wake_port
, reference
, referenceSize
, client64
, notification
);
2822 vm_deallocate( kernel_map
, data
, matchingCnt
);
2828 /* Routine io_service_add_notification_ool */
2830 is_io_service_add_notification_ool(
2831 mach_port_t master_port
,
2832 io_name_t notification_type
,
2833 io_buf_ptr_t matching
,
2834 mach_msg_type_number_t matchingCnt
,
2835 mach_port_t wake_port
,
2836 io_async_ref_t reference
,
2837 mach_msg_type_number_t referenceCnt
,
2838 kern_return_t
*result
,
2839 io_object_t
*notification
)
2841 io_async_ref_t zreference
;
2843 if (referenceCnt
> ASYNC_REF_COUNT
) {
2844 return kIOReturnBadArgument
;
2846 bcopy(&reference
[0], &zreference
[0], referenceCnt
* sizeof(zreference
[0]));
2847 bzero(&zreference
[referenceCnt
], (ASYNC_REF_COUNT
- referenceCnt
) * sizeof(zreference
[0]));
2849 return internal_io_service_add_notification_ool(master_port
, notification_type
,
2850 matching
, matchingCnt
, wake_port
, &zreference
[0], sizeof(io_async_ref_t
),
2851 false, result
, notification
);
2854 /* Routine io_service_add_notification_ool_64 */
2856 is_io_service_add_notification_ool_64(
2857 mach_port_t master_port
,
2858 io_name_t notification_type
,
2859 io_buf_ptr_t matching
,
2860 mach_msg_type_number_t matchingCnt
,
2861 mach_port_t wake_port
,
2862 io_async_ref64_t reference
,
2863 mach_msg_type_number_t referenceCnt
,
2864 kern_return_t
*result
,
2865 io_object_t
*notification
)
2867 io_async_ref64_t zreference
;
2869 if (referenceCnt
> ASYNC_REF64_COUNT
) {
2870 return kIOReturnBadArgument
;
2872 bcopy(&reference
[0], &zreference
[0], referenceCnt
* sizeof(zreference
[0]));
2873 bzero(&zreference
[referenceCnt
], (ASYNC_REF64_COUNT
- referenceCnt
) * sizeof(zreference
[0]));
2875 return internal_io_service_add_notification_ool(master_port
, notification_type
,
2876 matching
, matchingCnt
, wake_port
, &zreference
[0], sizeof(io_async_ref64_t
),
2877 true, result
, notification
);
2880 /* Routine io_service_add_notification_old */
2882 is_io_service_add_notification_old(
2883 mach_port_t master_port
,
2884 io_name_t notification_type
,
2885 io_string_t matching
,
2887 // for binary compatibility reasons, this must be natural_t for ILP32
2889 io_object_t
* notification
)
2891 return is_io_service_add_notification( master_port
, notification_type
,
2892 matching
, port
, &ref
, 1, notification
);
2896 static kern_return_t
2897 internal_io_service_add_interest_notification(
2898 io_object_t _service
,
2899 io_name_t type_of_interest
,
2902 vm_size_t referenceSize
,
2904 io_object_t
* notification
)
2906 IOServiceMessageUserNotification
* userNotify
= NULL
;
2907 IONotifier
* notify
= NULL
;
2908 const OSSymbol
* sym
;
2911 CHECK( IOService
, _service
, service
);
2913 err
= kIOReturnNoResources
;
2914 if ((sym
= OSSymbol::withCString( type_of_interest
))) {
2916 userNotify
= new IOServiceMessageUserNotification
;
2918 if (userNotify
&& !userNotify
->init( port
, kIOServiceMessageNotificationType
,
2919 reference
, referenceSize
,
2920 kIOUserNotifyMaxMessageSize
,
2922 userNotify
->release();
2929 notify
= service
->registerInterest( sym
,
2930 &userNotify
->_handler
, userNotify
);
2932 *notification
= userNotify
;
2933 userNotify
->setNotification( notify
);
2934 err
= kIOReturnSuccess
;
2936 err
= kIOReturnUnsupported
;
2943 if ((kIOReturnSuccess
!= err
) && userNotify
) {
2944 userNotify
->invalidatePort();
2945 userNotify
->release();
2952 /* Routine io_service_add_message_notification */
2954 is_io_service_add_interest_notification(
2955 io_object_t service
,
2956 io_name_t type_of_interest
,
2958 io_async_ref_t reference
,
2959 mach_msg_type_number_t referenceCnt
,
2960 io_object_t
* notification
)
2962 io_async_ref_t zreference
;
2964 if (referenceCnt
> ASYNC_REF_COUNT
) {
2965 return kIOReturnBadArgument
;
2967 bcopy(&reference
[0], &zreference
[0], referenceCnt
* sizeof(zreference
[0]));
2968 bzero(&zreference
[referenceCnt
], (ASYNC_REF_COUNT
- referenceCnt
) * sizeof(zreference
[0]));
2970 return internal_io_service_add_interest_notification(service
, type_of_interest
,
2971 port
, &zreference
[0], sizeof(io_async_ref_t
), false, notification
);
2974 /* Routine io_service_add_interest_notification_64 */
2976 is_io_service_add_interest_notification_64(
2977 io_object_t service
,
2978 io_name_t type_of_interest
,
2979 mach_port_t wake_port
,
2980 io_async_ref64_t reference
,
2981 mach_msg_type_number_t referenceCnt
,
2982 io_object_t
*notification
)
2984 io_async_ref64_t zreference
;
2986 if (referenceCnt
> ASYNC_REF64_COUNT
) {
2987 return kIOReturnBadArgument
;
2989 bcopy(&reference
[0], &zreference
[0], referenceCnt
* sizeof(zreference
[0]));
2990 bzero(&zreference
[referenceCnt
], (ASYNC_REF64_COUNT
- referenceCnt
) * sizeof(zreference
[0]));
2992 return internal_io_service_add_interest_notification(service
, type_of_interest
,
2993 wake_port
, &zreference
[0], sizeof(io_async_ref64_t
), true, notification
);
2997 /* Routine io_service_acknowledge_notification */
2999 is_io_service_acknowledge_notification(
3000 io_object_t _service
,
3001 natural_t notify_ref
,
3002 natural_t response
)
3004 CHECK( IOService
, _service
, service
);
3006 return service
->acknowledgeNotification((IONotificationRef
)(uintptr_t) notify_ref
,
3007 (IOOptionBits
) response
);
3010 /* Routine io_connect_get_semaphore */
3012 is_io_connect_get_notification_semaphore(
3013 io_connect_t connection
,
3014 natural_t notification_type
,
3015 semaphore_t
*semaphore
)
3017 CHECK( IOUserClient
, connection
, client
);
3019 IOStatisticsClientCall();
3020 return client
->getNotificationSemaphore((UInt32
) notification_type
,
3024 /* Routine io_registry_get_root_entry */
3026 is_io_registry_get_root_entry(
3027 mach_port_t master_port
,
3030 IORegistryEntry
* entry
;
3032 if (master_port
!= master_device_port
) {
3033 return kIOReturnNotPrivileged
;
3036 entry
= IORegistryEntry::getRegistryRoot();
3042 return kIOReturnSuccess
;
3045 /* Routine io_registry_create_iterator */
3047 is_io_registry_create_iterator(
3048 mach_port_t master_port
,
3051 io_object_t
*iterator
)
3053 if (master_port
!= master_device_port
) {
3054 return kIOReturnNotPrivileged
;
3057 *iterator
= IOUserIterator::withIterator(
3058 IORegistryIterator::iterateOver(
3059 IORegistryEntry::getPlane( plane
), options
));
3061 return *iterator
? kIOReturnSuccess
: kIOReturnBadArgument
;
3064 /* Routine io_registry_entry_create_iterator */
3066 is_io_registry_entry_create_iterator(
3067 io_object_t registry_entry
,
3070 io_object_t
*iterator
)
3072 CHECK( IORegistryEntry
, registry_entry
, entry
);
3074 *iterator
= IOUserIterator::withIterator(
3075 IORegistryIterator::iterateOver( entry
,
3076 IORegistryEntry::getPlane( plane
), options
));
3078 return *iterator
? kIOReturnSuccess
: kIOReturnBadArgument
;
3081 /* Routine io_registry_iterator_enter */
3083 is_io_registry_iterator_enter_entry(
3084 io_object_t iterator
)
3086 CHECKLOCKED( IORegistryIterator
, iterator
, iter
);
3088 IOLockLock(oIter
->lock
);
3090 IOLockUnlock(oIter
->lock
);
3092 return kIOReturnSuccess
;
3095 /* Routine io_registry_iterator_exit */
3097 is_io_registry_iterator_exit_entry(
3098 io_object_t iterator
)
3102 CHECKLOCKED( IORegistryIterator
, iterator
, iter
);
3104 IOLockLock(oIter
->lock
);
3105 didIt
= iter
->exitEntry();
3106 IOLockUnlock(oIter
->lock
);
3108 return didIt
? kIOReturnSuccess
: kIOReturnNoDevice
;
3111 /* Routine io_registry_entry_from_path */
3113 is_io_registry_entry_from_path(
3114 mach_port_t master_port
,
3116 io_object_t
*registry_entry
)
3118 IORegistryEntry
* entry
;
3120 if (master_port
!= master_device_port
) {
3121 return kIOReturnNotPrivileged
;
3124 entry
= IORegistryEntry::fromPath( path
);
3126 *registry_entry
= entry
;
3128 return kIOReturnSuccess
;
3132 /* Routine io_registry_entry_from_path */
3134 is_io_registry_entry_from_path_ool(
3135 mach_port_t master_port
,
3136 io_string_inband_t path
,
3137 io_buf_ptr_t path_ool
,
3138 mach_msg_type_number_t path_oolCnt
,
3139 kern_return_t
*result
,
3140 io_object_t
*registry_entry
)
3142 IORegistryEntry
* entry
;
3143 vm_map_offset_t map_data
;
3148 if (master_port
!= master_device_port
) {
3149 return kIOReturnNotPrivileged
;
3154 res
= err
= KERN_SUCCESS
;
3159 return kIOReturnBadArgument
;
3161 if (path_oolCnt
> (sizeof(io_struct_inband_t
) * 1024)) {
3162 return kIOReturnMessageTooLarge
;
3165 err
= vm_map_copyout(kernel_map
, &map_data
, (vm_map_copy_t
) path_ool
);
3166 if (KERN_SUCCESS
== err
) {
3167 // must return success to mig after vm_map_copyout() succeeds, so result is actual
3168 cpath
= CAST_DOWN(const char *, map_data
);
3169 if (cpath
[path_oolCnt
- 1]) {
3170 res
= kIOReturnBadArgument
;
3175 if ((KERN_SUCCESS
== err
) && (KERN_SUCCESS
== res
)) {
3176 entry
= IORegistryEntry::fromPath(cpath
);
3177 res
= entry
? kIOReturnSuccess
: kIOReturnNotFound
;
3181 vm_deallocate(kernel_map
, map_data
, path_oolCnt
);
3184 if (KERN_SUCCESS
!= err
) {
3187 *registry_entry
= entry
;
3194 /* Routine io_registry_entry_in_plane */
3196 is_io_registry_entry_in_plane(
3197 io_object_t registry_entry
,
3199 boolean_t
*inPlane
)
3201 CHECK( IORegistryEntry
, registry_entry
, entry
);
3203 *inPlane
= entry
->inPlane( IORegistryEntry::getPlane( plane
));
3205 return kIOReturnSuccess
;
3209 /* Routine io_registry_entry_get_path */
3211 is_io_registry_entry_get_path(
3212 io_object_t registry_entry
,
3217 CHECK( IORegistryEntry
, registry_entry
, entry
);
3219 length
= sizeof(io_string_t
);
3220 if (entry
->getPath( path
, &length
, IORegistryEntry::getPlane( plane
))) {
3221 return kIOReturnSuccess
;
3223 return kIOReturnBadArgument
;
3227 /* Routine io_registry_entry_get_path */
3229 is_io_registry_entry_get_path_ool(
3230 io_object_t registry_entry
,
3232 io_string_inband_t path
,
3233 io_buf_ptr_t
*path_ool
,
3234 mach_msg_type_number_t
*path_oolCnt
)
3236 enum { kMaxPath
= 16384 };
3241 CHECK( IORegistryEntry
, registry_entry
, entry
);
3245 length
= sizeof(io_string_inband_t
);
3246 if (entry
->getPath(path
, &length
, IORegistryEntry::getPlane(plane
))) {
3247 err
= kIOReturnSuccess
;
3250 buf
= IONew(char, length
);
3252 err
= kIOReturnNoMemory
;
3253 } else if (!entry
->getPath(buf
, &length
, IORegistryEntry::getPlane(plane
))) {
3254 err
= kIOReturnError
;
3256 *path_oolCnt
= length
;
3257 err
= copyoutkdata(buf
, length
, path_ool
);
3260 IODelete(buf
, char, kMaxPath
);
3268 /* Routine io_registry_entry_get_name */
3270 is_io_registry_entry_get_name(
3271 io_object_t registry_entry
,
3274 CHECK( IORegistryEntry
, registry_entry
, entry
);
3276 strncpy( name
, entry
->getName(), sizeof(io_name_t
));
3278 return kIOReturnSuccess
;
3281 /* Routine io_registry_entry_get_name_in_plane */
3283 is_io_registry_entry_get_name_in_plane(
3284 io_object_t registry_entry
,
3285 io_name_t planeName
,
3288 const IORegistryPlane
* plane
;
3289 CHECK( IORegistryEntry
, registry_entry
, entry
);
3292 plane
= IORegistryEntry::getPlane( planeName
);
3297 strncpy( name
, entry
->getName( plane
), sizeof(io_name_t
));
3299 return kIOReturnSuccess
;
3302 /* Routine io_registry_entry_get_location_in_plane */
3304 is_io_registry_entry_get_location_in_plane(
3305 io_object_t registry_entry
,
3306 io_name_t planeName
,
3307 io_name_t location
)
3309 const IORegistryPlane
* plane
;
3310 CHECK( IORegistryEntry
, registry_entry
, entry
);
3313 plane
= IORegistryEntry::getPlane( planeName
);
3318 const char * cstr
= entry
->getLocation( plane
);
3321 strncpy( location
, cstr
, sizeof(io_name_t
));
3322 return kIOReturnSuccess
;
3324 return kIOReturnNotFound
;
3328 /* Routine io_registry_entry_get_registry_entry_id */
3330 is_io_registry_entry_get_registry_entry_id(
3331 io_object_t registry_entry
,
3332 uint64_t *entry_id
)
3334 CHECK( IORegistryEntry
, registry_entry
, entry
);
3336 *entry_id
= entry
->getRegistryEntryID();
3338 return kIOReturnSuccess
;
3341 /* Routine io_registry_entry_get_property */
3343 is_io_registry_entry_get_property_bytes(
3344 io_object_t registry_entry
,
3345 io_name_t property_name
,
3346 io_struct_inband_t buf
,
3347 mach_msg_type_number_t
*dataCnt
)
3355 unsigned int len
= 0;
3356 const void * bytes
= NULL
;
3357 IOReturn ret
= kIOReturnSuccess
;
3359 CHECK( IORegistryEntry
, registry_entry
, entry
);
3362 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry
, property_name
)) {
3363 return kIOReturnNotPermitted
;
3367 obj
= entry
->copyProperty(property_name
);
3369 return kIOReturnNoResources
;
3372 // One day OSData will be a common container base class
3374 if ((data
= OSDynamicCast( OSData
, obj
))) {
3375 len
= data
->getLength();
3376 bytes
= data
->getBytesNoCopy();
3377 if (!data
->isSerializable()) {
3380 } else if ((str
= OSDynamicCast( OSString
, obj
))) {
3381 len
= str
->getLength() + 1;
3382 bytes
= str
->getCStringNoCopy();
3383 } else if ((boo
= OSDynamicCast( OSBoolean
, obj
))) {
3384 len
= boo
->isTrue() ? sizeof("Yes") : sizeof("No");
3385 bytes
= boo
->isTrue() ? "Yes" : "No";
3386 } else if ((off
= OSDynamicCast( OSNumber
, obj
))) {
3387 offsetBytes
= off
->unsigned64BitValue();
3388 len
= off
->numberOfBytes();
3389 if (len
> sizeof(offsetBytes
)) {
3390 len
= sizeof(offsetBytes
);
3392 bytes
= &offsetBytes
;
3393 #ifdef __BIG_ENDIAN__
3394 bytes
= (const void *)
3395 (((UInt32
) bytes
) + (sizeof(UInt64
) - len
));
3398 ret
= kIOReturnBadArgument
;
3402 if (*dataCnt
< len
) {
3403 ret
= kIOReturnIPCError
;
3406 bcopy( bytes
, buf
, len
);
3415 /* Routine io_registry_entry_get_property */
3417 is_io_registry_entry_get_property(
3418 io_object_t registry_entry
,
3419 io_name_t property_name
,
3420 io_buf_ptr_t
*properties
,
3421 mach_msg_type_number_t
*propertiesCnt
)
3427 CHECK( IORegistryEntry
, registry_entry
, entry
);
3430 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry
, property_name
)) {
3431 return kIOReturnNotPermitted
;
3435 obj
= entry
->copyProperty(property_name
);
3437 return kIOReturnNotFound
;
3440 OSSerialize
* s
= OSSerialize::withCapacity(4096);
3443 return kIOReturnNoMemory
;
3446 if (obj
->serialize( s
)) {
3447 len
= s
->getLength();
3448 *propertiesCnt
= len
;
3449 err
= copyoutkdata( s
->text(), len
, properties
);
3451 err
= kIOReturnUnsupported
;
3460 /* Routine io_registry_entry_get_property_recursively */
3462 is_io_registry_entry_get_property_recursively(
3463 io_object_t registry_entry
,
3465 io_name_t property_name
,
3467 io_buf_ptr_t
*properties
,
3468 mach_msg_type_number_t
*propertiesCnt
)
3474 CHECK( IORegistryEntry
, registry_entry
, entry
);
3477 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry
, property_name
)) {
3478 return kIOReturnNotPermitted
;
3482 obj
= entry
->copyProperty( property_name
,
3483 IORegistryEntry::getPlane( plane
), options
);
3485 return kIOReturnNotFound
;
3488 OSSerialize
* s
= OSSerialize::withCapacity(4096);
3491 return kIOReturnNoMemory
;
3494 if (obj
->serialize( s
)) {
3495 len
= s
->getLength();
3496 *propertiesCnt
= len
;
3497 err
= copyoutkdata( s
->text(), len
, properties
);
3499 err
= kIOReturnUnsupported
;
3508 /* Routine io_registry_entry_get_properties */
3510 is_io_registry_entry_get_properties(
3511 io_object_t registry_entry
,
3512 io_buf_ptr_t
*properties
,
3513 mach_msg_type_number_t
*propertiesCnt
)
3515 return kIOReturnUnsupported
;
3520 struct GetPropertiesEditorRef
{
3522 IORegistryEntry
* entry
;
3523 OSCollection
* root
;
3526 static const OSMetaClassBase
*
3527 GetPropertiesEditor(void * reference
,
3529 OSCollection
* container
,
3530 const OSSymbol
* name
,
3531 const OSMetaClassBase
* value
)
3533 GetPropertiesEditorRef
* ref
= (typeof(ref
))reference
;
3536 ref
->root
= container
;
3538 if (ref
->root
== container
) {
3539 if (0 != mac_iokit_check_get_property(ref
->cred
, ref
->entry
, name
->getCStringNoCopy())) {
3549 #endif /* CONFIG_MACF */
3551 /* Routine io_registry_entry_get_properties */
3553 is_io_registry_entry_get_properties_bin(
3554 io_object_t registry_entry
,
3555 io_buf_ptr_t
*properties
,
3556 mach_msg_type_number_t
*propertiesCnt
)
3558 kern_return_t err
= kIOReturnSuccess
;
3561 OSSerialize::Editor editor
= NULL
;
3562 void * editRef
= NULL
;
3564 CHECK(IORegistryEntry
, registry_entry
, entry
);
3567 GetPropertiesEditorRef ref
;
3568 if (mac_iokit_check_filter_properties(kauth_cred_get(), entry
)) {
3569 editor
= &GetPropertiesEditor
;
3571 ref
.cred
= kauth_cred_get();
3577 s
= OSSerialize::binaryWithCapacity(4096, editor
, editRef
);
3579 return kIOReturnNoMemory
;
3582 if (!entry
->serializeProperties(s
)) {
3583 err
= kIOReturnUnsupported
;
3586 if (kIOReturnSuccess
== err
) {
3587 len
= s
->getLength();
3588 *propertiesCnt
= len
;
3589 err
= copyoutkdata(s
->text(), len
, properties
);
3596 /* Routine io_registry_entry_get_property_bin */
3598 is_io_registry_entry_get_property_bin(
3599 io_object_t registry_entry
,
3601 io_name_t property_name
,
3603 io_buf_ptr_t
*properties
,
3604 mach_msg_type_number_t
*propertiesCnt
)
3609 const OSSymbol
* sym
;
3611 CHECK( IORegistryEntry
, registry_entry
, entry
);
3614 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry
, property_name
)) {
3615 return kIOReturnNotPermitted
;
3619 sym
= OSSymbol::withCString(property_name
);
3621 return kIOReturnNoMemory
;
3624 if (gIORegistryEntryPropertyKeysKey
== sym
) {
3625 obj
= entry
->copyPropertyKeys();
3627 if ((kIORegistryIterateRecursively
& options
) && plane
[0]) {
3628 obj
= entry
->copyProperty(property_name
,
3629 IORegistryEntry::getPlane(plane
), options
);
3631 obj
= entry
->copyProperty(property_name
);
3633 if (obj
&& gIORemoveOnReadProperties
->containsObject(sym
)) {
3634 entry
->removeProperty(sym
);
3640 return kIOReturnNotFound
;
3643 OSSerialize
* s
= OSSerialize::binaryWithCapacity(4096);
3646 return kIOReturnNoMemory
;
3649 if (obj
->serialize( s
)) {
3650 len
= s
->getLength();
3651 *propertiesCnt
= len
;
3652 err
= copyoutkdata( s
->text(), len
, properties
);
3654 err
= kIOReturnUnsupported
;
3664 /* Routine io_registry_entry_set_properties */
3666 is_io_registry_entry_set_properties
3668 io_object_t registry_entry
,
3669 io_buf_ptr_t properties
,
3670 mach_msg_type_number_t propertiesCnt
,
3671 kern_return_t
* result
)
3677 vm_map_offset_t map_data
;
3679 CHECK( IORegistryEntry
, registry_entry
, entry
);
3681 if (propertiesCnt
> sizeof(io_struct_inband_t
) * 1024) {
3682 return kIOReturnMessageTooLarge
;
3685 err
= vm_map_copyout( kernel_map
, &map_data
, (vm_map_copy_t
) properties
);
3686 data
= CAST_DOWN(vm_offset_t
, map_data
);
3688 if (KERN_SUCCESS
== err
) {
3689 FAKE_STACK_FRAME(entry
->getMetaClass());
3691 // must return success after vm_map_copyout() succeeds
3692 obj
= OSUnserializeXML((const char *) data
, propertiesCnt
);
3693 vm_deallocate( kernel_map
, data
, propertiesCnt
);
3696 res
= kIOReturnBadArgument
;
3699 else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
3700 registry_entry
, obj
)) {
3701 res
= kIOReturnNotPermitted
;
3705 res
= entry
->setProperties( obj
);
3712 FAKE_STACK_FRAME_END();
3721 /* Routine io_registry_entry_get_child_iterator */
3723 is_io_registry_entry_get_child_iterator(
3724 io_object_t registry_entry
,
3726 io_object_t
*iterator
)
3728 CHECK( IORegistryEntry
, registry_entry
, entry
);
3730 *iterator
= IOUserIterator::withIterator(entry
->getChildIterator(
3731 IORegistryEntry::getPlane( plane
)));
3733 return kIOReturnSuccess
;
3736 /* Routine io_registry_entry_get_parent_iterator */
3738 is_io_registry_entry_get_parent_iterator(
3739 io_object_t registry_entry
,
3741 io_object_t
*iterator
)
3743 CHECK( IORegistryEntry
, registry_entry
, entry
);
3745 *iterator
= IOUserIterator::withIterator(entry
->getParentIterator(
3746 IORegistryEntry::getPlane( plane
)));
3748 return kIOReturnSuccess
;
3751 /* Routine io_service_get_busy_state */
3753 is_io_service_get_busy_state(
3754 io_object_t _service
,
3755 uint32_t *busyState
)
3757 CHECK( IOService
, _service
, service
);
3759 *busyState
= service
->getBusyState();
3761 return kIOReturnSuccess
;
3764 /* Routine io_service_get_state */
3766 is_io_service_get_state(
3767 io_object_t _service
,
3769 uint32_t *busy_state
,
3770 uint64_t *accumulated_busy_time
)
3772 CHECK( IOService
, _service
, service
);
3774 *state
= service
->getState();
3775 *busy_state
= service
->getBusyState();
3776 *accumulated_busy_time
= service
->getAccumulatedBusyTime();
3778 return kIOReturnSuccess
;
3781 /* Routine io_service_wait_quiet */
3783 is_io_service_wait_quiet(
3784 io_object_t _service
,
3785 mach_timespec_t wait_time
)
3789 CHECK( IOService
, _service
, service
);
3791 timeoutNS
= wait_time
.tv_sec
;
3792 timeoutNS
*= kSecondScale
;
3793 timeoutNS
+= wait_time
.tv_nsec
;
3795 return service
->waitQuiet(timeoutNS
);
3798 /* Routine io_service_request_probe */
3800 is_io_service_request_probe(
3801 io_object_t _service
,
3804 CHECK( IOService
, _service
, service
);
3806 return service
->requestProbe( options
);
3809 /* Routine io_service_get_authorization_id */
3811 is_io_service_get_authorization_id(
3812 io_object_t _service
,
3813 uint64_t *authorization_id
)
3817 CHECK( IOService
, _service
, service
);
3819 kr
= IOUserClient::clientHasPrivilege((void *) current_task(),
3820 kIOClientPrivilegeAdministrator
);
3821 if (kIOReturnSuccess
!= kr
) {
3825 *authorization_id
= service
->getAuthorizationID();
3830 /* Routine io_service_set_authorization_id */
3832 is_io_service_set_authorization_id(
3833 io_object_t _service
,
3834 uint64_t authorization_id
)
3836 CHECK( IOService
, _service
, service
);
3838 return service
->setAuthorizationID( authorization_id
);
3841 /* Routine io_service_open_ndr */
3843 is_io_service_open_extended(
3844 io_object_t _service
,
3846 uint32_t connect_type
,
3848 io_buf_ptr_t properties
,
3849 mach_msg_type_number_t propertiesCnt
,
3850 kern_return_t
* result
,
3851 io_object_t
*connection
)
3853 IOUserClient
* client
= NULL
;
3854 kern_return_t err
= KERN_SUCCESS
;
3855 IOReturn res
= kIOReturnSuccess
;
3856 OSDictionary
* propertiesDict
= NULL
;
3858 bool disallowAccess
;
3860 CHECK( IOService
, _service
, service
);
3863 return kIOReturnBadArgument
;
3865 assert(owningTask
== current_task());
3866 if (owningTask
!= current_task()) {
3867 return kIOReturnBadArgument
;
3872 return kIOReturnUnsupported
;
3878 vm_map_offset_t map_data
;
3880 if (propertiesCnt
> sizeof(io_struct_inband_t
)) {
3881 return kIOReturnMessageTooLarge
;
3884 err
= vm_map_copyout( kernel_map
, &map_data
, (vm_map_copy_t
) properties
);
3886 data
= CAST_DOWN(vm_offset_t
, map_data
);
3887 if (KERN_SUCCESS
== err
) {
3888 // must return success after vm_map_copyout() succeeds
3889 obj
= OSUnserializeXML((const char *) data
, propertiesCnt
);
3890 vm_deallocate( kernel_map
, data
, propertiesCnt
);
3891 propertiesDict
= OSDynamicCast(OSDictionary
, obj
);
3892 if (!propertiesDict
) {
3893 res
= kIOReturnBadArgument
;
3899 if (kIOReturnSuccess
!= res
) {
3904 crossEndian
= (ndr
.int_rep
!= NDR_record
.int_rep
);
3906 if (!propertiesDict
) {
3907 propertiesDict
= OSDictionary::withCapacity(4);
3909 OSData
* data
= OSData::withBytes(&ndr
, sizeof(ndr
));
3911 if (propertiesDict
) {
3912 propertiesDict
->setObject(kIOUserClientCrossEndianKey
, data
);
3918 res
= service
->newUserClient( owningTask
, (void *) owningTask
,
3919 connect_type
, propertiesDict
, &client
);
3921 if (propertiesDict
) {
3922 propertiesDict
->release();
3925 if (res
== kIOReturnSuccess
) {
3926 assert( OSDynamicCast(IOUserClient
, client
));
3928 client
->sharedInstance
= (NULL
!= client
->getProperty(kIOUserClientSharedInstanceKey
));
3929 client
->messageAppSuspended
= (NULL
!= client
->getProperty(kIOUserClientMessageAppSuspendedKey
));
3930 client
->closed
= false;
3931 client
->lock
= IOLockAlloc();
3933 disallowAccess
= (crossEndian
3934 && (kOSBooleanTrue
!= service
->getProperty(kIOUserClientCrossEndianCompatibleKey
))
3935 && (kOSBooleanTrue
!= client
->getProperty(kIOUserClientCrossEndianCompatibleKey
)));
3936 if (disallowAccess
) {
3937 res
= kIOReturnUnsupported
;
3940 else if (0 != mac_iokit_check_open(kauth_cred_get(), client
, connect_type
)) {
3941 res
= kIOReturnNotPermitted
;
3945 if (kIOReturnSuccess
== res
) {
3946 res
= client
->registerOwner(owningTask
);
3949 if (kIOReturnSuccess
!= res
) {
3950 IOStatisticsClientCall();
3951 client
->clientClose();
3956 OSString
* creatorName
= IOCopyLogNameForPID(proc_selfpid());
3958 client
->setProperty(kIOUserClientCreatorKey
, creatorName
);
3959 creatorName
->release();
3961 client
->setTerminateDefer(service
, false);
3965 *connection
= client
;
3971 /* Routine io_service_close */
3973 is_io_service_close(
3974 io_object_t connection
)
3977 if ((mappings
= OSDynamicCast(OSSet
, connection
))) {
3978 return kIOReturnSuccess
;
3981 CHECK( IOUserClient
, connection
, client
);
3983 IOStatisticsClientCall();
3985 if (client
->sharedInstance
|| OSCompareAndSwap8(0, 1, &client
->closed
)) {
3986 IOLockLock(client
->lock
);
3987 client
->clientClose();
3988 IOLockUnlock(client
->lock
);
3990 IOLog("ignored is_io_service_close(0x%qx,%s)\n",
3991 client
->getRegistryEntryID(), client
->getName());
3994 return kIOReturnSuccess
;
3997 /* Routine io_connect_get_service */
3999 is_io_connect_get_service(
4000 io_object_t connection
,
4001 io_object_t
*service
)
4003 IOService
* theService
;
4005 CHECK( IOUserClient
, connection
, client
);
4007 theService
= client
->getService();
4009 theService
->retain();
4012 *service
= theService
;
4014 return theService
? kIOReturnSuccess
: kIOReturnUnsupported
;
4017 /* Routine io_connect_set_notification_port */
4019 is_io_connect_set_notification_port(
4020 io_object_t connection
,
4021 uint32_t notification_type
,
4026 CHECK( IOUserClient
, connection
, client
);
4028 IOStatisticsClientCall();
4029 IOLockLock(client
->lock
);
4030 ret
= client
->registerNotificationPort( port
, notification_type
,
4031 (io_user_reference_t
) reference
);
4032 IOLockUnlock(client
->lock
);
4036 /* Routine io_connect_set_notification_port */
4038 is_io_connect_set_notification_port_64(
4039 io_object_t connection
,
4040 uint32_t notification_type
,
4042 io_user_reference_t reference
)
4045 CHECK( IOUserClient
, connection
, client
);
4047 IOStatisticsClientCall();
4048 IOLockLock(client
->lock
);
4049 ret
= client
->registerNotificationPort( port
, notification_type
,
4051 IOLockUnlock(client
->lock
);
4055 /* Routine io_connect_map_memory_into_task */
4057 is_io_connect_map_memory_into_task
4059 io_connect_t connection
,
4060 uint32_t memory_type
,
4062 mach_vm_address_t
*address
,
4063 mach_vm_size_t
*size
,
4070 CHECK( IOUserClient
, connection
, client
);
4073 return kIOReturnBadArgument
;
4076 IOStatisticsClientCall();
4077 map
= client
->mapClientMemory64( memory_type
, into_task
, flags
, *address
);
4080 *address
= map
->getAddress();
4082 *size
= map
->getSize();
4085 if (client
->sharedInstance
4086 || (into_task
!= current_task())) {
4087 // push a name out to the task owning the map,
4088 // so we can clean up maps
4089 mach_port_name_t name __unused
=
4090 IOMachPort::makeSendRightForTask(
4091 into_task
, map
, IKOT_IOKIT_OBJECT
);
4094 // keep it with the user client
4095 IOLockLock( gIOObjectPortLock
);
4096 if (NULL
== client
->mappings
) {
4097 client
->mappings
= OSSet::withCapacity(2);
4099 if (client
->mappings
) {
4100 client
->mappings
->setObject( map
);
4102 IOLockUnlock( gIOObjectPortLock
);
4105 err
= kIOReturnSuccess
;
4107 err
= kIOReturnBadArgument
;
4113 /* Routine is_io_connect_map_memory */
4115 is_io_connect_map_memory(
4116 io_object_t connect
,
4124 mach_vm_address_t address
;
4125 mach_vm_size_t size
;
4127 address
= SCALAR64(*mapAddr
);
4128 size
= SCALAR64(*mapSize
);
4130 err
= is_io_connect_map_memory_into_task(connect
, type
, task
, &address
, &size
, flags
);
4132 *mapAddr
= SCALAR32(address
);
4133 *mapSize
= SCALAR32(size
);
4140 IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor
* mem
)
4143 IOMemoryMap
* map
= NULL
;
4145 IOLockLock(gIOObjectPortLock
);
4147 iter
= OSCollectionIterator::withCollection(mappings
);
4149 while ((map
= OSDynamicCast(IOMemoryMap
, iter
->getNextObject()))) {
4150 if (mem
== map
->getMemoryDescriptor()) {
4152 mappings
->removeObject(map
);
4159 IOLockUnlock(gIOObjectPortLock
);
4165 /* Routine io_connect_unmap_memory_from_task */
4167 is_io_connect_unmap_memory_from_task
4169 io_connect_t connection
,
4170 uint32_t memory_type
,
4172 mach_vm_address_t address
)
4175 IOOptionBits options
= 0;
4176 IOMemoryDescriptor
* memory
= NULL
;
4179 CHECK( IOUserClient
, connection
, client
);
4182 return kIOReturnBadArgument
;
4185 IOStatisticsClientCall();
4186 err
= client
->clientMemoryForType((UInt32
) memory_type
, &options
, &memory
);
4188 if (memory
&& (kIOReturnSuccess
== err
)) {
4189 options
= (options
& ~kIOMapUserOptionsMask
)
4190 | kIOMapAnywhere
| kIOMapReference
;
4192 map
= memory
->createMappingInTask( from_task
, address
, options
);
4195 IOLockLock( gIOObjectPortLock
);
4196 if (client
->mappings
) {
4197 client
->mappings
->removeObject( map
);
4199 IOLockUnlock( gIOObjectPortLock
);
4201 mach_port_name_t name
= 0;
4202 if (from_task
!= current_task()) {
4203 name
= IOMachPort::makeSendRightForTask( from_task
, map
, IKOT_IOKIT_OBJECT
);
4208 map
->userClientUnmap();
4209 err
= iokit_mod_send_right( from_task
, name
, -2 );
4210 err
= kIOReturnSuccess
;
4212 IOMachPort::releasePortForObject( map
, IKOT_IOKIT_OBJECT
);
4214 if (from_task
== current_task()) {
4218 err
= kIOReturnBadArgument
;
4226 is_io_connect_unmap_memory(
4227 io_object_t connect
,
4233 mach_vm_address_t address
;
4235 address
= SCALAR64(mapAddr
);
4237 err
= is_io_connect_unmap_memory_from_task(connect
, type
, task
, mapAddr
);
4243 /* Routine io_connect_add_client */
4245 is_io_connect_add_client(
4246 io_object_t connection
,
4247 io_object_t connect_to
)
4249 CHECK( IOUserClient
, connection
, client
);
4250 CHECK( IOUserClient
, connect_to
, to
);
4252 IOStatisticsClientCall();
4253 return client
->connectClient( to
);
4257 /* Routine io_connect_set_properties */
4259 is_io_connect_set_properties(
4260 io_object_t connection
,
4261 io_buf_ptr_t properties
,
4262 mach_msg_type_number_t propertiesCnt
,
4263 kern_return_t
* result
)
4265 return is_io_registry_entry_set_properties( connection
, properties
, propertiesCnt
, result
);
4268 /* Routine io_user_client_method */
4270 is_io_connect_method_var_output
4272 io_connect_t connection
,
4274 io_scalar_inband64_t scalar_input
,
4275 mach_msg_type_number_t scalar_inputCnt
,
4276 io_struct_inband_t inband_input
,
4277 mach_msg_type_number_t inband_inputCnt
,
4278 mach_vm_address_t ool_input
,
4279 mach_vm_size_t ool_input_size
,
4280 io_struct_inband_t inband_output
,
4281 mach_msg_type_number_t
*inband_outputCnt
,
4282 io_scalar_inband64_t scalar_output
,
4283 mach_msg_type_number_t
*scalar_outputCnt
,
4284 io_buf_ptr_t
*var_output
,
4285 mach_msg_type_number_t
*var_outputCnt
4288 CHECK( IOUserClient
, connection
, client
);
4290 IOExternalMethodArguments args
;
4292 IOMemoryDescriptor
* inputMD
= NULL
;
4293 OSObject
* structureVariableOutputData
= NULL
;
4295 bzero(&args
.__reserved
[0], sizeof(args
.__reserved
));
4296 args
.__reservedA
= 0;
4297 args
.version
= kIOExternalMethodArgumentsCurrentVersion
;
4299 args
.selector
= selector
;
4301 args
.asyncWakePort
= MACH_PORT_NULL
;
4302 args
.asyncReference
= NULL
;
4303 args
.asyncReferenceCount
= 0;
4304 args
.structureVariableOutputData
= &structureVariableOutputData
;
4306 args
.scalarInput
= scalar_input
;
4307 args
.scalarInputCount
= scalar_inputCnt
;
4308 args
.structureInput
= inband_input
;
4309 args
.structureInputSize
= inband_inputCnt
;
4311 if (ool_input
&& (ool_input_size
<= sizeof(io_struct_inband_t
))) {
4312 return kIOReturnIPCError
;
4316 inputMD
= IOMemoryDescriptor::withAddressRange(ool_input
, ool_input_size
,
4317 kIODirectionOut
| kIOMemoryMapCopyOnWrite
,
4321 args
.structureInputDescriptor
= inputMD
;
4323 args
.scalarOutput
= scalar_output
;
4324 args
.scalarOutputCount
= *scalar_outputCnt
;
4325 bzero(&scalar_output
[0], *scalar_outputCnt
* sizeof(scalar_output
[0]));
4326 args
.structureOutput
= inband_output
;
4327 args
.structureOutputSize
= *inband_outputCnt
;
4328 args
.structureOutputDescriptor
= NULL
;
4329 args
.structureOutputDescriptorSize
= 0;
4331 IOStatisticsClientCall();
4332 ret
= client
->externalMethod( selector
, &args
);
4334 *scalar_outputCnt
= args
.scalarOutputCount
;
4335 *inband_outputCnt
= args
.structureOutputSize
;
4337 if (var_outputCnt
&& var_output
&& (kIOReturnSuccess
== ret
)) {
4338 OSSerialize
* serialize
;
4342 if ((serialize
= OSDynamicCast(OSSerialize
, structureVariableOutputData
))) {
4343 len
= serialize
->getLength();
4344 *var_outputCnt
= len
;
4345 ret
= copyoutkdata(serialize
->text(), len
, var_output
);
4346 } else if ((data
= OSDynamicCast(OSData
, structureVariableOutputData
))) {
4347 len
= data
->getLength();
4348 *var_outputCnt
= len
;
4349 ret
= copyoutkdata(data
->getBytesNoCopy(), len
, var_output
);
4351 ret
= kIOReturnUnderrun
;
4358 if (structureVariableOutputData
) {
4359 structureVariableOutputData
->release();
4365 /* Routine io_user_client_method */
4367 is_io_connect_method
4369 io_connect_t connection
,
4371 io_scalar_inband64_t scalar_input
,
4372 mach_msg_type_number_t scalar_inputCnt
,
4373 io_struct_inband_t inband_input
,
4374 mach_msg_type_number_t inband_inputCnt
,
4375 mach_vm_address_t ool_input
,
4376 mach_vm_size_t ool_input_size
,
4377 io_struct_inband_t inband_output
,
4378 mach_msg_type_number_t
*inband_outputCnt
,
4379 io_scalar_inband64_t scalar_output
,
4380 mach_msg_type_number_t
*scalar_outputCnt
,
4381 mach_vm_address_t ool_output
,
4382 mach_vm_size_t
*ool_output_size
4385 CHECK( IOUserClient
, connection
, client
);
4387 IOExternalMethodArguments args
;
4389 IOMemoryDescriptor
* inputMD
= NULL
;
4390 IOMemoryDescriptor
* outputMD
= NULL
;
4392 bzero(&args
.__reserved
[0], sizeof(args
.__reserved
));
4393 args
.__reservedA
= 0;
4394 args
.version
= kIOExternalMethodArgumentsCurrentVersion
;
4396 args
.selector
= selector
;
4398 args
.asyncWakePort
= MACH_PORT_NULL
;
4399 args
.asyncReference
= NULL
;
4400 args
.asyncReferenceCount
= 0;
4401 args
.structureVariableOutputData
= NULL
;
4403 args
.scalarInput
= scalar_input
;
4404 args
.scalarInputCount
= scalar_inputCnt
;
4405 args
.structureInput
= inband_input
;
4406 args
.structureInputSize
= inband_inputCnt
;
4408 if (ool_input
&& (ool_input_size
<= sizeof(io_struct_inband_t
))) {
4409 return kIOReturnIPCError
;
4411 if (ool_output
&& (*ool_output_size
<= sizeof(io_struct_inband_t
))) {
4412 return kIOReturnIPCError
;
4416 inputMD
= IOMemoryDescriptor::withAddressRange(ool_input
, ool_input_size
,
4417 kIODirectionOut
| kIOMemoryMapCopyOnWrite
,
4421 args
.structureInputDescriptor
= inputMD
;
4423 args
.scalarOutput
= scalar_output
;
4424 args
.scalarOutputCount
= *scalar_outputCnt
;
4425 bzero(&scalar_output
[0], *scalar_outputCnt
* sizeof(scalar_output
[0]));
4426 args
.structureOutput
= inband_output
;
4427 args
.structureOutputSize
= *inband_outputCnt
;
4429 if (ool_output
&& ool_output_size
) {
4430 outputMD
= IOMemoryDescriptor::withAddressRange(ool_output
, *ool_output_size
,
4431 kIODirectionIn
, current_task());
4434 args
.structureOutputDescriptor
= outputMD
;
4435 args
.structureOutputDescriptorSize
= ool_output_size
? *ool_output_size
: 0;
4437 IOStatisticsClientCall();
4438 ret
= client
->externalMethod( selector
, &args
);
4440 *scalar_outputCnt
= args
.scalarOutputCount
;
4441 *inband_outputCnt
= args
.structureOutputSize
;
4442 *ool_output_size
= args
.structureOutputDescriptorSize
;
4448 outputMD
->release();
4454 /* Routine io_async_user_client_method */
4456 is_io_connect_async_method
4458 io_connect_t connection
,
4459 mach_port_t wake_port
,
4460 io_async_ref64_t reference
,
4461 mach_msg_type_number_t referenceCnt
,
4463 io_scalar_inband64_t scalar_input
,
4464 mach_msg_type_number_t scalar_inputCnt
,
4465 io_struct_inband_t inband_input
,
4466 mach_msg_type_number_t inband_inputCnt
,
4467 mach_vm_address_t ool_input
,
4468 mach_vm_size_t ool_input_size
,
4469 io_struct_inband_t inband_output
,
4470 mach_msg_type_number_t
*inband_outputCnt
,
4471 io_scalar_inband64_t scalar_output
,
4472 mach_msg_type_number_t
*scalar_outputCnt
,
4473 mach_vm_address_t ool_output
,
4474 mach_vm_size_t
* ool_output_size
4477 CHECK( IOUserClient
, connection
, client
);
4479 IOExternalMethodArguments args
;
4481 IOMemoryDescriptor
* inputMD
= NULL
;
4482 IOMemoryDescriptor
* outputMD
= NULL
;
4484 bzero(&args
.__reserved
[0], sizeof(args
.__reserved
));
4485 args
.__reservedA
= 0;
4486 args
.version
= kIOExternalMethodArgumentsCurrentVersion
;
4488 reference
[0] = (io_user_reference_t
) wake_port
;
4489 if (vm_map_is_64bit(get_task_map(current_task()))) {
4490 reference
[0] |= kIOUCAsync64Flag
;
4493 args
.selector
= selector
;
4495 args
.asyncWakePort
= wake_port
;
4496 args
.asyncReference
= reference
;
4497 args
.asyncReferenceCount
= referenceCnt
;
4499 args
.structureVariableOutputData
= NULL
;
4501 args
.scalarInput
= scalar_input
;
4502 args
.scalarInputCount
= scalar_inputCnt
;
4503 args
.structureInput
= inband_input
;
4504 args
.structureInputSize
= inband_inputCnt
;
4506 if (ool_input
&& (ool_input_size
<= sizeof(io_struct_inband_t
))) {
4507 return kIOReturnIPCError
;
4509 if (ool_output
&& (*ool_output_size
<= sizeof(io_struct_inband_t
))) {
4510 return kIOReturnIPCError
;
4514 inputMD
= IOMemoryDescriptor::withAddressRange(ool_input
, ool_input_size
,
4515 kIODirectionOut
| kIOMemoryMapCopyOnWrite
,
4519 args
.structureInputDescriptor
= inputMD
;
4521 args
.scalarOutput
= scalar_output
;
4522 args
.scalarOutputCount
= *scalar_outputCnt
;
4523 bzero(&scalar_output
[0], *scalar_outputCnt
* sizeof(scalar_output
[0]));
4524 args
.structureOutput
= inband_output
;
4525 args
.structureOutputSize
= *inband_outputCnt
;
4528 outputMD
= IOMemoryDescriptor::withAddressRange(ool_output
, *ool_output_size
,
4529 kIODirectionIn
, current_task());
4532 args
.structureOutputDescriptor
= outputMD
;
4533 args
.structureOutputDescriptorSize
= *ool_output_size
;
4535 IOStatisticsClientCall();
4536 ret
= client
->externalMethod( selector
, &args
);
4538 *scalar_outputCnt
= args
.scalarOutputCount
;
4539 *inband_outputCnt
= args
.structureOutputSize
;
4540 *ool_output_size
= args
.structureOutputDescriptorSize
;
4546 outputMD
->release();
4552 /* Routine io_connect_method_scalarI_scalarO */
4554 is_io_connect_method_scalarI_scalarO(
4555 io_object_t connect
,
4557 io_scalar_inband_t input
,
4558 mach_msg_type_number_t inputCount
,
4559 io_scalar_inband_t output
,
4560 mach_msg_type_number_t
* outputCount
)
4564 io_scalar_inband64_t _input
;
4565 io_scalar_inband64_t _output
;
4567 mach_msg_type_number_t struct_outputCnt
= 0;
4568 mach_vm_size_t ool_output_size
= 0;
4570 bzero(&_output
[0], sizeof(_output
));
4571 for (i
= 0; i
< inputCount
; i
++) {
4572 _input
[i
] = SCALAR64(input
[i
]);
4575 err
= is_io_connect_method(connect
, index
,
4579 NULL
, &struct_outputCnt
,
4580 _output
, outputCount
,
4581 0, &ool_output_size
);
4583 for (i
= 0; i
< *outputCount
; i
++) {
4584 output
[i
] = SCALAR32(_output
[i
]);
4591 shim_io_connect_method_scalarI_scalarO(
4592 IOExternalMethod
* method
,
4594 const io_user_scalar_t
* input
,
4595 mach_msg_type_number_t inputCount
,
4596 io_user_scalar_t
* output
,
4597 mach_msg_type_number_t
* outputCount
)
4600 io_scalar_inband_t _output
;
4602 err
= kIOReturnBadArgument
;
4604 bzero(&_output
[0], sizeof(_output
));
4606 if (inputCount
!= method
->count0
) {
4607 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
);
4608 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
4611 if (*outputCount
!= method
->count1
) {
4612 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)*outputCount
, (uint64_t)method
->count1
);
4613 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)*outputCount
, uint64_t, (uint64_t)method
->count1
);
4617 func
= method
->func
;
4619 switch (inputCount
) {
4621 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4622 ARG32(input
[3]), ARG32(input
[4]), ARG32(input
[5]));
4625 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4626 ARG32(input
[3]), ARG32(input
[4]),
4630 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4632 &_output
[0], &_output
[1] );
4635 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4636 &_output
[0], &_output
[1], &_output
[2] );
4639 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]),
4640 &_output
[0], &_output
[1], &_output
[2],
4644 err
= (object
->*func
)( ARG32(input
[0]),
4645 &_output
[0], &_output
[1], &_output
[2],
4646 &_output
[3], &_output
[4] );
4649 err
= (object
->*func
)( &_output
[0], &_output
[1], &_output
[2],
4650 &_output
[3], &_output
[4], &_output
[5] );
4654 IOLog("%s: Bad method table\n", object
->getName());
4659 for (i
= 0; i
< *outputCount
; i
++) {
4660 output
[i
] = SCALAR32(_output
[i
]);
4666 /* Routine io_async_method_scalarI_scalarO */
4668 is_io_async_method_scalarI_scalarO(
4669 io_object_t connect
,
4670 mach_port_t wake_port
,
4671 io_async_ref_t reference
,
4672 mach_msg_type_number_t referenceCnt
,
4674 io_scalar_inband_t input
,
4675 mach_msg_type_number_t inputCount
,
4676 io_scalar_inband_t output
,
4677 mach_msg_type_number_t
* outputCount
)
4681 io_scalar_inband64_t _input
;
4682 io_scalar_inband64_t _output
;
4683 io_async_ref64_t _reference
;
4685 if (referenceCnt
> ASYNC_REF64_COUNT
) {
4686 return kIOReturnBadArgument
;
4688 bzero(&_output
[0], sizeof(_output
));
4689 for (i
= 0; i
< referenceCnt
; i
++) {
4690 _reference
[i
] = REF64(reference
[i
]);
4692 bzero(&_reference
[referenceCnt
], (ASYNC_REF64_COUNT
- referenceCnt
) * sizeof(_reference
[0]));
4694 mach_msg_type_number_t struct_outputCnt
= 0;
4695 mach_vm_size_t ool_output_size
= 0;
4697 for (i
= 0; i
< inputCount
; i
++) {
4698 _input
[i
] = SCALAR64(input
[i
]);
4701 err
= is_io_connect_async_method(connect
,
4702 wake_port
, _reference
, referenceCnt
,
4707 NULL
, &struct_outputCnt
,
4708 _output
, outputCount
,
4709 0, &ool_output_size
);
4711 for (i
= 0; i
< *outputCount
; i
++) {
4712 output
[i
] = SCALAR32(_output
[i
]);
4717 /* Routine io_async_method_scalarI_structureO */
4719 is_io_async_method_scalarI_structureO(
4720 io_object_t connect
,
4721 mach_port_t wake_port
,
4722 io_async_ref_t reference
,
4723 mach_msg_type_number_t referenceCnt
,
4725 io_scalar_inband_t input
,
4726 mach_msg_type_number_t inputCount
,
4727 io_struct_inband_t output
,
4728 mach_msg_type_number_t
* outputCount
)
4731 io_scalar_inband64_t _input
;
4732 io_async_ref64_t _reference
;
4734 if (referenceCnt
> ASYNC_REF64_COUNT
) {
4735 return kIOReturnBadArgument
;
4737 for (i
= 0; i
< referenceCnt
; i
++) {
4738 _reference
[i
] = REF64(reference
[i
]);
4740 bzero(&_reference
[referenceCnt
], (ASYNC_REF64_COUNT
- referenceCnt
) * sizeof(_reference
[0]));
4742 mach_msg_type_number_t scalar_outputCnt
= 0;
4743 mach_vm_size_t ool_output_size
= 0;
4745 for (i
= 0; i
< inputCount
; i
++) {
4746 _input
[i
] = SCALAR64(input
[i
]);
4749 return is_io_connect_async_method(connect
,
4750 wake_port
, _reference
, referenceCnt
,
4755 output
, outputCount
,
4756 NULL
, &scalar_outputCnt
,
4757 0, &ool_output_size
);
4760 /* Routine io_async_method_scalarI_structureI */
4762 is_io_async_method_scalarI_structureI(
4763 io_connect_t connect
,
4764 mach_port_t wake_port
,
4765 io_async_ref_t reference
,
4766 mach_msg_type_number_t referenceCnt
,
4768 io_scalar_inband_t input
,
4769 mach_msg_type_number_t inputCount
,
4770 io_struct_inband_t inputStruct
,
4771 mach_msg_type_number_t inputStructCount
)
4774 io_scalar_inband64_t _input
;
4775 io_async_ref64_t _reference
;
4777 if (referenceCnt
> ASYNC_REF64_COUNT
) {
4778 return kIOReturnBadArgument
;
4780 for (i
= 0; i
< referenceCnt
; i
++) {
4781 _reference
[i
] = REF64(reference
[i
]);
4783 bzero(&_reference
[referenceCnt
], (ASYNC_REF64_COUNT
- referenceCnt
) * sizeof(_reference
[0]));
4785 mach_msg_type_number_t scalar_outputCnt
= 0;
4786 mach_msg_type_number_t inband_outputCnt
= 0;
4787 mach_vm_size_t ool_output_size
= 0;
4789 for (i
= 0; i
< inputCount
; i
++) {
4790 _input
[i
] = SCALAR64(input
[i
]);
4793 return is_io_connect_async_method(connect
,
4794 wake_port
, _reference
, referenceCnt
,
4797 inputStruct
, inputStructCount
,
4799 NULL
, &inband_outputCnt
,
4800 NULL
, &scalar_outputCnt
,
4801 0, &ool_output_size
);
4804 /* Routine io_async_method_structureI_structureO */
4806 is_io_async_method_structureI_structureO(
4807 io_object_t connect
,
4808 mach_port_t wake_port
,
4809 io_async_ref_t reference
,
4810 mach_msg_type_number_t referenceCnt
,
4812 io_struct_inband_t input
,
4813 mach_msg_type_number_t inputCount
,
4814 io_struct_inband_t output
,
4815 mach_msg_type_number_t
* outputCount
)
4818 mach_msg_type_number_t scalar_outputCnt
= 0;
4819 mach_vm_size_t ool_output_size
= 0;
4820 io_async_ref64_t _reference
;
4822 if (referenceCnt
> ASYNC_REF64_COUNT
) {
4823 return kIOReturnBadArgument
;
4825 for (i
= 0; i
< referenceCnt
; i
++) {
4826 _reference
[i
] = REF64(reference
[i
]);
4828 bzero(&_reference
[referenceCnt
], (ASYNC_REF64_COUNT
- referenceCnt
) * sizeof(_reference
[0]));
4830 return is_io_connect_async_method(connect
,
4831 wake_port
, _reference
, referenceCnt
,
4836 output
, outputCount
,
4837 NULL
, &scalar_outputCnt
,
4838 0, &ool_output_size
);
4843 shim_io_async_method_scalarI_scalarO(
4844 IOExternalAsyncMethod
* method
,
4846 mach_port_t asyncWakePort
,
4847 io_user_reference_t
* asyncReference
,
4848 uint32_t asyncReferenceCount
,
4849 const io_user_scalar_t
* input
,
4850 mach_msg_type_number_t inputCount
,
4851 io_user_scalar_t
* output
,
4852 mach_msg_type_number_t
* outputCount
)
4856 io_scalar_inband_t _output
;
4858 io_async_ref_t reference
;
4860 bzero(&_output
[0], sizeof(_output
));
4861 for (i
= 0; i
< asyncReferenceCount
; i
++) {
4862 reference
[i
] = REF32(asyncReference
[i
]);
4865 err
= kIOReturnBadArgument
;
4868 if (inputCount
!= method
->count0
) {
4869 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
);
4870 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
4873 if (*outputCount
!= method
->count1
) {
4874 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)*outputCount
, (uint64_t)method
->count1
);
4875 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)*outputCount
, uint64_t, (uint64_t)method
->count1
);
4879 func
= method
->func
;
4881 switch (inputCount
) {
4883 err
= (object
->*func
)( reference
,
4884 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4885 ARG32(input
[3]), ARG32(input
[4]), ARG32(input
[5]));
4888 err
= (object
->*func
)( reference
,
4889 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4890 ARG32(input
[3]), ARG32(input
[4]),
4894 err
= (object
->*func
)( reference
,
4895 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4897 &_output
[0], &_output
[1] );
4900 err
= (object
->*func
)( reference
,
4901 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4902 &_output
[0], &_output
[1], &_output
[2] );
4905 err
= (object
->*func
)( reference
,
4906 ARG32(input
[0]), ARG32(input
[1]),
4907 &_output
[0], &_output
[1], &_output
[2],
4911 err
= (object
->*func
)( reference
,
4913 &_output
[0], &_output
[1], &_output
[2],
4914 &_output
[3], &_output
[4] );
4917 err
= (object
->*func
)( reference
,
4918 &_output
[0], &_output
[1], &_output
[2],
4919 &_output
[3], &_output
[4], &_output
[5] );
4923 IOLog("%s: Bad method table\n", object
->getName());
4927 for (i
= 0; i
< *outputCount
; i
++) {
4928 output
[i
] = SCALAR32(_output
[i
]);
4935 /* Routine io_connect_method_scalarI_structureO */
4937 is_io_connect_method_scalarI_structureO(
4938 io_object_t connect
,
4940 io_scalar_inband_t input
,
4941 mach_msg_type_number_t inputCount
,
4942 io_struct_inband_t output
,
4943 mach_msg_type_number_t
* outputCount
)
4946 io_scalar_inband64_t _input
;
4948 mach_msg_type_number_t scalar_outputCnt
= 0;
4949 mach_vm_size_t ool_output_size
= 0;
4951 for (i
= 0; i
< inputCount
; i
++) {
4952 _input
[i
] = SCALAR64(input
[i
]);
4955 return is_io_connect_method(connect
, index
,
4959 output
, outputCount
,
4960 NULL
, &scalar_outputCnt
,
4961 0, &ool_output_size
);
4965 shim_io_connect_method_scalarI_structureO(
4967 IOExternalMethod
* method
,
4969 const io_user_scalar_t
* input
,
4970 mach_msg_type_number_t inputCount
,
4971 io_struct_inband_t output
,
4972 IOByteCount
* outputCount
)
4977 err
= kIOReturnBadArgument
;
4980 if (inputCount
!= method
->count0
) {
4981 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
);
4982 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
4985 if ((kIOUCVariableStructureSize
!= method
->count1
)
4986 && (*outputCount
!= method
->count1
)) {
4987 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)*outputCount
, (uint64_t)method
->count1
, (uint64_t)kIOUCVariableStructureSize
);
4988 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)*outputCount
, uint64_t, (uint64_t)method
->count1
);
4992 func
= method
->func
;
4994 switch (inputCount
) {
4996 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
4997 ARG32(input
[3]), ARG32(input
[4]),
5001 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5003 output
, (void *)outputCount
);
5006 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5007 output
, (void *)outputCount
, NULL
);
5010 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]),
5011 output
, (void *)outputCount
, NULL
, NULL
);
5014 err
= (object
->*func
)( ARG32(input
[0]),
5015 output
, (void *)outputCount
, NULL
, NULL
, NULL
);
5018 err
= (object
->*func
)( output
, (void *)outputCount
, NULL
, NULL
, NULL
, NULL
);
5022 IOLog("%s: Bad method table\n", object
->getName());
5031 shim_io_async_method_scalarI_structureO(
5032 IOExternalAsyncMethod
* method
,
5034 mach_port_t asyncWakePort
,
5035 io_user_reference_t
* asyncReference
,
5036 uint32_t asyncReferenceCount
,
5037 const io_user_scalar_t
* input
,
5038 mach_msg_type_number_t inputCount
,
5039 io_struct_inband_t output
,
5040 mach_msg_type_number_t
* outputCount
)
5045 io_async_ref_t reference
;
5047 for (i
= 0; i
< asyncReferenceCount
; i
++) {
5048 reference
[i
] = REF32(asyncReference
[i
]);
5051 err
= kIOReturnBadArgument
;
5053 if (inputCount
!= method
->count0
) {
5054 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
);
5055 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
5058 if ((kIOUCVariableStructureSize
!= method
->count1
)
5059 && (*outputCount
!= method
->count1
)) {
5060 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)*outputCount
, (uint64_t)method
->count1
, (uint64_t)kIOUCVariableStructureSize
);
5061 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)*outputCount
, uint64_t, (uint64_t)method
->count1
);
5065 func
= method
->func
;
5067 switch (inputCount
) {
5069 err
= (object
->*func
)( reference
,
5070 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5071 ARG32(input
[3]), ARG32(input
[4]),
5075 err
= (object
->*func
)( reference
,
5076 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5078 output
, (void *)outputCount
);
5081 err
= (object
->*func
)( reference
,
5082 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5083 output
, (void *)outputCount
, NULL
);
5086 err
= (object
->*func
)( reference
,
5087 ARG32(input
[0]), ARG32(input
[1]),
5088 output
, (void *)outputCount
, NULL
, NULL
);
5091 err
= (object
->*func
)( reference
,
5093 output
, (void *)outputCount
, NULL
, NULL
, NULL
);
5096 err
= (object
->*func
)( reference
,
5097 output
, (void *)outputCount
, NULL
, NULL
, NULL
, NULL
);
5101 IOLog("%s: Bad method table\n", object
->getName());
5108 /* Routine io_connect_method_scalarI_structureI */
5110 is_io_connect_method_scalarI_structureI(
5111 io_connect_t connect
,
5113 io_scalar_inband_t input
,
5114 mach_msg_type_number_t inputCount
,
5115 io_struct_inband_t inputStruct
,
5116 mach_msg_type_number_t inputStructCount
)
5119 io_scalar_inband64_t _input
;
5121 mach_msg_type_number_t scalar_outputCnt
= 0;
5122 mach_msg_type_number_t inband_outputCnt
= 0;
5123 mach_vm_size_t ool_output_size
= 0;
5125 for (i
= 0; i
< inputCount
; i
++) {
5126 _input
[i
] = SCALAR64(input
[i
]);
5129 return is_io_connect_method(connect
, index
,
5131 inputStruct
, inputStructCount
,
5133 NULL
, &inband_outputCnt
,
5134 NULL
, &scalar_outputCnt
,
5135 0, &ool_output_size
);
5139 shim_io_connect_method_scalarI_structureI(
5140 IOExternalMethod
* method
,
5142 const io_user_scalar_t
* input
,
5143 mach_msg_type_number_t inputCount
,
5144 io_struct_inband_t inputStruct
,
5145 mach_msg_type_number_t inputStructCount
)
5148 IOReturn err
= kIOReturnBadArgument
;
5151 if (inputCount
!= method
->count0
) {
5152 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
);
5153 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
5156 if ((kIOUCVariableStructureSize
!= method
->count1
)
5157 && (inputStructCount
!= method
->count1
)) {
5158 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputStructCount
, (uint64_t)method
->count1
, (uint64_t)kIOUCVariableStructureSize
);
5159 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputStructCount
, uint64_t, (uint64_t)method
->count1
);
5163 func
= method
->func
;
5165 switch (inputCount
) {
5167 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5168 ARG32(input
[3]), ARG32(input
[4]),
5172 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), (void *) input
[2],
5174 inputStruct
, (void *)(uintptr_t)inputStructCount
);
5177 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5178 inputStruct
, (void *)(uintptr_t)inputStructCount
,
5182 err
= (object
->*func
)( ARG32(input
[0]), ARG32(input
[1]),
5183 inputStruct
, (void *)(uintptr_t)inputStructCount
,
5187 err
= (object
->*func
)( ARG32(input
[0]),
5188 inputStruct
, (void *)(uintptr_t)inputStructCount
,
5192 err
= (object
->*func
)( inputStruct
, (void *)(uintptr_t)inputStructCount
,
5193 NULL
, NULL
, NULL
, NULL
);
5197 IOLog("%s: Bad method table\n", object
->getName());
5205 shim_io_async_method_scalarI_structureI(
5206 IOExternalAsyncMethod
* method
,
5208 mach_port_t asyncWakePort
,
5209 io_user_reference_t
* asyncReference
,
5210 uint32_t asyncReferenceCount
,
5211 const io_user_scalar_t
* input
,
5212 mach_msg_type_number_t inputCount
,
5213 io_struct_inband_t inputStruct
,
5214 mach_msg_type_number_t inputStructCount
)
5218 IOReturn err
= kIOReturnBadArgument
;
5219 io_async_ref_t reference
;
5221 for (i
= 0; i
< asyncReferenceCount
; i
++) {
5222 reference
[i
] = REF32(asyncReference
[i
]);
5226 if (inputCount
!= method
->count0
) {
5227 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
);
5228 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
5231 if ((kIOUCVariableStructureSize
!= method
->count1
)
5232 && (inputStructCount
!= method
->count1
)) {
5233 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputStructCount
, (uint64_t)method
->count1
, (uint64_t)kIOUCVariableStructureSize
);
5234 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputStructCount
, uint64_t, (uint64_t)method
->count1
);
5238 func
= method
->func
;
5240 switch (inputCount
) {
5242 err
= (object
->*func
)( reference
,
5243 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5244 ARG32(input
[3]), ARG32(input
[4]),
5248 err
= (object
->*func
)( reference
,
5249 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5251 inputStruct
, (void *)(uintptr_t)inputStructCount
);
5254 err
= (object
->*func
)( reference
,
5255 ARG32(input
[0]), ARG32(input
[1]), ARG32(input
[2]),
5256 inputStruct
, (void *)(uintptr_t)inputStructCount
,
5260 err
= (object
->*func
)( reference
,
5261 ARG32(input
[0]), ARG32(input
[1]),
5262 inputStruct
, (void *)(uintptr_t)inputStructCount
,
5266 err
= (object
->*func
)( reference
,
5268 inputStruct
, (void *)(uintptr_t)inputStructCount
,
5272 err
= (object
->*func
)( reference
,
5273 inputStruct
, (void *)(uintptr_t)inputStructCount
,
5274 NULL
, NULL
, NULL
, NULL
);
5278 IOLog("%s: Bad method table\n", object
->getName());
5285 /* Routine io_connect_method_structureI_structureO */
5287 is_io_connect_method_structureI_structureO(
5288 io_object_t connect
,
5290 io_struct_inband_t input
,
5291 mach_msg_type_number_t inputCount
,
5292 io_struct_inband_t output
,
5293 mach_msg_type_number_t
* outputCount
)
5295 mach_msg_type_number_t scalar_outputCnt
= 0;
5296 mach_vm_size_t ool_output_size
= 0;
5298 return is_io_connect_method(connect
, index
,
5302 output
, outputCount
,
5303 NULL
, &scalar_outputCnt
,
5304 0, &ool_output_size
);
5308 shim_io_connect_method_structureI_structureO(
5309 IOExternalMethod
* method
,
5311 io_struct_inband_t input
,
5312 mach_msg_type_number_t inputCount
,
5313 io_struct_inband_t output
,
5314 IOByteCount
* outputCount
)
5317 IOReturn err
= kIOReturnBadArgument
;
5320 if ((kIOUCVariableStructureSize
!= method
->count0
)
5321 && (inputCount
!= method
->count0
)) {
5322 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
, (uint64_t)kIOUCVariableStructureSize
);
5323 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
5326 if ((kIOUCVariableStructureSize
!= method
->count1
)
5327 && (*outputCount
!= method
->count1
)) {
5328 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)*outputCount
, (uint64_t)method
->count1
, (uint64_t)kIOUCVariableStructureSize
);
5329 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)*outputCount
, uint64_t, (uint64_t)method
->count1
);
5333 func
= method
->func
;
5335 if (method
->count1
) {
5336 if (method
->count0
) {
5337 err
= (object
->*func
)( input
, output
,
5338 (void *)(uintptr_t)inputCount
, outputCount
, NULL
, NULL
);
5340 err
= (object
->*func
)( output
, outputCount
, NULL
, NULL
, NULL
, NULL
);
5343 err
= (object
->*func
)( input
, (void *)(uintptr_t)inputCount
, NULL
, NULL
, NULL
, NULL
);
5352 shim_io_async_method_structureI_structureO(
5353 IOExternalAsyncMethod
* method
,
5355 mach_port_t asyncWakePort
,
5356 io_user_reference_t
* asyncReference
,
5357 uint32_t asyncReferenceCount
,
5358 io_struct_inband_t input
,
5359 mach_msg_type_number_t inputCount
,
5360 io_struct_inband_t output
,
5361 mach_msg_type_number_t
* outputCount
)
5366 io_async_ref_t reference
;
5368 for (i
= 0; i
< asyncReferenceCount
; i
++) {
5369 reference
[i
] = REF32(asyncReference
[i
]);
5372 err
= kIOReturnBadArgument
;
5374 if ((kIOUCVariableStructureSize
!= method
->count0
)
5375 && (inputCount
!= method
->count0
)) {
5376 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)inputCount
, (uint64_t)method
->count0
, (uint64_t)kIOUCVariableStructureSize
);
5377 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)inputCount
, uint64_t, (uint64_t)method
->count0
);
5380 if ((kIOUCVariableStructureSize
!= method
->count1
)
5381 && (*outputCount
!= method
->count1
)) {
5382 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__
, __LINE__
, object
->getName(), (uint64_t)*outputCount
, (uint64_t)method
->count1
, (uint64_t)kIOUCVariableStructureSize
);
5383 DTRACE_IO2(iokit_count_mismatch
, uint64_t, (uint64_t)*outputCount
, uint64_t, (uint64_t)method
->count1
);
5387 func
= method
->func
;
5389 if (method
->count1
) {
5390 if (method
->count0
) {
5391 err
= (object
->*func
)( reference
,
5393 (void *)(uintptr_t)inputCount
, outputCount
, NULL
, NULL
);
5395 err
= (object
->*func
)( reference
,
5396 output
, outputCount
, NULL
, NULL
, NULL
, NULL
);
5399 err
= (object
->*func
)( reference
,
5400 input
, (void *)(uintptr_t)inputCount
, NULL
, NULL
, NULL
, NULL
);
5408 bool gIOKextdClearedBusy
= false;
5411 /* Routine io_catalog_send_data */
5413 is_io_catalog_send_data(
5414 mach_port_t master_port
,
5416 io_buf_ptr_t inData
,
5417 mach_msg_type_number_t inDataCount
,
5418 kern_return_t
* result
)
5421 return kIOReturnNotPrivileged
;
5422 #else /* NO_KEXTD */
5423 OSObject
* obj
= NULL
;
5425 kern_return_t kr
= kIOReturnError
;
5427 //printf("io_catalog_send_data called. flag: %d\n", flag);
5429 if (master_port
!= master_device_port
) {
5430 return kIOReturnNotPrivileged
;
5433 if ((flag
!= kIOCatalogRemoveKernelLinker__Removed
&&
5434 flag
!= kIOCatalogKextdActive
&&
5435 flag
!= kIOCatalogKextdFinishedLaunching
) &&
5436 (!inData
|| !inDataCount
)) {
5437 return kIOReturnBadArgument
;
5440 if (!IOTaskHasEntitlement(current_task(), kOSKextManagementEntitlement
)) {
5441 OSString
* taskName
= IOCopyLogNameForPID(proc_selfpid());
5442 IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName
? taskName
->getCStringNoCopy() : "");
5443 OSSafeReleaseNULL(taskName
);
5444 // For now, fake success to not break applications relying on this function succeeding.
5445 // See <rdar://problem/32554970> for more details.
5446 return kIOReturnSuccess
;
5450 vm_map_offset_t map_data
;
5452 if (inDataCount
> sizeof(io_struct_inband_t
) * 1024) {
5453 return kIOReturnMessageTooLarge
;
5456 kr
= vm_map_copyout( kernel_map
, &map_data
, (vm_map_copy_t
)inData
);
5457 data
= CAST_DOWN(vm_offset_t
, map_data
);
5459 if (kr
!= KERN_SUCCESS
) {
5463 // must return success after vm_map_copyout() succeeds
5466 obj
= (OSObject
*)OSUnserializeXML((const char *)data
, inDataCount
);
5467 vm_deallocate( kernel_map
, data
, inDataCount
);
5469 *result
= kIOReturnNoMemory
;
5470 return KERN_SUCCESS
;
5476 case kIOCatalogResetDrivers
:
5477 case kIOCatalogResetDriversNoMatch
: {
5480 array
= OSDynamicCast(OSArray
, obj
);
5482 if (!gIOCatalogue
->resetAndAddDrivers(array
,
5483 flag
== kIOCatalogResetDrivers
)) {
5484 kr
= kIOReturnError
;
5487 kr
= kIOReturnBadArgument
;
5492 case kIOCatalogAddDrivers
:
5493 case kIOCatalogAddDriversNoMatch
: {
5496 array
= OSDynamicCast(OSArray
, obj
);
5498 if (!gIOCatalogue
->addDrivers( array
,
5499 flag
== kIOCatalogAddDrivers
)) {
5500 kr
= kIOReturnError
;
5503 kr
= kIOReturnBadArgument
;
5508 case kIOCatalogRemoveDrivers
:
5509 case kIOCatalogRemoveDriversNoMatch
: {
5510 OSDictionary
* dict
;
5512 dict
= OSDynamicCast(OSDictionary
, obj
);
5514 if (!gIOCatalogue
->removeDrivers( dict
,
5515 flag
== kIOCatalogRemoveDrivers
)) {
5516 kr
= kIOReturnError
;
5519 kr
= kIOReturnBadArgument
;
5524 case kIOCatalogStartMatching__Removed
:
5525 case kIOCatalogRemoveKernelLinker__Removed
:
5526 kr
= KERN_NOT_SUPPORTED
;
5529 case kIOCatalogKextdActive
:
5531 IOServiceTrace(IOSERVICE_KEXTD_ALIVE
, 0, 0, 0, 0);
5532 OSKext::setKextdActive();
5534 /* Dump all nonloaded startup extensions; kextd will now send them
5537 OSKext::flushNonloadedKexts( /* flushPrelinkedKexts */ false);
5539 kr
= kIOReturnSuccess
;
5542 case kIOCatalogKextdFinishedLaunching
: {
5544 if (!gIOKextdClearedBusy
) {
5545 IOService::kextdLaunched();
5546 gIOKextdClearedBusy
= true;
5549 kr
= kIOReturnSuccess
;
5554 kr
= kIOReturnBadArgument
;
5563 return KERN_SUCCESS
;
5564 #endif /* NO_KEXTD */
5567 /* Routine io_catalog_terminate */
5569 is_io_catalog_terminate(
5570 mach_port_t master_port
,
5576 if (master_port
!= master_device_port
) {
5577 return kIOReturnNotPrivileged
;
5580 kr
= IOUserClient::clientHasPrivilege((void *) current_task(),
5581 kIOClientPrivilegeAdministrator
);
5582 if (kIOReturnSuccess
!= kr
) {
5587 #if !defined(SECURE_KERNEL)
5588 case kIOCatalogServiceTerminate
:
5590 IOService
* service
;
5592 iter
= IORegistryIterator::iterateOver(gIOServicePlane
,
5593 kIORegistryIterateRecursively
);
5595 return kIOReturnNoMemory
;
5600 while ((service
= (IOService
*)iter
->getNextObject())) {
5601 if (service
->metaCast(name
)) {
5602 if (!service
->terminate( kIOServiceRequired
5603 | kIOServiceSynchronous
)) {
5604 kr
= kIOReturnUnsupported
;
5609 } while (!service
&& !iter
->isValid());
5613 case kIOCatalogModuleUnload
:
5614 case kIOCatalogModuleTerminate
:
5615 kr
= gIOCatalogue
->terminateDriversForModule(name
,
5616 flag
== kIOCatalogModuleUnload
);
5621 kr
= kIOReturnBadArgument
;
5628 /* Routine io_catalog_get_data */
5630 is_io_catalog_get_data(
5631 mach_port_t master_port
,
5633 io_buf_ptr_t
*outData
,
5634 mach_msg_type_number_t
*outDataCount
)
5636 kern_return_t kr
= kIOReturnSuccess
;
5639 if (master_port
!= master_device_port
) {
5640 return kIOReturnNotPrivileged
;
5643 //printf("io_catalog_get_data called. flag: %d\n", flag);
5645 s
= OSSerialize::withCapacity(4096);
5647 return kIOReturnNoMemory
;
5650 kr
= gIOCatalogue
->serializeData(flag
, s
);
5652 if (kr
== kIOReturnSuccess
) {
5657 size
= s
->getLength();
5658 kr
= vm_allocate_kernel(kernel_map
, &data
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IOKIT
);
5659 if (kr
== kIOReturnSuccess
) {
5660 bcopy(s
->text(), (void *)data
, size
);
5661 kr
= vm_map_copyin(kernel_map
, (vm_map_address_t
)data
,
5662 (vm_map_size_t
)size
, true, ©
);
5663 *outData
= (char *)copy
;
5664 *outDataCount
= size
;
5673 /* Routine io_catalog_get_gen_count */
5675 is_io_catalog_get_gen_count(
5676 mach_port_t master_port
,
5679 if (master_port
!= master_device_port
) {
5680 return kIOReturnNotPrivileged
;
5683 //printf("io_catalog_get_gen_count called.\n");
5686 return kIOReturnBadArgument
;
5689 *genCount
= gIOCatalogue
->getGenerationCount();
5691 return kIOReturnSuccess
;
5694 /* Routine io_catalog_module_loaded.
5695 * Is invoked from IOKitLib's IOCatalogueModuleLoaded(). Doesn't seem to be used.
5698 is_io_catalog_module_loaded(
5699 mach_port_t master_port
,
5702 if (master_port
!= master_device_port
) {
5703 return kIOReturnNotPrivileged
;
5706 //printf("io_catalog_module_loaded called. name %s\n", name);
5709 return kIOReturnBadArgument
;
5712 gIOCatalogue
->moduleHasLoaded(name
);
5714 return kIOReturnSuccess
;
5718 is_io_catalog_reset(
5719 mach_port_t master_port
,
5722 if (master_port
!= master_device_port
) {
5723 return kIOReturnNotPrivileged
;
5727 case kIOCatalogResetDefault
:
5728 gIOCatalogue
->reset();
5732 return kIOReturnBadArgument
;
5735 return kIOReturnSuccess
;
5739 iokit_user_client_trap(struct iokit_user_client_trap_args
*args
)
5741 kern_return_t result
= kIOReturnBadArgument
;
5742 IOUserClient
* userClient
;
5746 ref
= (uintptr_t) args
->userClientRef
;
5747 if ((1ULL << 32) & ref
) {
5748 object
= iokit_lookup_uext_ref_current_task((mach_port_name_t
) ref
);
5750 result
= IOUserServerUEXTTrap(object
, args
->p1
, args
->p2
, args
->p3
, args
->p4
, args
->p5
, args
->p6
);
5752 OSSafeReleaseNULL(object
);
5753 } else if ((userClient
= OSDynamicCast(IOUserClient
, iokit_lookup_connect_ref_current_task((mach_port_name_t
) ref
)))) {
5754 IOExternalTrap
*trap
;
5755 IOService
*target
= NULL
;
5757 trap
= userClient
->getTargetAndTrapForIndex(&target
, args
->index
);
5759 if (trap
&& target
) {
5765 result
= (target
->*func
)(args
->p1
, args
->p2
, args
->p3
, args
->p4
, args
->p5
, args
->p6
);
5769 iokit_remove_connect_reference(userClient
);
5775 /* Routine io_device_tree_entry_exists_with_name */
5777 is_io_device_tree_entry_exists_with_name(
5778 mach_port_t master_port
,
5782 OSCollectionIterator
*iter
;
5784 if (master_port
!= master_device_port
) {
5785 return kIOReturnNotPrivileged
;
5788 iter
= IODTFindMatchingEntries(IORegistryEntry::getRegistryRoot(), kIODTRecursive
, name
);
5789 *exists
= iter
&& iter
->getNextObject();
5790 OSSafeReleaseNULL(iter
);
5792 return kIOReturnSuccess
;
5797 IOUserClient::externalMethod( uint32_t selector
, IOExternalMethodArguments
* args
,
5798 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
5802 IOByteCount structureOutputSize
;
5806 count
= dispatch
->checkScalarInputCount
;
5807 if ((kIOUCVariableStructureSize
!= count
) && (count
!= args
->scalarInputCount
)) {
5808 return kIOReturnBadArgument
;
5811 count
= dispatch
->checkStructureInputSize
;
5812 if ((kIOUCVariableStructureSize
!= count
)
5813 && (count
!= ((args
->structureInputDescriptor
)
5814 ? args
->structureInputDescriptor
->getLength() : args
->structureInputSize
))) {
5815 return kIOReturnBadArgument
;
5818 count
= dispatch
->checkScalarOutputCount
;
5819 if ((kIOUCVariableStructureSize
!= count
) && (count
!= args
->scalarOutputCount
)) {
5820 return kIOReturnBadArgument
;
5823 count
= dispatch
->checkStructureOutputSize
;
5824 if ((kIOUCVariableStructureSize
!= count
)
5825 && (count
!= ((args
->structureOutputDescriptor
)
5826 ? args
->structureOutputDescriptor
->getLength() : args
->structureOutputSize
))) {
5827 return kIOReturnBadArgument
;
5830 if (dispatch
->function
) {
5831 err
= (*dispatch
->function
)(target
, reference
, args
);
5833 err
= kIOReturnNoCompletion
; /* implementator can dispatch */
5839 // pre-Leopard API's don't do ool structs
5840 if (args
->structureInputDescriptor
|| args
->structureOutputDescriptor
) {
5841 err
= kIOReturnIPCError
;
5845 structureOutputSize
= args
->structureOutputSize
;
5847 if (args
->asyncWakePort
) {
5848 IOExternalAsyncMethod
* method
;
5850 if (!(method
= getAsyncTargetAndMethodForIndex(&object
, selector
)) || !object
) {
5851 return kIOReturnUnsupported
;
5854 if (kIOUCForegroundOnly
& method
->flags
) {
5855 if (task_is_gpu_denied(current_task())) {
5856 return kIOReturnNotPermitted
;
5860 switch (method
->flags
& kIOUCTypeMask
) {
5861 case kIOUCScalarIStructI
:
5862 err
= shim_io_async_method_scalarI_structureI( method
, object
,
5863 args
->asyncWakePort
, args
->asyncReference
, args
->asyncReferenceCount
,
5864 args
->scalarInput
, args
->scalarInputCount
,
5865 (char *)args
->structureInput
, args
->structureInputSize
);
5868 case kIOUCScalarIScalarO
:
5869 err
= shim_io_async_method_scalarI_scalarO( method
, object
,
5870 args
->asyncWakePort
, args
->asyncReference
, args
->asyncReferenceCount
,
5871 args
->scalarInput
, args
->scalarInputCount
,
5872 args
->scalarOutput
, &args
->scalarOutputCount
);
5875 case kIOUCScalarIStructO
:
5876 err
= shim_io_async_method_scalarI_structureO( method
, object
,
5877 args
->asyncWakePort
, args
->asyncReference
, args
->asyncReferenceCount
,
5878 args
->scalarInput
, args
->scalarInputCount
,
5879 (char *) args
->structureOutput
, &args
->structureOutputSize
);
5883 case kIOUCStructIStructO
:
5884 err
= shim_io_async_method_structureI_structureO( method
, object
,
5885 args
->asyncWakePort
, args
->asyncReference
, args
->asyncReferenceCount
,
5886 (char *)args
->structureInput
, args
->structureInputSize
,
5887 (char *) args
->structureOutput
, &args
->structureOutputSize
);
5891 err
= kIOReturnBadArgument
;
5895 IOExternalMethod
* method
;
5897 if (!(method
= getTargetAndMethodForIndex(&object
, selector
)) || !object
) {
5898 return kIOReturnUnsupported
;
5901 if (kIOUCForegroundOnly
& method
->flags
) {
5902 if (task_is_gpu_denied(current_task())) {
5903 return kIOReturnNotPermitted
;
5907 switch (method
->flags
& kIOUCTypeMask
) {
5908 case kIOUCScalarIStructI
:
5909 err
= shim_io_connect_method_scalarI_structureI( method
, object
,
5910 args
->scalarInput
, args
->scalarInputCount
,
5911 (char *) args
->structureInput
, args
->structureInputSize
);
5914 case kIOUCScalarIScalarO
:
5915 err
= shim_io_connect_method_scalarI_scalarO( method
, object
,
5916 args
->scalarInput
, args
->scalarInputCount
,
5917 args
->scalarOutput
, &args
->scalarOutputCount
);
5920 case kIOUCScalarIStructO
:
5921 err
= shim_io_connect_method_scalarI_structureO( method
, object
,
5922 args
->scalarInput
, args
->scalarInputCount
,
5923 (char *) args
->structureOutput
, &structureOutputSize
);
5927 case kIOUCStructIStructO
:
5928 err
= shim_io_connect_method_structureI_structureO( method
, object
,
5929 (char *) args
->structureInput
, args
->structureInputSize
,
5930 (char *) args
->structureOutput
, &structureOutputSize
);
5934 err
= kIOReturnBadArgument
;
5939 args
->structureOutputSize
= structureOutputSize
;
5945 OSMetaClassDefineReservedUnused(IOUserClient
, 0);
5946 OSMetaClassDefineReservedUnused(IOUserClient
, 1);
5948 OSMetaClassDefineReservedUsed(IOUserClient
, 0);
5949 OSMetaClassDefineReservedUsed(IOUserClient
, 1);
5951 OSMetaClassDefineReservedUnused(IOUserClient
, 2);
5952 OSMetaClassDefineReservedUnused(IOUserClient
, 3);
5953 OSMetaClassDefineReservedUnused(IOUserClient
, 4);
5954 OSMetaClassDefineReservedUnused(IOUserClient
, 5);
5955 OSMetaClassDefineReservedUnused(IOUserClient
, 6);
5956 OSMetaClassDefineReservedUnused(IOUserClient
, 7);
5957 OSMetaClassDefineReservedUnused(IOUserClient
, 8);
5958 OSMetaClassDefineReservedUnused(IOUserClient
, 9);
5959 OSMetaClassDefineReservedUnused(IOUserClient
, 10);
5960 OSMetaClassDefineReservedUnused(IOUserClient
, 11);
5961 OSMetaClassDefineReservedUnused(IOUserClient
, 12);
5962 OSMetaClassDefineReservedUnused(IOUserClient
, 13);
5963 OSMetaClassDefineReservedUnused(IOUserClient
, 14);
5964 OSMetaClassDefineReservedUnused(IOUserClient
, 15);