2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/IORPC.h>
30 #include <IOKit/IOKitServer.h>
31 #include <IOKit/IOKitKeysPrivate.h>
32 #include <IOKit/IOUserClient.h>
33 #include <IOKit/IOService.h>
34 #include <IOKit/IORegistryEntry.h>
35 #include <IOKit/IOCatalogue.h>
36 #include <IOKit/IOMemoryDescriptor.h>
37 #include <IOKit/IOBufferMemoryDescriptor.h>
38 #include <IOKit/IOSubMemoryDescriptor.h>
39 #include <IOKit/IOMultiMemoryDescriptor.h>
40 #include <IOKit/IOMapper.h>
41 #include <IOKit/IOLib.h>
42 #include <IOKit/IOBSD.h>
43 #include <IOKit/system.h>
44 #include <IOKit/IOUserServer.h>
45 #include <IOKit/IOInterruptEventSource.h>
46 #include <IOKit/IOTimerEventSource.h>
47 #include <IOKit/pwr_mgt/RootDomain.h>
48 #include <libkern/c++/OSKext.h>
49 #include <libkern/c++/OSSharedPtr.h>
50 #include <libkern/OSDebug.h>
51 #include <libkern/Block.h>
53 #include "IOKitKernelInternal.h"
55 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
57 #include <DriverKit/IODispatchQueue.h>
58 #include <DriverKit/OSObject.h>
59 #include <DriverKit/OSAction.h>
60 #include <DriverKit/IODispatchSource.h>
61 #include <DriverKit/IOInterruptDispatchSource.h>
62 #include <DriverKit/IOService.h>
63 #include <DriverKit/IOMemoryDescriptor.h>
64 #include <DriverKit/IOBufferMemoryDescriptor.h>
65 #include <DriverKit/IOMemoryMap.h>
66 #include <DriverKit/IODataQueueDispatchSource.h>
67 #include <DriverKit/IOServiceNotificationDispatchSource.h>
68 #include <DriverKit/IOUserServer.h>
70 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
72 #include <System/IODataQueueDispatchSourceShared.h>
74 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
76 SECURITY_READ_ONLY_LATE(SInt64
) gIODKDebug
= kIODKEnable
;
78 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
82 class OSUserMetaClass
: public OSObject
84 OSDeclareDefaultStructors(OSUserMetaClass
);
86 const OSSymbol
* name
;
87 const OSMetaClass
* meta
;
88 OSUserMetaClass
* superMeta
;
92 OSClassDescription
* description
;
93 IOPStrings
* queueNames
;
97 virtual void free() override
;
98 virtual kern_return_t
Dispatch(const IORPC rpc
) APPLE_KEXT_OVERRIDE
;
100 OSDefineMetaClassAndStructors(OSUserMetaClass
, OSObject
);
102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
104 class IOUserService
: public IOService
106 friend class IOService
;
108 OSDeclareDefaultStructors(IOUserService
)
111 start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
114 OSDefineMetaClassAndStructors(IOUserService
, IOService
)
116 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
118 class IOUserUserClient
: public IOUserClient
120 OSDeclareDefaultStructors(IOUserUserClient
);
124 IOReturn
setTask(task_t task
);
125 virtual void stop(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
126 virtual IOReturn
clientClose(void) APPLE_KEXT_OVERRIDE
;
127 virtual IOReturn
setProperties(OSObject
* properties
) APPLE_KEXT_OVERRIDE
;
128 virtual IOReturn
externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
129 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
) APPLE_KEXT_OVERRIDE
;
130 virtual IOReturn
clientMemoryForType(UInt32 type
,
131 IOOptionBits
* options
,
132 IOMemoryDescriptor
** memory
) APPLE_KEXT_OVERRIDE
;
135 OSDefineMetaClassAndStructors(IOUserServerCheckInToken
, OSObject
);
137 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
141 IOUserService::start(IOService
* provider
)
146 ret
= Start(provider
);
147 if (kIOReturnSuccess
!= ret
) {
154 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
158 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
160 struct IODispatchQueue_IVars
{
161 IOUserServer
* userServer
;
162 IODispatchQueue
* queue
;
166 mach_port_t serverPort
;
169 struct OSAction_IVars
{
171 uint64_t targetmsgid
;
173 OSActionAbortedHandler abortedHandler
;
174 size_t referenceSize
;
179 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
182 IOService::GetRegistryEntryID_Impl(
183 uint64_t * registryEntryID
)
185 IOReturn ret
= kIOReturnSuccess
;
187 *registryEntryID
= getRegistryEntryID();
193 IOService::SetName_Impl(
196 IOReturn ret
= kIOReturnSuccess
;
204 IOService::Start_Impl(
205 IOService
* provider
)
207 IOReturn ret
= kIOReturnSuccess
;
212 IOService::RegisterService_Impl()
214 IOReturn ret
= kIOReturnSuccess
;
222 IOService::CopyDispatchQueue_Impl(
224 IODispatchQueue
** queue
)
226 IODispatchQueue
* result
;
231 if (!reserved
->uvars
) {
232 return kIOReturnError
;
235 ret
= kIOReturnNotFound
;
237 if (!strcmp("Default", name
)) {
239 } else if (reserved
->uvars
->userMeta
240 && reserved
->uvars
->userMeta
->queueNames
) {
241 index
= reserved
->uvars
->userServer
->stringArrayIndex(reserved
->uvars
->userMeta
->queueNames
, name
);
247 if ((service
= getProvider())) {
248 ret
= service
->CopyDispatchQueue(name
, queue
);
251 result
= reserved
->uvars
->queueArray
[index
];
255 ret
= kIOReturnSuccess
;
263 IOService::SetDispatchQueue_Impl(
265 IODispatchQueue
* queue
)
267 IOReturn ret
= kIOReturnSuccess
;
270 if (!reserved
->uvars
) {
271 return kIOReturnError
;
274 if (kIODKLogSetup
& gIODKDebug
) {
275 DKLOG(DKS
"::SetDispatchQueue(%s)\n", DKN(this), name
);
277 queue
->ivars
->userServer
= reserved
->uvars
->userServer
;
279 if (!strcmp("Default", name
)) {
281 } else if (reserved
->uvars
->userMeta
282 && reserved
->uvars
->userMeta
->queueNames
) {
283 index
= reserved
->uvars
->userServer
->stringArrayIndex(reserved
->uvars
->userMeta
->queueNames
, name
);
289 ret
= kIOReturnBadArgument
;
291 reserved
->uvars
->queueArray
[index
] = queue
;
299 IOService::SetProperties_Impl(
300 OSDictionary
* properties
)
306 ret
= setProperties(properties
);
308 if (kIOReturnUnsupported
== ret
) {
309 dict
= OSDynamicCast(OSDictionary
, properties
);
310 us
= (typeof(us
))thread_iokit_tls_get(0);
311 if (dict
&& reserved
->uvars
&& (reserved
->uvars
->userServer
== us
)) {
312 ret
= runPropertyActionBlock(^IOReturn (void) {
313 OSDictionary
* userProps
;
316 userProps
= OSDynamicCast(OSDictionary
, getProperty(gIOUserServicePropertiesKey
));
318 userProps
= (typeof(userProps
))userProps
->copyCollection();
320 userProps
= OSDictionary::withCapacity(4);
323 ret
= kIOReturnNoMemory
;
325 bool ok
= userProps
->merge(dict
);
327 ok
= setProperty(gIOUserServicePropertiesKey
, userProps
);
329 OSSafeReleaseNULL(userProps
);
330 ret
= ok
? kIOReturnSuccess
: kIOReturnNotWritable
;
341 IOService::CopyProperties_Impl(
342 OSDictionary
** properties
)
344 IOReturn ret
= kIOReturnSuccess
;
345 *properties
= dictionaryWithProperties();
350 IOService::RequireMaxBusStall_Impl(
356 if (os_convert_overflow(u64ns
, &ns
)) {
357 return kIOReturnBadArgument
;
359 ret
= requireMaxBusStall(ns
);
361 return kIOReturnSuccess
;
364 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
367 IOMemoryDescriptor::_CopyState_Impl(
368 _IOMDPrivateState
* state
)
372 state
->length
= _length
;
373 state
->options
= _flags
;
375 ret
= kIOReturnSuccess
;
381 IOMemoryDescriptor::GetLength(uint64_t * returnLength
)
383 *returnLength
= getLength();
385 return kIOReturnSuccess
;
389 IOMemoryDescriptor::CreateMapping_Impl(
398 IOMemoryMap
* resultMap
;
399 IOOptionBits koptions
;
400 mach_vm_address_t atAddress
;
402 ret
= kIOReturnSuccess
;
406 if (kIOMemoryMapFixedAddress
& options
) {
411 koptions
|= kIOMapAnywhere
;
414 if (kIOMemoryMapReadOnly
& options
|| (kIODirectionOut
== getDirection())) {
415 if (!reserved
|| (current_task() != reserved
->creator
)) {
416 koptions
|= kIOMapReadOnly
;
420 switch (0xFF00 & options
) {
421 case kIOMemoryMapCacheModeDefault
:
422 koptions
|= kIOMapDefaultCache
;
424 case kIOMemoryMapCacheModeInhibit
:
425 koptions
|= kIOMapInhibitCache
;
427 case kIOMemoryMapCacheModeCopyback
:
428 koptions
|= kIOMapCopybackCache
;
430 case kIOMemoryMapCacheModeWriteThrough
:
431 koptions
|= kIOMapWriteThruCache
;
434 ret
= kIOReturnBadArgument
;
437 if (kIOReturnSuccess
== ret
) {
438 resultMap
= createMappingInTask(current_task(), atAddress
, koptions
, offset
, length
);
440 ret
= kIOReturnError
;
450 IOMemoryDescriptor::CreateSubMemoryDescriptor_Impl(
451 uint64_t memoryDescriptorCreateOptions
,
454 IOMemoryDescriptor
* ofDescriptor
,
455 IOMemoryDescriptor
** memory
)
458 IOMemoryDescriptor
* iomd
;
459 IOByteCount mdOffset
;
460 IOByteCount mdLength
;
464 return kIOReturnBadArgument
;
466 if (memoryDescriptorCreateOptions
& ~kIOMemoryDirectionOutIn
) {
467 return kIOReturnBadArgument
;
469 if (os_convert_overflow(offset
, &mdOffset
)) {
470 return kIOReturnBadArgument
;
472 if (os_convert_overflow(length
, &mdLength
)) {
473 return kIOReturnBadArgument
;
475 if (os_add_overflow(mdOffset
, mdLength
, &mdEnd
)) {
476 return kIOReturnBadArgument
;
478 if (mdEnd
> ofDescriptor
->getLength()) {
479 return kIOReturnBadArgument
;
482 iomd
= IOSubMemoryDescriptor::withSubRange(
483 ofDescriptor
, mdOffset
, mdLength
, (IOOptionBits
) memoryDescriptorCreateOptions
);
486 ret
= kIOReturnSuccess
;
489 ret
= kIOReturnNoMemory
;
496 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
499 IOMemoryDescriptor::CreateWithMemoryDescriptors_Impl(
500 uint64_t memoryDescriptorCreateOptions
,
501 uint32_t withDescriptorsCount
,
502 IOMemoryDescriptor
** const withDescriptors
,
503 IOMemoryDescriptor
** memory
)
506 IOMemoryDescriptor
* iomd
;
508 if (!withDescriptors
) {
509 return kIOReturnBadArgument
;
511 if (!withDescriptorsCount
) {
512 return kIOReturnBadArgument
;
514 if (memoryDescriptorCreateOptions
& ~kIOMemoryDirectionOutIn
) {
515 return kIOReturnBadArgument
;
518 for (unsigned int idx
= 0; idx
< withDescriptorsCount
; idx
++) {
519 if (NULL
== withDescriptors
[idx
]) {
520 return kIOReturnBadArgument
;
524 iomd
= IOMultiMemoryDescriptor::withDescriptors(withDescriptors
, withDescriptorsCount
,
525 (IODirection
) memoryDescriptorCreateOptions
, false);
528 ret
= kIOReturnSuccess
;
531 ret
= kIOReturnNoMemory
;
538 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
541 IOUserClient::CreateMemoryDescriptorFromClient_Impl(
542 uint64_t memoryDescriptorCreateOptions
,
543 uint32_t segmentsCount
,
544 const IOAddressSegment segments
[32],
545 IOMemoryDescriptor
** memory
)
548 IOMemoryDescriptor
* iomd
;
549 IOOptionBits mdOptions
;
550 IOUserUserClient
* me
;
551 IOAddressRange
* ranges
;
553 me
= OSDynamicCast(IOUserUserClient
, this);
555 return kIOReturnBadArgument
;
559 if (kIOMemoryDirectionOut
& memoryDescriptorCreateOptions
) {
560 mdOptions
|= kIODirectionOut
;
562 if (kIOMemoryDirectionIn
& memoryDescriptorCreateOptions
) {
563 mdOptions
|= kIODirectionIn
;
565 if (!(kIOMemoryDisableCopyOnWrite
& memoryDescriptorCreateOptions
)) {
566 mdOptions
|= kIOMemoryMapCopyOnWrite
;
569 static_assert(sizeof(IOAddressRange
) == sizeof(IOAddressSegment
));
570 ranges
= __DECONST(IOAddressRange
*, &segments
[0]);
572 iomd
= IOMemoryDescriptor::withAddressRanges(
573 ranges
, segmentsCount
,
574 mdOptions
, me
->fTask
);
577 ret
= kIOReturnSuccess
;
580 ret
= kIOReturnNoMemory
;
587 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
590 IOMemoryMap::_CopyState_Impl(
591 _IOMemoryMapPrivateState
* state
)
595 state
->offset
= fOffset
;
596 state
->length
= getLength();
597 state
->address
= getAddress();
598 state
->options
= getMapOptions();
600 ret
= kIOReturnSuccess
;
605 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
608 IOBufferMemoryDescriptor::Create_Impl(
612 IOBufferMemoryDescriptor
** memory
)
615 IOOptionBits bmdOptions
;
616 IOBufferMemoryDescriptor
* bmd
;
617 IOMemoryDescriptorReserved
* reserved
;
619 if (options
& ~((uint64_t) kIOMemoryDirectionOutIn
)) {
620 // no other options currently defined
621 return kIOReturnBadArgument
;
623 bmdOptions
= (options
& kIOMemoryDirectionOutIn
) | kIOMemoryKernelUserShared
;
624 bmd
= IOBufferMemoryDescriptor::inTaskWithOptions(
625 kernel_task
, bmdOptions
, capacity
, alignment
);
630 return kIOReturnNoMemory
;
633 reserved
= bmd
->getKernelReserved();
634 reserved
->creator
= current_task();
635 task_reference(reserved
->creator
);
637 ret
= kIOReturnSuccess
;
643 IOBufferMemoryDescriptor::SetLength_Impl(
647 return kIOReturnSuccess
;
651 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
654 IODMACommand::Create_Impl(
657 const IODMACommandSpecification
* specification
,
658 IODMACommand
** command
)
662 IODMACommand::SegmentOptions segmentOptions
;
665 if (options
& ~((uint64_t) kIODMACommandCreateNoOptions
)) {
666 // no other options currently defined
667 return kIOReturnBadArgument
;
670 if (os_convert_overflow(specification
->maxAddressBits
, &segmentOptions
.fNumAddressBits
)) {
671 return kIOReturnBadArgument
;
673 segmentOptions
.fMaxSegmentSize
= 0;
674 segmentOptions
.fMaxTransferSize
= 0;
675 segmentOptions
.fAlignment
= 1;
676 segmentOptions
.fAlignmentLength
= 1;
677 segmentOptions
.fAlignmentInternalSegments
= 1;
678 segmentOptions
.fStructSize
= sizeof(segmentOptions
);
680 mapper
= IOMapper::copyMapperForDevice(device
);
682 dma
= IODMACommand::withSpecification(
683 kIODMACommandOutputHost64
,
685 kIODMAMapOptionMapped
,
689 OSSafeReleaseNULL(mapper
);
693 return kIOReturnNoMemory
;
695 ret
= kIOReturnSuccess
;
701 IODMACommand::PrepareForDMA_Impl(
703 IOMemoryDescriptor
* memory
,
707 uint32_t * segmentsCount
,
708 IOAddressSegment
* segments
)
711 uint64_t lflags
, mdFlags
;
715 if (options
& ~((uint64_t) kIODMACommandPrepareForDMANoOptions
)) {
716 // no other options currently defined
717 return kIOReturnBadArgument
;
720 // uses IOMD direction
721 ret
= memory
->prepare();
722 if (kIOReturnSuccess
!= ret
) {
726 ret
= setMemoryDescriptor(memory
, false);
727 if (kIOReturnSuccess
!= ret
) {
732 ret
= prepare(offset
, length
);
733 if (kIOReturnSuccess
!= ret
) {
734 clearMemoryDescriptor(false);
739 static_assert(sizeof(IODMACommand::Segment64
) == sizeof(IOAddressSegment
));
741 numSegments
= *segmentsCount
;
743 ret
= genIOVMSegments(&genOffset
, segments
, &numSegments
);
745 if (kIOReturnSuccess
== ret
) {
746 mdFlags
= fMemory
->getFlags();
748 if (kIODirectionOut
& mdFlags
) {
749 lflags
|= kIOMemoryDirectionOut
;
751 if (kIODirectionIn
& mdFlags
) {
752 lflags
|= kIOMemoryDirectionIn
;
755 *segmentsCount
= numSegments
;
762 IODMACommand::CompleteDMA_Impl(
765 IOReturn ret
, completeRet
;
766 IOMemoryDescriptor
* md
;
768 if (options
& ~((uint64_t) kIODMACommandCompleteDMANoOptions
)) {
769 // no other options currently defined
770 return kIOReturnBadArgument
;
773 return kIOReturnNotReady
;
776 md
= __DECONST(IOMemoryDescriptor
*, fMemory
);
781 ret
= clearMemoryDescriptor(true);
784 completeRet
= md
->complete();
785 OSSafeReleaseNULL(md
);
786 if (kIOReturnSuccess
== ret
) {
795 IODMACommand::GetPreparation_Impl(
798 IOMemoryDescriptor
** memory
)
801 IOMemoryDescriptor
* md
;
804 return kIOReturnNotReady
;
807 ret
= getPreparedOffsetAndLength(offset
, length
);
808 if (kIOReturnSuccess
!= ret
) {
813 md
= __DECONST(IOMemoryDescriptor
*, fMemory
);
816 ret
= kIOReturnNotReady
;
825 IODMACommand::PerformOperation_Impl(
830 IOMemoryDescriptor
* data
)
835 IOByteCount mdOffset
, mdLength
, copied
;
837 if (options
& ~((uint64_t)
838 (kIODMACommandPerformOperationOptionRead
839 | kIODMACommandPerformOperationOptionWrite
840 | kIODMACommandPerformOperationOptionZero
))) {
841 // no other options currently defined
842 return kIOReturnBadArgument
;
846 return kIOReturnNotReady
;
848 if (os_convert_overflow(dataOffset
, &mdOffset
)) {
849 return kIOReturnBadArgument
;
851 if (os_convert_overflow(length
, &mdLength
)) {
852 return kIOReturnBadArgument
;
854 if (length
> fMemory
->getLength()) {
855 return kIOReturnBadArgument
;
857 buffer
= IONew(uint8_t, length
);
858 if (NULL
== buffer
) {
859 return kIOReturnNoMemory
;
863 case kIODMACommandPerformOperationOptionZero
:
864 bzero(buffer
, length
);
865 copiedDMA
= writeBytes(dmaOffset
, buffer
, length
);
866 if (copiedDMA
!= length
) {
867 ret
= kIOReturnUnderrun
;
870 ret
= kIOReturnSuccess
;
873 case kIODMACommandPerformOperationOptionRead
:
874 case kIODMACommandPerformOperationOptionWrite
:
877 ret
= kIOReturnBadArgument
;
880 if (length
> data
->getLength()) {
881 ret
= kIOReturnBadArgument
;
884 if (kIODMACommandPerformOperationOptionWrite
== options
) {
885 copied
= data
->readBytes(mdOffset
, buffer
, mdLength
);
886 if (copied
!= mdLength
) {
887 ret
= kIOReturnUnderrun
;
890 copiedDMA
= writeBytes(dmaOffset
, buffer
, length
);
891 if (copiedDMA
!= length
) {
892 ret
= kIOReturnUnderrun
;
895 } else { /* kIODMACommandPerformOperationOptionRead */
896 copiedDMA
= readBytes(dmaOffset
, buffer
, length
);
897 if (copiedDMA
!= length
) {
898 ret
= kIOReturnUnderrun
;
901 copied
= data
->writeBytes(mdOffset
, buffer
, mdLength
);
902 if (copied
!= mdLength
) {
903 ret
= kIOReturnUnderrun
;
907 ret
= kIOReturnSuccess
;
910 ret
= kIOReturnBadArgument
;
914 IODelete(buffer
, uint8_t, length
);
920 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
923 OSActionCreateWithTypeNameInternal(OSObject
* target
, uint64_t targetmsgid
, uint64_t msgid
, size_t referenceSize
, OSString
* typeName
, bool fromKernel
, OSAction
** action
)
925 OSAction
* inst
= NULL
;
927 const OSSymbol
*sym
= NULL
; // must release
928 OSObject
*obj
= NULL
; // must release
929 const OSMetaClass
*actionMetaClass
= NULL
; // do not release
932 if (os_add_overflow(referenceSize
, sizeof(OSAction_IVars
), &allocsize
)) {
933 ret
= kIOReturnBadArgument
;
937 if (fromKernel
&& typeName
) {
938 /* The action is being constructed in the kernel with a type name */
939 sym
= OSSymbol::withString(typeName
);
940 actionMetaClass
= OSMetaClass::getMetaClassWithName(sym
);
941 if (actionMetaClass
&& actionMetaClass
->getSuperClass() == OSTypeID(OSAction
)) {
942 obj
= actionMetaClass
->alloc();
944 ret
= kIOReturnNoMemory
;
947 inst
= OSDynamicCast(OSAction
, obj
);
948 obj
= NULL
; // prevent release
949 assert(inst
); // obj is a subclass of OSAction so the dynamic cast should always work
951 DKLOG("Attempted to create action object with type \"%s\" which does not inherit from OSAction\n", typeName
->getCStringNoCopy());
952 ret
= kIOReturnBadArgument
;
956 inst
= OSTypeAlloc(OSAction
);
958 ret
= kIOReturnNoMemory
;
963 inst
->ivars
= (typeof(inst
->ivars
))(uintptr_t) IONewZero(uint8_t, allocsize
);
965 ret
= kIOReturnNoMemory
;
969 inst
->ivars
->target
= target
;
970 inst
->ivars
->targetmsgid
= targetmsgid
;
971 inst
->ivars
->msgid
= msgid
;
972 inst
->ivars
->referenceSize
= referenceSize
;
976 inst
->ivars
->typeName
= typeName
;
979 inst
= NULL
; // prevent release
980 ret
= kIOReturnSuccess
;
983 OSSafeReleaseNULL(obj
);
984 OSSafeReleaseNULL(sym
);
985 OSSafeReleaseNULL(inst
);
991 OSAction::Create(OSAction_Create_Args
)
993 return OSAction::CreateWithTypeName(target
, targetmsgid
, msgid
, referenceSize
, NULL
, action
);
997 OSAction::CreateWithTypeName(OSAction_CreateWithTypeName_Args
)
999 return OSActionCreateWithTypeNameInternal(target
, targetmsgid
, msgid
, referenceSize
, typeName
, true, action
);
1003 OSAction::Create_Impl(
1005 uint64_t targetmsgid
,
1007 size_t referenceSize
,
1010 return OSAction::CreateWithTypeName_Impl(target
, targetmsgid
, msgid
, referenceSize
, NULL
, action
);
1014 OSAction::CreateWithTypeName_Impl(
1016 uint64_t targetmsgid
,
1018 size_t referenceSize
,
1019 OSString
* typeName
,
1022 return OSActionCreateWithTypeNameInternal(target
, targetmsgid
, msgid
, referenceSize
, typeName
, false, action
);
1029 if (ivars
->abortedHandler
) {
1030 Block_release(ivars
->abortedHandler
);
1031 ivars
->abortedHandler
= NULL
;
1033 OSSafeReleaseNULL(ivars
->target
);
1034 OSSafeReleaseNULL(ivars
->typeName
);
1035 IOSafeDeleteNULL(ivars
, uint8_t, ivars
->referenceSize
+ sizeof(OSAction_IVars
));
1037 return super::free();
1041 OSAction::GetReference()
1043 assert(ivars
&& ivars
->referenceSize
);
1044 return &ivars
->reference
[0];
1048 OSAction::SetAbortedHandler(OSActionAbortedHandler handler
)
1050 ivars
->abortedHandler
= Block_copy(handler
);
1051 return kIOReturnSuccess
;
1055 OSAction::Aborted_Impl(void)
1057 if (ivars
->abortedHandler
) {
1058 ivars
->abortedHandler();
1062 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1064 struct IODispatchSource_IVars
{
1066 IODispatchSource
* source
;
1067 IOUserServer
* server
;
1068 IODispatchQueue_IVars
* queue
;
1073 IODispatchSource::init()
1075 if (!super::init()) {
1079 ivars
= IONewZero(IODispatchSource_IVars
, 1);
1081 ivars
->source
= this;
1087 IODispatchSource::free()
1089 IOSafeDeleteNULL(ivars
, IODispatchSource_IVars
, 1);
1094 IODispatchSource::SetEnable_Impl(
1097 return SetEnableWithCompletion(enable
, NULL
);
1100 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1102 struct IOInterruptDispatchSource_IVars
{
1103 IOService
* provider
;
1106 IOSimpleLock
* lock
;
1115 IOInterruptDispatchSourceInterrupt(OSObject
* target
, void * refCon
,
1116 IOService
* nub
, int source
)
1118 IOInterruptDispatchSource_IVars
* ivars
= (typeof(ivars
))refCon
;
1119 IOInterruptState is
;
1121 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1123 if (ivars
->waiter
) {
1124 ivars
->time
= mach_absolute_time();
1125 thread_wakeup_thread((event_t
) ivars
, ivars
->waiter
);
1126 ivars
->waiter
= NULL
;
1128 if (kIOInterruptTypeLevel
& ivars
->interruptType
) {
1129 ivars
->provider
->disableInterrupt(ivars
->intIndex
);
1131 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1135 IOInterruptDispatchSource::Create_Impl(
1136 IOService
* provider
,
1138 IODispatchQueue
* queue
,
1139 IOInterruptDispatchSource
** source
)
1142 IOInterruptDispatchSource
* inst
;
1144 inst
= OSTypeAlloc(IOInterruptDispatchSource
);
1145 if (!inst
->init()) {
1147 return kIOReturnNoMemory
;
1150 inst
->ivars
->lock
= IOSimpleLockAlloc();
1152 ret
= provider
->getInterruptType(index
, &inst
->ivars
->interruptType
);
1153 if (kIOReturnSuccess
!= ret
) {
1154 OSSafeReleaseNULL(inst
);
1157 ret
= provider
->registerInterrupt(index
, inst
, IOInterruptDispatchSourceInterrupt
, inst
->ivars
);
1158 if (kIOReturnSuccess
== ret
) {
1159 inst
->ivars
->intIndex
= index
;
1160 inst
->ivars
->provider
= provider
;
1161 inst
->ivars
->provider
->retain();
1168 IOInterruptDispatchSource::GetInterruptType_Impl(
1169 IOService
* provider
,
1171 uint64_t * interruptType
)
1177 ret
= provider
->getInterruptType(index
, &type
);
1178 if (kIOReturnSuccess
== ret
) {
1179 *interruptType
= type
;
1186 IOInterruptDispatchSource::init()
1188 if (!super::init()) {
1191 ivars
= IONewZero(IOInterruptDispatchSource_IVars
, 1);
1200 IOInterruptDispatchSource::free()
1204 if (ivars
&& ivars
->provider
) {
1205 ret
= ivars
->provider
->unregisterInterrupt(ivars
->intIndex
);
1206 assert(kIOReturnSuccess
== ret
);
1207 ivars
->provider
->release();
1210 if (ivars
&& ivars
->lock
) {
1211 IOSimpleLockFree(ivars
->lock
);
1214 IOSafeDeleteNULL(ivars
, IOInterruptDispatchSource_IVars
, 1);
1220 IOInterruptDispatchSource::SetHandler_Impl(
1224 OSAction
* oldAction
;
1226 oldAction
= (typeof(oldAction
))ivars
->action
;
1227 if (oldAction
&& OSCompareAndSwapPtr(oldAction
, NULL
, &ivars
->action
)) {
1228 oldAction
->release();
1231 ivars
->action
= action
;
1233 ret
= kIOReturnSuccess
;
1239 IOInterruptDispatchSource::SetEnableWithCompletion_Impl(
1241 IODispatchSourceCancelHandler handler
)
1244 IOInterruptState is
;
1246 if (enable
== ivars
->enable
) {
1247 return kIOReturnSuccess
;
1251 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1252 ivars
->enable
= enable
;
1253 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1254 ret
= ivars
->provider
->enableInterrupt(ivars
->intIndex
);
1256 ret
= ivars
->provider
->disableInterrupt(ivars
->intIndex
);
1257 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1258 ivars
->enable
= enable
;
1259 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1266 IOInterruptDispatchSource::Cancel_Impl(
1267 IODispatchSourceCancelHandler handler
)
1269 return kIOReturnUnsupported
;
1273 IOInterruptDispatchSource::CheckForWork_Impl(
1277 IOReturn ret
= kIOReturnNotReady
;
1278 IOInterruptState is
;
1280 wait_result_t waitResult
;
1285 self
= current_thread();
1288 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1289 if ((icount
= ivars
->count
)) {
1290 itime
= ivars
->time
;
1292 waitResult
= THREAD_AWAKENED
;
1293 } else if (synchronous
) {
1294 assert(NULL
== ivars
->waiter
);
1295 ivars
->waiter
= self
;
1296 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
1298 willWait
= (synchronous
&& (waitResult
== THREAD_WAITING
));
1299 if (willWait
&& (kIOInterruptTypeLevel
& ivars
->interruptType
) && ivars
->enable
) {
1300 ivars
->provider
->enableInterrupt(ivars
->intIndex
);
1302 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1304 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
1305 if (THREAD_INTERRUPTED
== waitResult
) {
1306 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1307 ivars
->waiter
= NULL
;
1308 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1312 } while (synchronous
&& !icount
);
1314 if (icount
&& ivars
->action
) {
1315 ret
= InterruptOccurred(rpc
, ivars
->action
, icount
, itime
);
1322 IOInterruptDispatchSource::InterruptOccurred_Impl(
1329 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1332 kIOServiceNotificationTypeCount
= kIOServiceNotificationTypeLast
+ 1,
1335 struct IOServiceNotificationDispatchSource_IVars
{
1336 OSObject
* serverName
;
1339 IONotifier
* notifier
;
1340 OSDictionary
* interestNotifiers
;
1341 OSArray
* pending
[kIOServiceNotificationTypeCount
];
1346 IOServiceNotificationDispatchSource::Create_Impl(
1347 OSDictionary
* matching
,
1349 IODispatchQueue
* queue
,
1350 IOServiceNotificationDispatchSource
** notification
)
1354 IOServiceNotificationDispatchSource
* inst
;
1356 inst
= OSTypeAlloc(IOServiceNotificationDispatchSource
);
1357 if (!inst
->init()) {
1358 OSSafeReleaseNULL(inst
);
1359 return kIOReturnNoMemory
;
1362 us
= (typeof(us
))thread_iokit_tls_get(0);
1363 assert(OSDynamicCast(IOUserServer
, us
));
1365 OSSafeReleaseNULL(inst
);
1366 return kIOReturnError
;
1368 inst
->ivars
->serverName
= us
->copyProperty(gIOUserServerNameKey
);
1369 if (!inst
->ivars
->serverName
) {
1370 OSSafeReleaseNULL(inst
);
1371 return kIOReturnNoMemory
;
1374 inst
->ivars
->lock
= IOLockAlloc();
1375 if (!inst
->ivars
->lock
) {
1376 OSSafeReleaseNULL(inst
);
1377 return kIOReturnNoMemory
;
1379 for (uint32_t idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
1380 inst
->ivars
->pending
[idx
] = OSArray::withCapacity(4);
1381 if (!inst
->ivars
->pending
[idx
]) {
1382 OSSafeReleaseNULL(inst
);
1383 return kIOReturnNoMemory
;
1386 inst
->ivars
->interestNotifiers
= OSDictionary::withCapacity(4);
1387 if (!inst
->ivars
->interestNotifiers
) {
1388 OSSafeReleaseNULL(inst
);
1389 return kIOReturnNoMemory
;
1392 inst
->ivars
->notifier
= IOService::addMatchingNotification(gIOMatchedNotification
, matching
, 0 /*priority*/,
1393 ^bool (IOService
* newService
, IONotifier
* notifier
) {
1394 bool notifyReady
= false;
1395 IONotifier
* interest
;
1396 OSObject
* serverName
;
1399 serverName
= newService
->copyProperty(gIOUserServerNameKey
);
1400 okToUse
= (serverName
&& inst
->ivars
->serverName
->isEqualTo(serverName
));
1401 OSSafeReleaseNULL(serverName
);
1406 IOLockLock(inst
->ivars
->lock
);
1407 notifyReady
= (0 == inst
->ivars
->pending
[kIOServiceNotificationTypeMatched
]->getCount());
1408 inst
->ivars
->pending
[kIOServiceNotificationTypeMatched
]->setObject(newService
);
1409 IOLockUnlock(inst
->ivars
->lock
);
1411 interest
= newService
->registerInterest(gIOGeneralInterest
,
1412 ^IOReturn (uint32_t messageType
, IOService
* provider
,
1413 void * messageArgument
, size_t argSize
) {
1414 IONotifier
* interest
;
1415 bool notifyReady
= false;
1417 switch (messageType
) {
1418 case kIOMessageServiceIsTerminated
:
1419 IOLockLock(inst
->ivars
->lock
);
1420 notifyReady
= (0 == inst
->ivars
->pending
[kIOServiceNotificationTypeTerminated
]->getCount());
1421 inst
->ivars
->pending
[kIOServiceNotificationTypeTerminated
]->setObject(provider
);
1422 interest
= (typeof(interest
))inst
->ivars
->interestNotifiers
->getObject((const OSSymbol
*) newService
);
1425 inst
->ivars
->interestNotifiers
->removeObject((const OSSymbol
*) newService
);
1426 IOLockUnlock(inst
->ivars
->lock
);
1431 if (notifyReady
&& inst
->ivars
->action
) {
1432 inst
->ServiceNotificationReady(inst
->ivars
->action
);
1434 return kIOReturnSuccess
;
1437 IOLockLock(inst
->ivars
->lock
);
1438 inst
->ivars
->interestNotifiers
->setObject((const OSSymbol
*) newService
, interest
);
1439 IOLockUnlock(inst
->ivars
->lock
);
1442 if (inst
->ivars
->action
) {
1443 inst
->ServiceNotificationReady(inst
->ivars
->action
);
1449 if (!inst
->ivars
->notifier
) {
1450 OSSafeReleaseNULL(inst
);
1451 ret
= kIOReturnError
;
1454 *notification
= inst
;
1455 ret
= kIOReturnSuccess
;
1461 IOServiceNotificationDispatchSource::CopyNextNotification_Impl(
1463 IOService
** service
,
1469 IOLockLock(ivars
->lock
);
1470 for (idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
1471 next
= (IOService
*) ivars
->pending
[idx
]->getObject(0);
1474 ivars
->pending
[idx
]->removeObject(0);
1478 IOLockUnlock(ivars
->lock
);
1480 if (idx
== kIOServiceNotificationTypeCount
) {
1481 idx
= kIOServiceNotificationTypeNone
;
1487 return kIOReturnSuccess
;
1491 IOServiceNotificationDispatchSource::init()
1493 if (!super::init()) {
1496 ivars
= IONewZero(IOServiceNotificationDispatchSource_IVars
, 1);
1505 IOServiceNotificationDispatchSource::free()
1508 OSSafeReleaseNULL(ivars
->serverName
);
1509 if (ivars
->interestNotifiers
) {
1510 ivars
->interestNotifiers
->iterateObjects(^bool (const OSSymbol
* key
, OSObject
* object
) {
1511 IONotifier
* interest
= (typeof(interest
))object
;
1515 OSSafeReleaseNULL(ivars
->interestNotifiers
);
1517 for (uint32_t idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
1518 OSSafeReleaseNULL(ivars
->pending
[idx
]);
1521 IOLockFree(ivars
->lock
);
1524 if (ivars
->notifier
) {
1525 ivars
->notifier
->remove();
1526 ivars
->notifier
= NULL
;
1528 IOSafeDeleteNULL(ivars
, IOServiceNotificationDispatchSource_IVars
, 1);
1535 IOServiceNotificationDispatchSource::SetHandler_Impl(
1541 notifyReady
= false;
1543 IOLockLock(ivars
->lock
);
1544 OSSafeReleaseNULL(ivars
->action
);
1546 ivars
->action
= action
;
1548 for (uint32_t idx
= 0; idx
< kIOServiceNotificationTypeCount
; idx
++) {
1549 notifyReady
= (ivars
->pending
[idx
]->getCount());
1555 IOLockUnlock(ivars
->lock
);
1558 ServiceNotificationReady(action
);
1560 ret
= kIOReturnSuccess
;
1566 IOServiceNotificationDispatchSource::SetEnableWithCompletion_Impl(
1568 IODispatchSourceCancelHandler handler
)
1570 if (enable
== ivars
->enable
) {
1571 return kIOReturnSuccess
;
1574 IOLockLock(ivars
->lock
);
1575 ivars
->enable
= enable
;
1576 IOLockUnlock(ivars
->lock
);
1578 return kIOReturnSuccess
;
1582 IOServiceNotificationDispatchSource::Cancel_Impl(
1583 IODispatchSourceCancelHandler handler
)
1585 return kIOReturnUnsupported
;
1589 IOServiceNotificationDispatchSource::CheckForWork_Impl(
1593 return kIOReturnNotReady
;
1597 IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block
)
1599 return kIOReturnUnsupported
;
1602 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1605 IOUserServer::waitInterruptTrap(void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
1607 IOReturn ret
= kIOReturnBadArgument
;
1608 IOInterruptState is
;
1609 IOInterruptDispatchSource
* interrupt
;
1610 IOInterruptDispatchSource_IVars
* ivars
;
1611 IOInterruptDispatchSourcePayload payload
;
1614 wait_result_t waitResult
;
1619 object
= iokit_lookup_object_with_port_name((mach_port_name_t
)(uintptr_t)p1
, IKOT_UEXT_OBJECT
, current_task());
1622 return kIOReturnBadArgument
;
1624 if (!(interrupt
= OSDynamicCast(IOInterruptDispatchSource
, object
))) {
1625 ret
= kIOReturnBadArgument
;
1627 self
= current_thread();
1628 ivars
= interrupt
->ivars
;
1631 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1632 if ((payload
.count
= ivars
->count
)) {
1633 payload
.time
= ivars
->time
;
1635 waitResult
= THREAD_AWAKENED
;
1637 assert(NULL
== ivars
->waiter
);
1638 ivars
->waiter
= self
;
1639 waitResult
= assert_wait((event_t
) ivars
, THREAD_INTERRUPTIBLE
);
1641 willWait
= (waitResult
== THREAD_WAITING
);
1642 if (willWait
&& (kIOInterruptTypeLevel
& ivars
->interruptType
) && ivars
->enable
) {
1643 ivars
->provider
->enableInterrupt(ivars
->intIndex
);
1645 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1647 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
1648 if (THREAD_INTERRUPTED
== waitResult
) {
1649 is
= IOSimpleLockLockDisableInterrupt(ivars
->lock
);
1650 ivars
->waiter
= NULL
;
1651 IOSimpleLockUnlockEnableInterrupt(ivars
->lock
, is
);
1655 } while (!payload
.count
);
1656 ret
= (payload
.count
? kIOReturnSuccess
: kIOReturnAborted
);
1659 if (kIOReturnSuccess
== ret
) {
1660 int copyerr
= copyout(&payload
, (user_addr_t
) p2
, sizeof(payload
));
1662 ret
= kIOReturnVMError
;
1671 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1674 IOUserServer::Create_Impl(
1678 IOUserServer
** server
)
1682 const OSSymbol
* sym
;
1683 OSNumber
* serverTag
;
1686 us
= (typeof(us
))thread_iokit_tls_get(0);
1687 assert(OSDynamicCast(IOUserServer
, us
));
1688 if (kIODKLogSetup
& gIODKDebug
) {
1689 DKLOG(DKS
"::Create(" DKS
") %p\n", DKN(us
), name
, tag
, us
);
1692 return kIOReturnError
;
1695 sym
= OSSymbol::withCString(name
);
1696 serverTag
= OSNumber::withNumber(tag
, 64);
1698 us
->setProperty(gIOUserServerNameKey
, (OSObject
*) sym
);
1699 us
->setProperty(gIOUserServerTagKey
, serverTag
);
1701 serverTag
->release();
1702 OSSafeReleaseNULL(sym
);
1704 snprintf(rname
, sizeof(rname
), "IOUserServer(%s-0x%qx)", name
, tag
);
1709 ret
= kIOReturnSuccess
;
1715 IOUserServer::Exit_Impl(
1716 const char * reason
)
1718 return kIOReturnUnsupported
;
1722 IOUserServer::LoadModule_Impl(
1725 return kIOReturnUnsupported
;
1729 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1732 IODispatchQueue::Create_Impl(
1736 IODispatchQueue
** queue
)
1738 IODispatchQueue
* result
;
1741 result
= OSTypeAlloc(IODispatchQueue
);
1743 return kIOReturnNoMemory
;
1745 if (!result
->init()) {
1746 return kIOReturnNoMemory
;
1751 if (!strcmp("Root", name
)) {
1752 us
= (typeof(us
))thread_iokit_tls_get(0);
1753 assert(OSDynamicCast(IOUserServer
, us
));
1754 us
->setRootQueue(result
);
1757 if (kIODKLogSetup
& gIODKDebug
) {
1758 DKLOG("IODispatchQueue::Create %s %p\n", name
, result
);
1761 return kIOReturnSuccess
;
1765 IODispatchQueue::SetPort_Impl(
1768 if (MACH_PORT_NULL
!= ivars
->serverPort
) {
1769 return kIOReturnNotReady
;
1772 ivars
->serverPort
= port
;
1773 return kIOReturnSuccess
;
1777 IODispatchQueue::init()
1779 ivars
= IONewZero(IODispatchQueue_IVars
, 1);
1783 ivars
->queue
= this;
1789 IODispatchQueue::free()
1791 if (ivars
&& ivars
->serverPort
) {
1792 ipc_port_release_send(ivars
->serverPort
);
1793 ivars
->serverPort
= MACH_PORT_NULL
;
1795 IOSafeDeleteNULL(ivars
, IODispatchQueue_IVars
, 1);
1800 IODispatchQueue::OnQueue()
1805 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1809 OSMetaClassBase::Dispatch(IORPC rpc
)
1811 return kIOReturnUnsupported
;
1815 OSMetaClassBase::Invoke(IORPC rpc
)
1817 IOReturn ret
= kIOReturnUnsupported
;
1818 OSMetaClassBase
* object
;
1820 IOService
* service
;
1822 IORPCMessage
* message
;
1824 assert(rpc
.sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
1825 message
= IORPCMessageFromMach(rpc
.message
, false);
1827 return kIOReturnIPCError
;
1829 message
->flags
|= kIORPCMessageKernel
;
1832 if (!(kIORPCMessageLocalHost
& message
->flags
)) {
1833 us
= OSDynamicCast(IOUserServer
, this);
1835 if ((action
= OSDynamicCast(OSAction
, this))) {
1836 object
= IOUserServer::target(action
, message
);
1840 if ((service
= OSDynamicCast(IOService
, object
))
1841 && service
->reserved
->uvars
) {
1842 // xxx other classes
1843 us
= service
->reserved
->uvars
->userServer
;
1848 message
->flags
|= kIORPCMessageRemote
;
1850 if (kIOReturnSuccess
!= ret
) {
1851 if (kIODKLogIPC
& gIODKDebug
) {
1852 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret
);
1856 if (kIODKLogIPC
& gIODKDebug
) {
1857 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message
->msgid
);
1859 ret
= Dispatch(rpc
);
1865 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1870 const char strings
[0];
1874 OSUserMetaClass::Dispatch(IORPC rpc
)
1877 return const_cast<OSMetaClass
*>(meta
)->Dispatch(rpc
);
1879 return kIOReturnUnsupported
;
1884 OSUserMetaClass::free()
1887 IOFree(queueNames
, sizeof(IOPStrings
) + queueNames
->dataSize
* sizeof(char));
1891 IOFree(description
, description
->descriptionSize
);
1894 IOSafeDeleteNULL(methods
, uint64_t, 2 * methodCount
);
1896 meta
->releaseMetaClass();
1905 * Sets the loadTag of the associated OSKext
1907 * NOTE: different instances of the same OSKext
1908 * (so same BounleID but different tasks)
1909 * will have the same loadTag.
1912 IOUserServer::setTaskLoadTag(OSKext
*kext
)
1915 uint32_t loadTag
, prev_taskloadTag
;
1917 owningTask
= this->fOwningTask
;
1919 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1923 loadTag
= kext
->getLoadTag();
1924 prev_taskloadTag
= set_task_loadTag(owningTask
, loadTag
);
1925 if (prev_taskloadTag
) {
1926 printf("%s: found the task loadTag already set to %u (set to %u)\n",
1927 __FUNCTION__
, prev_taskloadTag
, loadTag
);
1932 * Sets the OSKext uuid as the uuid of the userspace
1936 IOUserServer::setDriverKitUUID(OSKext
*kext
)
1940 uuid_t p_uuid
, k_uuid
;
1941 OSData
*k_data_uuid
;
1943 uuid_string_t uuid_string
= "";
1945 task
= this->fOwningTask
;
1947 printf("%s: fOwningTask not found\n", __FUNCTION__
);
1951 p
= (proc_t
)(get_bsdtask_info(task
));
1953 printf("%s: proc not found\n", __FUNCTION__
);
1956 proc_getexecutableuuid(p
, p_uuid
, sizeof(p_uuid
));
1958 k_data_uuid
= kext
->copyUUID();
1960 memcpy(&k_uuid
, k_data_uuid
->getBytesNoCopy(), sizeof(k_uuid
));
1961 OSSafeReleaseNULL(k_data_uuid
);
1962 if (uuid_compare(k_uuid
, p_uuid
) != 0) {
1963 printf("%s: uuid not matching\n", __FUNCTION__
);
1968 uuid_unparse(p_uuid
, uuid_string
);
1969 new_uuid
= OSData::withBytes(p_uuid
, sizeof(p_uuid
));
1970 kext
->setDriverKitUUID(new_uuid
);
1974 IOUserServer::setCheckInToken(IOUserServerCheckInToken
*token
)
1976 if (token
!= NULL
&& fCheckInToken
== NULL
) {
1978 fCheckInToken
= token
;
1980 printf("%s: failed to set check in token. token=%p, fCheckInToken=%p\n", __FUNCTION__
, token
, fCheckInToken
);
1985 IOUserServer::serviceMatchesCheckInToken(IOUserServerCheckInToken
*token
)
1987 if (token
!= NULL
) {
1988 return token
== fCheckInToken
;
1990 printf("%s: null check in token\n", __FUNCTION__
);
1996 IOUserServer::checkEntitlements(
1997 OSDictionary
* entitlements
, OSObject
* prop
,
1998 IOService
* provider
, IOService
* dext
)
2000 OSDictionary
* matching
;
2005 if (!entitlements
) {
2011 matching
= dext
->dictionaryWithProperties();
2017 bool allPresent __block
;
2018 prop
->iterateObjects(^bool (OSObject
* object
) {
2020 object
->iterateObjects(^bool (OSObject
* object
) {
2023 string
= OSDynamicCast(OSString
, object
);
2024 value
= entitlements
->getObject(string
);
2025 if (matching
&& value
) {
2026 matching
->setObject(string
, value
);
2028 allPresent
= (NULL
!= value
);
2034 if (allPresent
&& matching
&& provider
) {
2035 allPresent
= provider
->matchPropertyTable(matching
);
2038 OSSafeReleaseNULL(matching
);
2039 OSSafeReleaseNULL(prop
);
2045 IOUserServer::checkEntitlements(IOService
* provider
, IOService
* dext
)
2054 prop
= provider
->copyProperty(gIOServiceDEXTEntitlementsKey
);
2055 ok
= checkEntitlements(fEntitlements
, prop
, provider
, dext
);
2057 DKLOG(DKS
": provider entitlements check failed\n", DKN(dext
));
2060 prop
= dext
->copyProperty(gIOServiceDEXTEntitlementsKey
);
2061 ok
= checkEntitlements(fEntitlements
, prop
, NULL
, NULL
);
2063 DKLOG(DKS
": family entitlements check failed\n", DKN(dext
));
2071 IOUserServer::exit(const char * reason
)
2073 DKLOG("%s::exit(%s)\n", getName(), reason
);
2075 return kIOReturnSuccess
;
2079 IOUserServer::varsForObject(OSObject
* obj
)
2081 IOService
* service
;
2083 if ((service
= OSDynamicCast(IOService
, obj
))) {
2084 return service
->reserved
->uvars
;
2091 IOUserServer::copyInStringArray(const char * string
, uint32_t userSize
)
2099 if (userSize
<= 1) {
2103 if (os_add_overflow(sizeof(IOPStrings
), userSize
, &alloc
)) {
2107 if (alloc
> 16384) {
2111 array
= (typeof(array
))IOMalloc(alloc
);
2115 array
->dataSize
= userSize
;
2116 bcopy(string
, (void *) &array
->strings
[0], userSize
);
2119 cstr
= &array
->strings
[0];
2120 end
= &array
->strings
[array
->dataSize
];
2121 while ((len
= (unsigned char)cstr
[0])) {
2123 if ((cstr
+ len
) >= end
) {
2130 IOFree(array
, alloc
);
2138 IOUserServer::stringArrayIndex(IOPStrings
* array
, const char * look
)
2146 cstr
= &array
->strings
[0];
2147 end
= &array
->strings
[array
->dataSize
];
2148 llen
= strlen(look
);
2149 while ((len
= (unsigned char)cstr
[0])) {
2151 if ((cstr
+ len
) >= end
) {
2154 if ((len
== llen
) && !strncmp(cstr
, look
, len
)) {
2163 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
2166 IOUserServer::queueForObject(OSObject
* obj
, uint64_t msgid
)
2168 IODispatchQueue
* queue
;
2169 OSObjectUserVars
* uvars
;
2172 uvars
= varsForObject(obj
);
2176 if (!uvars
->queueArray
) {
2177 if (uvars
->stopped
) {
2178 return kIODispatchQueueStopped
;
2182 queue
= uvars
->queueArray
[0];
2185 && uvars
->userMeta
->methods
) {
2186 uint32_t idx
, baseIdx
;
2189 for (baseIdx
= 0, lim
= uvars
->userMeta
->methodCount
; lim
; lim
>>= 1) {
2190 idx
= baseIdx
+ (lim
>> 1);
2191 if (msgid
== uvars
->userMeta
->methods
[idx
]) {
2192 option
= uvars
->userMeta
->methods
[uvars
->userMeta
->methodCount
+ idx
];
2194 if (option
< uvars
->userMeta
->queueNames
->count
) {
2195 queue
= uvars
->queueArray
[option
+ 1];
2198 } else if (msgid
> uvars
->userMeta
->methods
[idx
]) {
2200 baseIdx
+= (lim
>> 1) + 1;
2210 IOUserServer::objectInstantiate(OSObject
* obj
, IORPC rpc
, IORPCMessage
* message
)
2215 IOService
* service
;
2219 uint32_t queueCount
, queueAlloc
;
2220 const char * resultClassName
;
2221 uint64_t resultFlags
;
2223 mach_msg_size_t replySize
;
2224 uint32_t methodCount
;
2225 const uint64_t * methods
;
2226 IODispatchQueue
* queue
;
2227 OSUserMetaClass
* userMeta
;
2228 OSObjectUserVars
* uvars
;
2230 ipc_port_t sendPort
;
2232 OSObject_Instantiate_Rpl_Content
* reply
;
2240 resultClassName
= NULL
;
2242 ret
= kIOReturnUnsupportedMode
;
2244 service
= OSDynamicCast(IOService
, obj
);
2245 action
= OSDynamicCast(OSAction
, obj
);
2247 // xxx other classes hosted
2248 resultFlags
|= kOSObjectRPCKernel
;
2249 resultFlags
|= kOSObjectRPCRemote
;
2251 if (service
->isInactive()) {
2252 DKLOG(DKS
"::instantiate inactive\n", DKN(service
));
2253 return kIOReturnOffline
;
2255 prop
= service
->copyProperty(gIOUserClassKey
);
2256 str
= OSDynamicCast(OSString
, prop
);
2257 if (!service
->reserved
->uvars
) {
2258 resultFlags
|= kOSObjectRPCRemote
;
2259 resultFlags
|= kOSObjectRPCKernel
;
2260 } else if (this != service
->reserved
->uvars
->userServer
) {
2261 // remote, use base class
2262 resultFlags
|= kOSObjectRPCRemote
;
2264 if (service
->reserved
->uvars
&& service
->reserved
->uvars
->userServer
) {
2265 IOLockLock(service
->reserved
->uvars
->userServer
->fLock
);
2266 userMeta
= (typeof(userMeta
))service
->reserved
->uvars
->userServer
->fClasses
->getObject(str
);
2267 IOLockUnlock(service
->reserved
->uvars
->userServer
->fLock
);
2270 if (!str
&& !userMeta
) {
2271 const OSMetaClass
* meta
;
2272 meta
= obj
->getMetaClass();
2275 str
= action
->ivars
->typeName
;
2277 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
2280 while (meta
&& !userMeta
) {
2281 str
= (OSString
*) meta
->getClassNameSymbol();
2282 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
2284 meta
= meta
->getSuperClass();
2287 IOLockUnlock(fLock
);
2292 userMeta
= (typeof(userMeta
))fClasses
->getObject(str
);
2293 IOLockUnlock(fLock
);
2295 if (kIODKLogSetup
& gIODKDebug
) {
2296 DKLOG("userMeta %s %p\n", str
->getCStringNoCopy(), userMeta
);
2299 if (kOSObjectRPCRemote
& resultFlags
) {
2301 /* Special case: For OSAction subclasses, do not use the superclass */
2302 while (userMeta
&& !(kOSClassCanRemote
& userMeta
->description
->flags
)) {
2303 userMeta
= userMeta
->superMeta
;
2307 resultClassName
= userMeta
->description
->name
;
2308 ret
= kIOReturnSuccess
;
2311 service
->reserved
->uvars
->userMeta
= userMeta
;
2313 if (userMeta
->queueNames
) {
2314 queueAlloc
+= userMeta
->queueNames
->count
;
2316 service
->reserved
->uvars
->queueArray
=
2317 IONewZero(IODispatchQueue
*, queueAlloc
);
2318 resultClassName
= str
->getCStringNoCopy();
2319 ret
= kIOReturnSuccess
;
2321 } else if (kIODKLogSetup
& gIODKDebug
) {
2322 DKLOG("userMeta %s was not found in fClasses\n", str
->getCStringNoCopy());
2324 fClasses
->iterateObjects(^bool (const OSSymbol
* key
, OSObject
* val
) {
2325 DKLOG(" fClasses[\"%s\"] => %p\n", key
->getCStringNoCopy(), val
);
2328 IOLockUnlock(fLock
);
2331 OSSafeReleaseNULL(prop
);
2333 IORPCMessageMach
* machReply
= rpc
.reply
;
2334 replySize
= sizeof(OSObject_Instantiate_Rpl
);
2336 if ((kIOReturnSuccess
== ret
) && (kOSObjectRPCRemote
& resultFlags
)) {
2339 if (action
->ivars
->referenceSize
) {
2340 resultFlags
|= kOSObjectRPCKernel
;
2342 resultFlags
&= ~kOSObjectRPCKernel
;
2343 target
= action
->ivars
->target
;
2346 queue
= queueForObject(target
, action
->ivars
->targetmsgid
);
2349 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
2350 sendPort
= ipc_port_copy_send(queue
->ivars
->serverPort
);
2352 replySize
= sizeof(OSObject_Instantiate_Rpl
)
2353 + queueCount
* sizeof(machReply
->objects
[0])
2354 + 2 * methodCount
* sizeof(reply
->methods
[0]);
2355 if (replySize
> rpc
.replySize
) {
2357 return kIOReturnIPCError
;
2359 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
2360 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
2361 machReply
->objects
[idx
].name
= sendPort
;
2362 machReply
->objects
[idx
].pad2
= 0;
2363 machReply
->objects
[idx
].pad_end
= 0;
2366 uvars
= varsForObject(target
);
2367 if (uvars
&& uvars
->userMeta
) {
2369 if (uvars
->userMeta
->queueNames
) {
2370 queueCount
+= uvars
->userMeta
->queueNames
->count
;
2372 methods
= &uvars
->userMeta
->methods
[0];
2373 methodCount
= uvars
->userMeta
->methodCount
;
2374 replySize
= sizeof(OSObject_Instantiate_Rpl
)
2375 + queueCount
* sizeof(machReply
->objects
[0])
2376 + 2 * methodCount
* sizeof(reply
->methods
[0]);
2377 if (replySize
> rpc
.replySize
) {
2379 return kIOReturnIPCError
;
2381 for (idx
= 0; idx
< queueCount
; idx
++) {
2382 queue
= uvars
->queueArray
[idx
];
2385 sendPort
= ipc_port_copy_send(queue
->ivars
->serverPort
);
2387 machReply
->objects
[idx
].type
= MACH_MSG_PORT_DESCRIPTOR
;
2388 machReply
->objects
[idx
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
2389 machReply
->objects
[idx
].name
= sendPort
;
2390 machReply
->objects
[idx
].pad2
= 0;
2391 machReply
->objects
[idx
].pad_end
= 0;
2397 if (kIODKLogIPC
& gIODKDebug
) {
2398 DKLOG("instantiate object %s with user class %s\n", obj
->getMetaClass()->getClassName(), str
? str
->getCStringNoCopy() : "(null)");
2401 if (kIOReturnSuccess
!= ret
) {
2402 DKLOG("%s: no user class found\n", str
? str
->getCStringNoCopy() : obj
->getMetaClass()->getClassName());
2403 resultClassName
= "unknown";
2406 machReply
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
2407 machReply
->msgh
.msgh_size
= replySize
;
2408 machReply
->msgh_body
.msgh_descriptor_count
= queueCount
;
2410 reply
= (typeof(reply
))IORPCMessageFromMach(machReply
, true);
2412 return kIOReturnIPCError
;
2415 bcopy(methods
, &reply
->methods
[0], methodCount
* 2 * sizeof(reply
->methods
[0]));
2417 reply
->__hdr
.msgid
= OSObject_Instantiate_ID
;
2418 reply
->__hdr
.flags
= kIORPCMessageOneway
;
2419 reply
->__hdr
.objectRefs
= 0;
2421 reply
->flags
= resultFlags
;
2422 strlcpy(reply
->classname
, resultClassName
, sizeof(reply
->classname
));
2423 reply
->__result
= ret
;
2425 ret
= kIOReturnSuccess
;
2430 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2433 IOUserServer::kernelDispatch(OSObject
* obj
, IORPC rpc
)
2436 IORPCMessage
* message
;
2438 message
= IORPCMessageFromMach(rpc
.message
, false);
2440 return kIOReturnIPCError
;
2443 if (OSObject_Instantiate_ID
== message
->msgid
) {
2444 ret
= objectInstantiate(obj
, rpc
, message
);
2445 if (kIOReturnSuccess
!= ret
) {
2446 DKLOG("%s: instantiate failed 0x%x\n", obj
->getMetaClass()->getClassName(), ret
);
2449 if (kIODKLogIPC
& gIODKDebug
) {
2450 DKLOG("%s::Dispatch kernel 0x%qx\n", obj
->getMetaClass()->getClassName(), message
->msgid
);
2452 ret
= obj
->Dispatch(rpc
);
2453 if (kIODKLogIPC
& gIODKDebug
) {
2454 DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj
->getMetaClass()->getClassName(), message
->msgid
, ret
);
2462 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2465 IOUserServer::target(OSAction
* action
, IORPCMessage
* message
)
2469 if (message
->msgid
!= action
->ivars
->msgid
) {
2472 object
= action
->ivars
->target
;
2473 message
->msgid
= action
->ivars
->targetmsgid
;
2474 message
->objects
[0] = (OSObjectRef
) object
;
2475 if (kIORPCMessageRemote
& message
->flags
) {
2477 #ifndef __clang_analyzer__
2478 // Hide the release of 'action' from the clang static analyzer to suppress
2479 // an overrelease diagnostic. The analyzer doesn't have a way to express the
2480 // non-standard contract of this method, which is that it releases 'action' when
2481 // the message flags have kIORPCMessageRemote set.
2485 if (kIODKLogIPC
& gIODKDebug
) {
2486 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
, action
->ivars
->msgid
);
2492 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2495 uext_server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
2498 IORPCMessageMach
* msgin
;
2500 IOUserServer
* server
;
2502 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
2504 object
= IOUserServer::copyObjectForSendRight(msgin
->msgh
.msgh_remote_port
, IKOT_UEXT_OBJECT
);
2505 server
= OSDynamicCast(IOUserServer
, object
);
2507 OSSafeReleaseNULL(object
);
2508 return KERN_INVALID_NAME
;
2510 ret
= server
->server(requestkmsg
, pReply
);
2516 #define MAX_UEXT_REPLY_SIZE 0x17c0
2519 IOUserServer::server(ipc_kmsg_t requestkmsg
, ipc_kmsg_t
* pReply
)
2522 mach_msg_size_t replyAlloc
;
2523 ipc_kmsg_t replykmsg
;
2524 IORPCMessageMach
* msgin
;
2525 IORPCMessage
* message
;
2526 IORPCMessageMach
* msgout
;
2527 IORPCMessage
* reply
;
2534 msgin
= (typeof(msgin
))ipc_kmsg_msg_header(requestkmsg
);
2539 if (msgin
->msgh
.msgh_size
< (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
2540 if (kIODKLogIPC
& gIODKDebug
) {
2541 DKLOG("UEXT notify %o\n", msgin
->msgh
.msgh_id
);
2543 return KERN_NOT_SUPPORTED
;
2546 if (!(MACH_MSGH_BITS_COMPLEX
& msgin
->msgh
.msgh_bits
)) {
2547 msgin
->msgh_body
.msgh_descriptor_count
= 0;
2549 message
= IORPCMessageFromMach(msgin
, false);
2551 return kIOReturnIPCError
;
2553 if (message
->objectRefs
== 0) {
2554 return kIOReturnIPCError
;
2556 ret
= copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, true, false);
2557 if (kIOReturnSuccess
!= ret
) {
2558 if (kIODKLogIPC
& gIODKDebug
) {
2559 DKLOG("UEXT copyin(0x%x) %x\n", ret
, msgin
->msgh
.msgh_id
);
2561 return KERN_NOT_SUPPORTED
;
2564 if (msgin
->msgh_body
.msgh_descriptor_count
< 1) {
2565 return KERN_NOT_SUPPORTED
;
2567 object
= (OSObject
*) message
->objects
[0];
2568 msgid
= message
->msgid
;
2569 message
->flags
&= ~kIORPCMessageKernel
;
2570 message
->flags
|= kIORPCMessageRemote
;
2572 if ((action
= OSDynamicCast(OSAction
, object
))) {
2573 object
= target(action
, message
);
2574 msgid
= message
->msgid
;
2577 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
2578 assert(oneway
|| (MACH_PORT_NULL
!= msgin
->msgh
.msgh_local_port
));
2580 // includes trailer size
2581 replyAlloc
= oneway
? 0 : MAX_UEXT_REPLY_SIZE
;
2583 replykmsg
= ipc_kmsg_alloc(replyAlloc
);
2584 if (replykmsg
== NULL
) {
2585 // printf("uext_server: dropping request\n");
2586 // ipc_kmsg_trace_send(request, option);
2587 consumeObjects(message
, msgin
->msgh
.msgh_size
);
2588 ipc_kmsg_destroy(requestkmsg
);
2589 return KERN_MEMORY_FAILURE
;
2592 msgout
= (typeof(msgout
))ipc_kmsg_msg_header(replykmsg
);
2594 * MIG should really assure no data leakage -
2595 * but until it does, pessimistically zero the
2596 * whole reply buffer.
2598 bzero((void *)msgout
, replyAlloc
);
2601 IORPC rpc
= { .message
= msgin
, .reply
= msgout
, .sendSize
= msgin
->msgh
.msgh_size
, .replySize
= replyAlloc
};
2604 thread_iokit_tls_set(0, this);
2605 ret
= kernelDispatch(object
, rpc
);
2606 thread_iokit_tls_set(0, NULL
);
2608 ret
= kIOReturnBadArgument
;
2612 consumeObjects(message
, msgin
->msgh
.msgh_size
);
2615 copyInObjects(msgin
, message
, msgin
->msgh
.msgh_size
, false, true);
2618 if (kIOReturnSuccess
== ret
) {
2619 replySize
= msgout
->msgh
.msgh_size
;
2620 reply
= IORPCMessageFromMach(msgout
, true);
2622 ret
= kIOReturnIPCError
;
2624 ret
= copyOutObjects(msgout
, reply
, replySize
, (kIORPCVersionCurrentReply
== msgout
->msgh
.msgh_id
) /* =>!InvokeReply */);
2627 if (kIOReturnSuccess
!= ret
) {
2628 IORPCMessageErrorReturnContent
* errorMsg
;
2630 msgout
->msgh_body
.msgh_descriptor_count
= 0;
2631 msgout
->msgh
.msgh_id
= kIORPCVersionCurrentReply
;
2632 errorMsg
= (typeof(errorMsg
))IORPCMessageFromMach(msgout
, true);
2633 errorMsg
->hdr
.msgid
= message
->msgid
;
2634 errorMsg
->hdr
.flags
= kIORPCMessageOneway
| kIORPCMessageError
;
2635 errorMsg
->hdr
.objectRefs
= 0;
2636 errorMsg
->result
= ret
;
2638 replySize
= sizeof(IORPCMessageErrorReturn
);
2641 msgout
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
2642 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin
->msgh
.msgh_bits
) /*remote*/, 0 /*local*/, 0, 0);
2644 msgout
->msgh
.msgh_remote_port
= msgin
->msgh
.msgh_local_port
;
2645 msgout
->msgh
.msgh_local_port
= MACH_PORT_NULL
;
2646 msgout
->msgh
.msgh_voucher_port
= (mach_port_name_t
) 0;
2647 msgout
->msgh
.msgh_reserved
= 0;
2648 msgout
->msgh
.msgh_size
= replySize
;
2651 *pReply
= replykmsg
;
2653 return oneway
? MIG_NO_REPLY
: KERN_SUCCESS
;
2656 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2658 #define MAX_OBJECT_COUNT(mach, size, message) \
2659 ((uint32_t)(((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))))
2662 IOUserServerUEXTTrap(OSObject
* object
, void * p1
, void * p2
, void * p3
, void * p4
, void * p5
, void * p6
)
2664 const user_addr_t msg
= (uintptr_t) p1
;
2665 size_t inSize
= (uintptr_t) p2
;
2666 user_addr_t out
= (uintptr_t) p3
;
2667 size_t outSize
= (uintptr_t) p4
;
2668 mach_port_name_t objectName1
= (mach_port_name_t
)(uintptr_t) p5
;
2670 OSObject
* objectArg1
;
2672 IORPCMessageMach
* mach
;
2673 mach_msg_port_descriptor_t
* descs
;
2678 IORPCMessageMach mach
;
2679 mach_msg_port_descriptor_t objects
[2];
2680 IOTrapMessageBuffer buffer
;
2687 IORPCMessage
* message
;
2688 IORPCMessage
* reply
;
2691 uint32_t maxObjectCount
;
2693 uint64_t * replyHdr
;
2696 bzero(&buffer
, sizeof(buffer
));
2698 p
= (typeof(p
)) & buffer
.buffer
[0];
2699 if (os_add_overflow(inSize
, outSize
, &totalSize
)) {
2700 return kIOReturnMessageTooLarge
;
2702 if (totalSize
> sizeof(buffer
.buffer
)) {
2703 return kIOReturnMessageTooLarge
;
2705 if (inSize
< sizeof(IORPCMessage
)) {
2706 return kIOReturnIPCError
;
2708 copyerr
= copyin(msg
, &buffer
.buffer
[0], inSize
);
2710 return kIOReturnVMError
;
2713 message
= (typeof(message
))p
;
2714 refs
= message
->objectRefs
;
2715 if ((refs
> 2) || !refs
) {
2716 return kIOReturnUnsupported
;
2718 if (!(kIORPCMessageSimpleReply
& message
->flags
)) {
2719 return kIOReturnUnsupported
;
2722 descs
= (typeof(descs
))(p
- refs
* sizeof(*descs
));
2723 mach
= (typeof(mach
))(p
- refs
* sizeof(*descs
) - sizeof(*mach
));
2725 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
2726 mach
->msgh
.msgh_size
= (mach_msg_size_t
) (sizeof(IORPCMessageMach
) + refs
* sizeof(*descs
) + inSize
); // totalSize was checked
2727 mach
->msgh_body
.msgh_descriptor_count
= ((mach_msg_size_t
) refs
);
2730 rpc
.sendSize
= mach
->msgh
.msgh_size
;
2731 rpc
.reply
= (IORPCMessageMach
*) (p
+ inSize
);
2732 rpc
.replySize
= ((uint32_t) (sizeof(buffer
.buffer
) - inSize
)); // inSize was checked
2734 message
->objects
[0] = 0;
2735 if ((action
= OSDynamicCast(OSAction
, object
))) {
2736 maxObjectCount
= MAX_OBJECT_COUNT(rpc
.message
, rpc
.sendSize
, message
);
2737 if (refs
> maxObjectCount
) {
2738 return kIOReturnBadArgument
;
2740 object
= IOUserServer::target(action
, message
);
2741 message
->objects
[1] = (OSObjectRef
) action
;
2742 if (kIODKLogIPC
& gIODKDebug
) {
2743 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
2745 ret
= object
->Dispatch(rpc
);
2750 objectArg1
= iokit_lookup_uext_ref_current_task(objectName1
);
2752 return kIOReturnIPCError
;
2755 message
->objects
[1] = (OSObjectRef
) objectArg1
;
2757 if (kIODKLogIPC
& gIODKDebug
) {
2758 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object
->getMetaClass()->getClassName(), message
->msgid
);
2760 ret
= object
->Dispatch(rpc
);
2761 if (kIODKLogIPC
& gIODKDebug
) {
2762 DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object
->getMetaClass()->getClassName(), message
->msgid
, ret
);
2764 OSSafeReleaseNULL(objectArg1
);
2766 if (kIOReturnSuccess
== ret
) {
2767 if (rpc
.reply
->msgh_body
.msgh_descriptor_count
) {
2768 return kIOReturnIPCError
;
2770 reply
= IORPCMessageFromMach(rpc
.reply
, rpc
.reply
->msgh
.msgh_size
);
2772 return kIOReturnIPCError
;
2774 copySize
= rpc
.reply
->msgh
.msgh_size
- (((uintptr_t) reply
) - ((uintptr_t) rpc
.reply
)) + sizeof(uint64_t);
2775 if (copySize
> outSize
) {
2776 return kIOReturnIPCError
;
2778 replyHdr
= (uint64_t *) reply
;
2780 replyHdr
[0] = copySize
;
2781 copyerr
= copyout(replyHdr
, out
, copySize
);
2783 return kIOReturnVMError
;
2791 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2794 IOUserServer::rpc(IORPC rpc
)
2796 if (isInactive() && !fRootQueue
) {
2797 return kIOReturnOffline
;
2801 IORPCMessage
* message
;
2802 IORPCMessageMach
* mach
;
2803 mach_msg_id_t machid
;
2804 uint32_t sendSize
, replySize
;
2807 IODispatchQueue
* queue
;
2808 IOService
* service
;
2810 ipc_port_t sendPort
;
2817 sendSize
= rpc
.sendSize
;
2818 replySize
= rpc
.replySize
;
2820 assert(sendSize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
2822 message
= IORPCMessageFromMach(mach
, false);
2824 return kIOReturnIPCError
;
2826 msgid
= message
->msgid
;
2827 machid
= (msgid
>> 32);
2829 if (mach
->msgh_body
.msgh_descriptor_count
< 1) {
2830 return kIOReturnNoMedia
;
2833 IOLockLock(gIOUserServerLock
);
2834 if ((service
= OSDynamicCast(IOService
, (OSObject
*) message
->objects
[0]))) {
2835 queue
= queueForObject(service
, msgid
);
2840 if (queue
&& (kIODispatchQueueStopped
!= queue
)) {
2841 port
= queue
->ivars
->serverPort
;
2844 sendPort
= ipc_port_copy_send(port
);
2846 IOLockUnlock(gIOUserServerLock
);
2848 return kIOReturnNotReady
;
2851 oneway
= (0 != (kIORPCMessageOneway
& message
->flags
));
2853 ret
= copyOutObjects(mach
, message
, sendSize
, false);
2855 mach
->msgh
.msgh_bits
= MACH_MSGH_BITS_COMPLEX
|
2856 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, (oneway
? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE
));
2857 mach
->msgh
.msgh_remote_port
= sendPort
;
2858 mach
->msgh
.msgh_local_port
= (oneway
? MACH_PORT_NULL
: mig_get_reply_port());
2859 mach
->msgh
.msgh_id
= kIORPCVersionCurrent
;
2860 mach
->msgh
.msgh_reserved
= 0;
2862 boolean_t message_moved
;
2865 ret
= kernel_mach_msg_send(&mach
->msgh
, sendSize
,
2866 MACH_SEND_MSG
| MACH_SEND_ALWAYS
| MACH_SEND_NOIMPORTANCE
,
2869 assert(replySize
>= (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
)));
2870 ret
= kernel_mach_msg_rpc(&mach
->msgh
, sendSize
, replySize
, FALSE
, FALSE
, &message_moved
);
2873 ipc_port_release_send(sendPort
);
2875 if (MACH_MSG_SUCCESS
!= ret
) {
2876 if (kIODKLogIPC
& gIODKDebug
) {
2877 DKLOG("mach_msg() failed 0x%x\n", ret
);
2879 if (!message_moved
) {
2881 copyInObjects(mach
, message
, sendSize
, false, true);
2885 if ((KERN_SUCCESS
== ret
) && !oneway
) {
2886 if (kIORPCVersionCurrentReply
!= mach
->msgh
.msgh_id
) {
2887 ret
= (MACH_NOTIFY_SEND_ONCE
== mach
->msgh
.msgh_id
) ? MIG_SERVER_DIED
: MIG_REPLY_MISMATCH
;
2888 } else if ((replySize
= mach
->msgh
.msgh_size
) < (sizeof(IORPCMessageMach
) + sizeof(IORPCMessage
))) {
2889 // printf("BAD REPLY SIZE\n");
2890 ret
= MIG_BAD_ARGUMENTS
;
2892 if (!(MACH_MSGH_BITS_COMPLEX
& mach
->msgh
.msgh_bits
)) {
2893 mach
->msgh_body
.msgh_descriptor_count
= 0;
2895 message
= IORPCMessageFromMach(mach
, true);
2897 ret
= kIOReturnIPCError
;
2898 } else if (message
->msgid
!= msgid
) {
2899 // printf("BAD REPLY ID\n");
2900 ret
= MIG_BAD_ARGUMENTS
;
2902 bool isError
= (0 != (kIORPCMessageError
& message
->flags
));
2903 ret
= copyInObjects(mach
, message
, replySize
, !isError
, true);
2904 if (kIOReturnSuccess
!= ret
) {
2905 if (kIODKLogIPC
& gIODKDebug
) {
2906 DKLOG("rpc copyin(0x%x) %x\n", ret
, mach
->msgh
.msgh_id
);
2908 return KERN_NOT_SUPPORTED
;
2911 IORPCMessageErrorReturnContent
* errorMsg
= (typeof(errorMsg
))message
;
2912 ret
= errorMsg
->result
;
2921 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2924 IORPCMessageFromMach(IORPCMessageMach
* msg
, bool reply
)
2926 mach_msg_size_t idx
, count
;
2927 mach_msg_port_descriptor_t
* desc
;
2928 mach_msg_port_descriptor_t
* maxDesc
;
2929 size_t size
, msgsize
;
2932 msgsize
= msg
->msgh
.msgh_size
;
2933 count
= msg
->msgh_body
.msgh_descriptor_count
;
2934 desc
= &msg
->objects
[0];
2935 maxDesc
= (typeof(maxDesc
))(((uintptr_t) msg
) + msgsize
);
2936 upgrade
= (msg
->msgh
.msgh_id
!= (reply
? kIORPCVersionCurrentReply
: kIORPCVersionCurrent
));
2939 OSReportWithBacktrace("obsolete message");
2943 for (idx
= 0; idx
< count
; idx
++) {
2944 if (desc
>= maxDesc
) {
2947 switch (desc
->type
) {
2948 case MACH_MSG_PORT_DESCRIPTOR
:
2949 size
= sizeof(mach_msg_port_descriptor_t
);
2951 case MACH_MSG_OOL_DESCRIPTOR
:
2952 size
= sizeof(mach_msg_ool_descriptor_t
);
2957 desc
= (typeof(desc
))(((uintptr_t) desc
) + size
);
2959 return (IORPCMessage
*)(uintptr_t) desc
;
2963 IOUserServer::copySendRightForObject(OSObject
* object
, ipc_kobject_type_t type
)
2966 ipc_port_t sendPort
= NULL
;
2968 port
= iokit_port_for_object(object
, type
);
2970 sendPort
= ipc_port_make_send(port
);
2971 iokit_release_port(port
);
2978 IOUserServer::copyObjectForSendRight(ipc_port_t port
, ipc_kobject_type_t type
)
2981 object
= iokit_lookup_io_object(port
, type
);
2985 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2987 // Create a vm_map_copy_t or kalloc'ed data for memory
2988 // to be copied out. ipc will free after the copyout.
2990 static kern_return_t
2991 copyoutkdata(const void * data
, vm_size_t len
, void ** buf
)
2996 err
= vm_map_copyin( kernel_map
, CAST_USER_ADDR_T(data
), len
,
2997 false /* src_destroy */, ©
);
2999 assert( err
== KERN_SUCCESS
);
3000 if (err
== KERN_SUCCESS
) {
3001 *buf
= (char *) copy
;
3007 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3010 IOUserServer::copyOutObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
3011 size_t size
, bool consume
)
3014 uint32_t idx
, maxObjectCount
;
3018 mach_msg_port_descriptor_t
* desc
;
3019 mach_msg_ool_descriptor_t
* ool
;
3022 mach_msg_size_t length
;
3026 refs
= message
->objectRefs
;
3027 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
3028 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
3029 // assert(refs <= maxObjectCount);
3030 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
3031 return kIOReturnBadArgument
;
3033 if (refs
> maxObjectCount
) {
3034 return kIOReturnBadArgument
;
3037 desc
= &mach
->objects
[0];
3038 for (idx
= 0; idx
< refs
; idx
++) {
3039 object
= (OSObject
*) message
->objects
[idx
];
3041 switch (desc
->type
) {
3042 case MACH_MSG_PORT_DESCRIPTOR
:
3043 descsize
= sizeof(mach_msg_port_descriptor_t
);
3046 port
= copySendRightForObject(object
, IKOT_UEXT_OBJECT
);
3053 message
->objects
[idx
] = 0;
3055 // desc->type = MACH_MSG_PORT_DESCRIPTOR;
3056 desc
->disposition
= MACH_MSG_TYPE_MOVE_SEND
;
3062 case MACH_MSG_OOL_DESCRIPTOR
:
3063 descsize
= sizeof(mach_msg_ool_descriptor_t
);
3068 s
= OSSerialize::binaryWithCapacity(4096);
3073 s
->setIndexed(true);
3074 if (!object
->serialize(s
)) {
3080 length
= s
->getLength();
3081 kr
= copyoutkdata(s
->text(), length
, &address
);
3083 if (KERN_SUCCESS
!= kr
) {
3091 message
->objects
[idx
] = 0;
3093 ool
= (typeof(ool
))desc
;
3094 // ool->type = MACH_MSG_OOL_DESCRIPTOR;
3095 ool
->deallocate
= false;
3096 ool
->copy
= MACH_MSG_PHYSICAL_COPY
;
3098 ool
->address
= address
;
3105 if (-1UL == descsize
) {
3108 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
3112 return kIOReturnSuccess
;
3115 desc
= &mach
->objects
[0];
3117 switch (desc
->type
) {
3118 case MACH_MSG_PORT_DESCRIPTOR
:
3119 descsize
= sizeof(mach_msg_port_descriptor_t
);
3122 ipc_port_release_send(port
);
3126 case MACH_MSG_OOL_DESCRIPTOR
:
3127 descsize
= sizeof(mach_msg_ool_descriptor_t
);
3128 ool
= (typeof(ool
))desc
;
3129 copy
= (vm_map_copy_t
) ool
->address
;
3131 vm_map_copy_discard(copy
);
3139 if (-1UL == descsize
) {
3142 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
3145 return kIOReturnBadArgument
;
3149 IOUserServer::copyInObjects(IORPCMessageMach
* mach
, IORPCMessage
* message
,
3150 size_t size
, bool copyObjects
, bool consumePorts
)
3153 uint32_t idx
, maxObjectCount
;
3157 mach_msg_port_descriptor_t
* desc
;
3158 mach_msg_ool_descriptor_t
* ool
;
3159 vm_map_address_t copyoutdata
;
3162 refs
= message
->objectRefs
;
3163 maxObjectCount
= MAX_OBJECT_COUNT(mach
, size
, message
);
3164 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
3165 // assert(refs <= maxObjectCount);
3166 if (refs
> mach
->msgh_body
.msgh_descriptor_count
) {
3167 return kIOReturnBadArgument
;
3169 if (refs
> maxObjectCount
) {
3170 return kIOReturnBadArgument
;
3173 desc
= &mach
->objects
[0];
3174 for (idx
= 0; idx
< refs
; idx
++) {
3175 switch (desc
->type
) {
3176 case MACH_MSG_PORT_DESCRIPTOR
:
3177 descsize
= sizeof(mach_msg_port_descriptor_t
);
3183 object
= copyObjectForSendRight(port
, IKOT_UEXT_OBJECT
);
3190 ipc_port_release_send(port
);
3195 case MACH_MSG_OOL_DESCRIPTOR
:
3196 descsize
= sizeof(mach_msg_ool_descriptor_t
);
3197 ool
= (typeof(ool
))desc
;
3200 if (copyObjects
&& ool
->size
&& ool
->address
) {
3201 kr
= vm_map_copyout(kernel_map
, ©outdata
, (vm_map_copy_t
) ool
->address
);
3202 if (KERN_SUCCESS
== kr
) {
3203 object
= OSUnserializeXML((const char *) copyoutdata
, ool
->size
);
3204 // vm_map_copyout() has consumed the vm_map_copy_t in the message
3206 ool
->address
= NULL
;
3207 kr
= vm_deallocate(kernel_map
, copyoutdata
, ool
->size
);
3208 assert(KERN_SUCCESS
== kr
);
3221 if (-1UL == descsize
) {
3225 message
->objects
[idx
] = (OSObjectRef
) object
;
3227 desc
= (typeof(desc
))(((uintptr_t) desc
) + descsize
);
3231 return kIOReturnSuccess
;
3235 object
= (OSObject
*) message
->objects
[idx
];
3237 message
->objects
[idx
] = 0;
3240 return kIOReturnBadArgument
;
3244 IOUserServer::consumeObjects(IORPCMessage
* message
, size_t messageSize
)
3249 refs
= message
->objectRefs
;
3250 for (idx
= 0; idx
< refs
; idx
++) {
3251 object
= (OSObject
*) message
->objects
[idx
];
3254 message
->objects
[idx
] = 0;
3258 return kIOReturnSuccess
;
3261 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3264 IOUserServer::finalize(IOOptionBits options
)
3268 if (kIODKLogSetup
& gIODKDebug
) {
3269 DKLOG("%s::finalize(%p)\n", getName(), this);
3272 IOLockLock(gIOUserServerLock
);
3273 OSSafeReleaseNULL(fRootQueue
);
3274 IOLockUnlock(gIOUserServerLock
);
3279 services
= OSArray::withArray(fServices
);
3281 IOLockUnlock(fLock
);
3284 services
->iterateObjects(^bool (OSObject
* obj
) {
3285 IOService
* service
;
3286 IOService
* provider
;
3287 bool started
= false;
3289 service
= (IOService
*) obj
;
3290 if (kIODKLogSetup
& gIODKDebug
) {
3291 DKLOG("%s::terminate(" DKS
")\n", getName(), DKN(service
));
3293 if (service
->reserved
->uvars
) {
3294 started
= service
->reserved
->uvars
->started
;
3295 service
->reserved
->uvars
->serverDied
= true;
3297 provider
= service
->getProvider();
3298 serviceDidStop(service
, provider
);
3299 service
->terminate(kIOServiceTerminateNeedWillTerminate
| kIOServiceTerminateWithRematch
);
3303 DKLOG("%s::terminate(" DKS
") server exit before start()\n", getName(), DKN(service
));
3304 serviceStop(service
, NULL
);
3308 services
->release();
3311 return IOUserClient::finalize(options
);
3314 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3317 #define super IOUserClient
3319 OSDefineMetaClassAndStructors(IOUserServer
, IOUserClient
)
3321 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3323 IOUserClient
* IOUserServer::withTask(task_t owningTask
)
3325 IOUserServer
* inst
;
3327 inst
= new IOUserServer
;
3328 if (inst
&& !inst
->init()) {
3335 inst
->fOwningTask
= current_task();
3336 inst
->fEntitlements
= IOUserClient::copyClientEntitlements(inst
->fOwningTask
);
3338 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
3339 if (!inst
->fEntitlements
|| !inst
->fEntitlements
->getObject(gIODriverKitEntitlementKey
)) {
3343 p
= (proc_t
)get_bsdtask_info(inst
->fOwningTask
);
3346 IOLog(kIODriverKitEntitlementKey
" entitlement check failed for %s[%d]\n", proc_best_name(p
), pid
);
3354 /* Mark the current task's space as eligible for uext object ports */
3355 iokit_label_dext_task(inst
->fOwningTask
);
3357 inst
->fLock
= IOLockAlloc();
3358 inst
->fServices
= OSArray::withCapacity(4);
3359 inst
->fClasses
= OSDictionary::withCapacity(16);
3360 inst
->fClasses
->setOptions(OSCollection::kSort
, OSCollection::kSort
);
3366 IOUserServer::clientClose(void)
3370 if (kIODKLogSetup
& gIODKDebug
) {
3371 DKLOG("%s::clientClose(%p)\n", getName(), this);
3377 services
= OSArray::withArray(fServices
);
3379 IOLockUnlock(fLock
);
3381 // if this was a an expected exit, termination and stop should have detached at this
3382 // point, so send any provider still attached and not owned by this user server
3383 // the ClientCrashed() notification
3385 services
->iterateObjects(^bool (OSObject
* obj
) {
3386 IOService
* service
;
3387 IOService
* provider
;
3389 service
= (IOService
*) obj
;
3390 if (service
->isInactive()) {
3393 provider
= service
->getProvider();
3395 && (!provider
->reserved
->uvars
|| (provider
->reserved
->uvars
->userServer
!= this))) {
3396 if (kIODKLogSetup
& gIODKDebug
) {
3397 DKLOG(DKS
"::ClientCrashed(" DKS
")\n", DKN(provider
), DKN(service
));
3399 provider
->ClientCrashed(service
, 0);
3403 services
->release();
3407 return kIOReturnSuccess
;
3411 IOUserServer::setProperties(OSObject
* properties
)
3413 IOReturn kr
= kIOReturnUnsupported
;
3418 IOUserServer::stop(IOService
* provider
)
3420 fOwningTask
= TASK_NULL
;
3424 IOServicePH::serverRemove(this);
3426 OSSafeReleaseNULL(fRootQueue
);
3428 if (fInterruptLock
) {
3429 IOSimpleLockFree(fInterruptLock
);
3434 IOUserServer::free()
3436 OSSafeReleaseNULL(fEntitlements
);
3437 OSSafeReleaseNULL(fClasses
);
3441 OSSafeReleaseNULL(fServices
);
3442 OSSafeReleaseNULL(fCheckInToken
);
3443 IOUserClient::free();
3447 IOUserServer::registerClass(OSClassDescription
* desc
, uint32_t size
, OSUserMetaClass
** pCls
)
3449 OSUserMetaClass
* cls
;
3450 const OSSymbol
* sym
;
3451 uint64_t * methodOptions
;
3452 const char * queueNames
;
3453 uint32_t methodOptionsEnd
, queueNamesEnd
;
3454 IOReturn ret
= kIOReturnSuccess
;
3456 if (size
< sizeof(OSClassDescription
)) {
3458 return kIOReturnBadArgument
;
3461 if (kIODKLogSetup
& gIODKDebug
) {
3462 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc
->name
, desc
->queueNamesSize
, desc
->methodNamesSize
);
3465 if (desc
->descriptionSize
!= size
) {
3467 return kIOReturnBadArgument
;
3469 if (os_add_overflow(desc
->queueNamesOffset
, desc
->queueNamesSize
, &queueNamesEnd
)) {
3471 return kIOReturnBadArgument
;
3473 if (queueNamesEnd
> size
) {
3475 return kIOReturnBadArgument
;
3477 if (os_add_overflow(desc
->methodOptionsOffset
, desc
->methodOptionsSize
, &methodOptionsEnd
)) {
3479 return kIOReturnBadArgument
;
3481 if (methodOptionsEnd
> size
) {
3483 return kIOReturnBadArgument
;
3486 if ((desc
->queueNamesOffset
>= desc
->methodOptionsOffset
) && (desc
->queueNamesOffset
< methodOptionsEnd
)) {
3488 return kIOReturnBadArgument
;
3490 if ((queueNamesEnd
>= desc
->methodOptionsOffset
) && (queueNamesEnd
< methodOptionsEnd
)) {
3492 return kIOReturnBadArgument
;
3495 if (desc
->methodOptionsSize
& ((2 * sizeof(uint64_t)) - 1)) {
3497 return kIOReturnBadArgument
;
3499 if (sizeof(desc
->name
) == strnlen(desc
->name
, sizeof(desc
->name
))) {
3501 return kIOReturnBadArgument
;
3503 if (sizeof(desc
->superName
) == strnlen(desc
->superName
, sizeof(desc
->superName
))) {
3505 return kIOReturnBadArgument
;
3508 cls
= OSTypeAlloc(OSUserMetaClass
);
3511 return kIOReturnNoMemory
;
3514 cls
->description
= (typeof(cls
->description
))IOMalloc(size
);
3515 assert(cls
->description
);
3516 if (!cls
->description
) {
3519 return kIOReturnNoMemory
;
3521 bcopy(desc
, cls
->description
, size
);
3523 cls
->methodCount
= desc
->methodOptionsSize
/ (2 * sizeof(uint64_t));
3524 cls
->methods
= IONew(uint64_t, 2 * cls
->methodCount
);
3525 if (!cls
->methods
) {
3528 return kIOReturnNoMemory
;
3531 methodOptions
= (typeof(methodOptions
))(((uintptr_t) desc
) + desc
->methodOptionsOffset
);
3532 bcopy(methodOptions
, cls
->methods
, 2 * cls
->methodCount
* sizeof(uint64_t));
3534 queueNames
= (typeof(queueNames
))(((uintptr_t) desc
) + desc
->queueNamesOffset
);
3535 cls
->queueNames
= copyInStringArray(queueNames
, desc
->queueNamesSize
);
3537 sym
= OSSymbol::withCString(desc
->name
);
3542 return kIOReturnNoMemory
;
3546 cls
->meta
= OSMetaClass::copyMetaClassWithName(sym
);
3548 cls
->superMeta
= OSDynamicCast(OSUserMetaClass
, fClasses
->getObject(desc
->superName
));
3549 if (fClasses
->getObject(sym
) != NULL
) {
3550 /* class with this name exists */
3551 ret
= kIOReturnBadArgument
;
3553 if (fClasses
->setObject(sym
, cls
)) {
3556 /* could not add class to fClasses */
3557 ret
= kIOReturnNoMemory
;
3560 IOLockUnlock(fLock
);
3566 IOUserServer::registerClass(OSClassDescription
* desc
, uint32_t size
, OSSharedPtr
<OSUserMetaClass
>& pCls
)
3568 OSUserMetaClass
* pClsRaw
= NULL
;
3569 IOReturn result
= registerClass(desc
, size
, &pClsRaw
);
3570 if (result
== kIOReturnSuccess
) {
3571 pCls
.reset(pClsRaw
, OSRetain
);
3577 IOUserServer::setRootQueue(IODispatchQueue
* queue
)
3579 assert(!fRootQueue
);
3581 return kIOReturnStillOpen
;
3586 return kIOReturnSuccess
;
3590 IOUserServer::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
3591 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
3593 IOReturn ret
= kIOReturnBadArgument
;
3594 mach_port_name_t portname
;
3597 case kIOUserServerMethodRegisterClass
:
3599 OSUserMetaClass
* cls
;
3600 if (!args
->structureInputSize
) {
3601 return kIOReturnBadArgument
;
3603 if (args
->scalarOutputCount
!= 2) {
3604 return kIOReturnBadArgument
;
3606 ret
= registerClass((OSClassDescription
*) args
->structureInput
, args
->structureInputSize
, &cls
);
3607 if (kIOReturnSuccess
== ret
) {
3608 portname
= iokit_make_send_right(fOwningTask
, cls
, IKOT_UEXT_OBJECT
);
3610 args
->scalarOutput
[0] = portname
;
3611 args
->scalarOutput
[1] = kOSObjectRPCRemote
;
3615 case kIOUserServerMethodStart
:
3617 if (args
->scalarOutputCount
!= 1) {
3618 return kIOReturnBadArgument
;
3620 if (!(kIODKDisableCheckInTokenVerification
& gIODKDebug
)) {
3621 if (args
->scalarInputCount
!= 1) {
3622 return kIOReturnBadArgument
;
3624 mach_port_name_t checkInPortName
= ((typeof(checkInPortName
))args
->scalarInput
[0]);
3625 OSObject
* obj
= iokit_lookup_object_with_port_name(checkInPortName
, IKOT_IOKIT_IDENT
, fOwningTask
);
3626 IOUserServerCheckInToken
* retrievedToken
= OSDynamicCast(IOUserServerCheckInToken
, obj
);
3627 if (retrievedToken
!= NULL
) {
3628 setCheckInToken(retrievedToken
);
3630 OSSafeReleaseNULL(obj
);
3631 return kIOReturnBadArgument
;
3633 OSSafeReleaseNULL(obj
);
3635 portname
= iokit_make_send_right(fOwningTask
, this, IKOT_UEXT_OBJECT
);
3637 args
->scalarOutput
[0] = portname
;
3638 ret
= kIOReturnSuccess
;
3649 IOUserServer::getTargetAndTrapForIndex( IOService
**targetP
, UInt32 index
)
3651 static const IOExternalTrap trapTemplate
[] = {
3652 { NULL
, (IOTrap
) & IOUserServer::waitInterruptTrap
},
3654 if (index
>= (sizeof(trapTemplate
) / sizeof(IOExternalTrap
))) {
3658 return (IOExternalTrap
*)&trapTemplate
[index
];
3661 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3664 IOUserServer::serviceAttach(IOService
* service
, IOService
* provider
)
3667 OSObjectUserVars
* vars
;
3670 OSSymbol
const* bundleID
;
3671 char execPath
[1024];
3673 vars
= IONewZero(OSObjectUserVars
, 1);
3674 service
->reserved
->uvars
= vars
;
3676 vars
->userServer
= this;
3677 vars
->userServer
->retain();
3679 if (-1U == fServices
->getNextIndexOfObject(service
, 0)) {
3680 fServices
->setObject(service
);
3682 IOLockUnlock(fLock
);
3684 prop
= service
->copyProperty(gIOUserClassKey
);
3685 str
= OSDynamicCast(OSString
, prop
);
3687 service
->setName(str
);
3689 OSSafeReleaseNULL(prop
);
3691 prop
= service
->copyProperty(gIOModuleIdentifierKey
);
3692 bundleID
= OSDynamicCast(OSSymbol
, prop
);
3695 bool ok
= OSKext::copyUserExecutablePath(bundleID
, execPath
, sizeof(execPath
));
3697 ret
= LoadModule(execPath
);
3698 if (kIODKLogSetup
& gIODKDebug
) {
3699 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret
, execPath
);
3703 OSSafeReleaseNULL(prop
);
3705 ret
= kIOReturnSuccess
;
3710 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3712 #define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
3715 IOUserServer::serviceNewUserClient(IOService
* service
, task_t owningTask
, void * securityID
,
3716 uint32_t type
, OSDictionary
* properties
, IOUserClient
** handler
)
3720 IOUserUserClient
* userUC
;
3721 OSDictionary
* entitlements
;
3723 OSObject
* bundleID
;
3727 ret
= service
->NewUserClient(type
, &uc
);
3728 if (kIOReturnSuccess
!= ret
) {
3731 userUC
= OSDynamicCast(IOUserUserClient
, uc
);
3734 OSSafeReleaseNULL(uc
);
3735 return kIOReturnUnsupported
;
3737 userUC
->setTask(owningTask
);
3739 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
3741 entitlements
= IOUserClient::copyClientEntitlements(owningTask
);
3742 if (fEntitlements
&& fEntitlements
->getObject(gIODriverKitUserClientEntitlementAllowAnyKey
)) {
3745 bundleID
= service
->copyProperty(gIOModuleIdentifierKey
);
3748 && (prop
= entitlements
->getObject(gIODriverKitUserClientEntitlementsKey
)));
3750 bool found __block
= false;
3751 ok
= prop
->iterateObjects(^bool (OSObject
* object
) {
3752 found
= object
->isEqualTo(bundleID
);
3759 prop
= userUC
->copyProperty(gIOServiceDEXTEntitlementsKey
);
3760 ok
= checkEntitlements(entitlements
, prop
, NULL
, NULL
);
3762 OSSafeReleaseNULL(bundleID
);
3763 OSSafeReleaseNULL(entitlements
);
3765 DKLOG(DKS
":UC entitlements check failed\n", DKN(userUC
));
3767 OSSafeReleaseNULL(uc
);
3768 return kIOReturnNotPermitted
;
3778 IOUserServer::serviceNewUserClient(IOService
* service
, task_t owningTask
, void * securityID
,
3779 uint32_t type
, OSDictionary
* properties
, OSSharedPtr
<IOUserClient
>& handler
)
3781 IOUserClient
* handlerRaw
= NULL
;
3782 IOReturn result
= serviceNewUserClient(service
, owningTask
, securityID
, type
, properties
, &handlerRaw
);
3783 handler
.reset(handlerRaw
, OSNoRetain
);
3787 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3789 static IOPMPowerState
3791 { .version
= kIOPMPowerStateVersion1
,
3792 .capabilityFlags
= 0,
3793 .outputPowerCharacter
= 0,
3794 .inputPowerRequirement
= 0},
3795 { .version
= kIOPMPowerStateVersion1
,
3796 .capabilityFlags
= kIOPMLowPower
,
3797 .outputPowerCharacter
= kIOPMLowPower
,
3798 .inputPowerRequirement
= kIOPMLowPower
},
3799 { .version
= kIOPMPowerStateVersion1
,
3800 .capabilityFlags
= kIOPMPowerOn
,
3801 .outputPowerCharacter
= kIOPMPowerOn
,
3802 .inputPowerRequirement
= kIOPMPowerOn
},
3806 IOUserServer::setPowerState(unsigned long state
, IOService
* service
)
3808 if (kIODKLogPM
& gIODKDebug
) {
3809 DKLOG(DKS
"::setPowerState(%ld) %d\n", DKN(service
), state
, fSystemPowerAck
);
3811 return kIOPMAckImplied
;
3815 IOUserServer::serviceSetPowerState(IOService
* controllingDriver
, IOService
* service
, IOPMPowerFlags flags
, unsigned long state
)
3819 if (service
->reserved
->uvars
) {
3820 if (!fSystemOff
&& !(kIODKDisablePM
& gIODKDebug
)) {
3821 service
->reserved
->uvars
->willPower
= true;
3822 service
->reserved
->uvars
->willPowerState
= state
;
3823 service
->reserved
->uvars
->controllingDriver
= controllingDriver
;
3824 if (kIODKLogPM
& gIODKDebug
) {
3825 DKLOG(DKS
"::serviceSetPowerState(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
3827 ret
= service
->SetPowerState((uint32_t) flags
);
3828 if (kIOReturnSuccess
== ret
) {
3829 return 20 * 1000 * 1000;
3832 service
->reserved
->uvars
->willPower
= false;
3835 return kIOPMAckImplied
;
3839 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
3841 return kIOPMAckImplied
;
3845 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags
, unsigned long state
, IOService
* service
)
3852 idx
= fServices
->getNextIndexOfObject(service
, 0);
3854 IOLockUnlock(fLock
);
3855 return kIOPMAckImplied
;
3860 fPowerStates
|= (1ULL << idx
);
3862 fPowerStates
&= ~(1ULL << idx
);
3864 if (kIODKLogPM
& gIODKDebug
) {
3865 DKLOG(DKS
"::powerStateDidChangeTo(%ld) 0x%qx, %d\n", DKN(service
), state
, fPowerStates
, fSystemPowerAck
);
3867 if (!fPowerStates
&& (pmAck
= fSystemPowerAck
)) {
3868 fSystemPowerAck
= false;
3871 IOLockUnlock(fLock
);
3874 IOServicePH::serverAck(this);
3877 return kIOPMAckImplied
;
3881 IOService::SetPowerState_Impl(
3882 uint32_t powerFlags
)
3884 if (kIODKLogPM
& gIODKDebug
) {
3885 DKLOG(DKS
"::SetPowerState(%d), %d\n", DKN(this), powerFlags
, reserved
->uvars
->willPower
);
3888 && reserved
->uvars
->userServer
3889 && reserved
->uvars
->willPower
) {
3891 reserved
->uvars
->willPower
= false;
3892 ret
= reserved
->uvars
->controllingDriver
->setPowerState(reserved
->uvars
->willPowerState
, this);
3893 if (kIOPMAckImplied
== ret
) {
3894 acknowledgeSetPowerState();
3896 return kIOReturnSuccess
;
3898 return kIOReturnNotReady
;
3902 IOService::ChangePowerState_Impl(
3903 uint32_t powerFlags
)
3905 switch (powerFlags
) {
3906 case kIOServicePowerCapabilityOff
:
3907 changePowerStateToPriv(0);
3909 case kIOServicePowerCapabilityLow
:
3910 changePowerStateToPriv(1);
3912 case kIOServicePowerCapabilityOn
:
3913 changePowerStateToPriv(2);
3916 return kIOReturnBadArgument
;
3919 return kIOReturnSuccess
;
3923 IOService::Create_Impl(
3924 IOService
* provider
,
3925 const char * propertiesKey
,
3926 IOService
** result
)
3929 IOService
* service
;
3931 const OSSymbol
* sym
;
3933 OSDictionary
* properties
;
3936 if (provider
!= this) {
3937 return kIOReturnUnsupported
;
3940 ret
= kIOReturnUnsupported
;
3944 prop
= copyProperty(propertiesKey
);
3945 properties
= OSDynamicCast(OSDictionary
, prop
);
3948 str
= OSDynamicCast(OSString
, properties
->getObject(gIOClassKey
));
3950 sym
= OSSymbol::withString(str
);
3952 inst
= OSMetaClass::allocClassWithName(sym
);
3953 service
= OSDynamicCast(IOService
, inst
);
3954 if (service
&& service
->init(properties
) && service
->attach(this)) {
3955 reserved
->uvars
->userServer
->serviceAttach(service
, this);
3956 service
->reserved
->uvars
->started
= true;
3957 ret
= kIOReturnSuccess
;
3960 OSSafeReleaseNULL(sym
);
3964 OSSafeReleaseNULL(prop
);
3965 if (kIOReturnSuccess
!= ret
) {
3966 OSSafeReleaseNULL(inst
);
3973 IOService::Terminate_Impl(
3979 return kIOReturnUnsupported
;
3982 us
= (typeof(us
))thread_iokit_tls_get(0);
3983 if (!reserved
->uvars
3984 || (reserved
->uvars
->userServer
!= us
)) {
3985 return kIOReturnNotPermitted
;
3987 terminate(kIOServiceTerminateNeedWillTerminate
);
3989 return kIOReturnSuccess
;
3993 IOService::NewUserClient_Impl(
3995 IOUserClient
** userClient
)
3997 return kIOReturnError
;
4001 IOService::SearchProperty_Impl(
4005 OSContainer
** property
)
4008 IOOptionBits regOptions
;
4010 if (kIOServiceSearchPropertyParents
& options
) {
4011 regOptions
= kIORegistryIterateParents
| kIORegistryIterateRecursively
;
4016 object
= copyProperty(name
, IORegistryEntry::getPlane(plane
), regOptions
);
4019 return object
? kIOReturnSuccess
: kIOReturnNotFound
;
4023 IOService::CopyProviderProperties_Impl(
4024 OSArray
* propertyKeys
,
4025 OSArray
** properties
)
4029 IOService
* provider
;
4031 result
= OSArray::withCapacity(8);
4033 return kIOReturnNoMemory
;
4036 ret
= kIOReturnSuccess
;
4037 for (provider
= this; provider
; provider
= provider
->getProvider()) {
4039 OSDictionary
* props
;
4041 obj
= provider
->copyProperty(gIOSupportedPropertiesKey
);
4042 props
= OSDynamicCast(OSDictionary
, obj
);
4044 OSSafeReleaseNULL(obj
);
4045 props
= provider
->dictionaryWithProperties();
4048 ret
= kIOReturnNoMemory
;
4051 bool __block addClass
= true;
4053 OSDictionary
* retProps
;
4054 retProps
= OSDictionary::withCapacity(4);
4057 ret
= kIOReturnNoMemory
;
4060 propertyKeys
->iterateObjects(^bool (OSObject
* _key
) {
4061 OSString
* key
= OSDynamicCast(OSString
, _key
);
4062 if (gIOClassKey
->isEqualTo(key
)) {
4066 retProps
->setObject(key
, props
->getObject(key
));
4069 OSSafeReleaseNULL(props
);
4073 OSArray
* classes
= OSArray::withCapacity(8);
4075 ret
= kIOReturnNoMemory
;
4078 for (const OSMetaClass
* meta
= provider
->getMetaClass(); meta
; meta
= meta
->getSuperClass()) {
4079 classes
->setObject(meta
->getClassNameSymbol());
4081 props
->setObject(gIOClassKey
, classes
);
4082 OSSafeReleaseNULL(classes
);
4084 bool ok
= result
->setObject(props
);
4087 ret
= kIOReturnNoMemory
;
4091 if (kIOReturnSuccess
!= ret
) {
4092 OSSafeReleaseNULL(result
);
4094 *properties
= result
;
4099 IOUserServer::systemPower(bool powerOff
)
4103 if (kIODKLogPM
& gIODKDebug
) {
4104 DKLOG("%s::powerOff(%d) 0x%qx\n", getName(), powerOff
, fPowerStates
);
4108 services
= OSArray::withArray(fServices
);
4111 fSystemPowerAck
= (0 != fPowerStates
);
4112 if (!fSystemPowerAck
) {
4115 IOLockUnlock(fLock
);
4117 if (!fSystemPowerAck
) {
4118 IOServicePH::serverAck(this);
4121 services
->iterateObjects(^bool (OSObject
* obj
) {
4122 IOService
* service
;
4123 service
= (IOService
*) obj
;
4124 if (kIODKLogPM
& gIODKDebug
) {
4125 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), 0);
4127 service
->reserved
->uvars
->powerOverride
= service
->getPowerState();
4128 service
->changePowerStateWithOverrideTo(0, 0);
4135 IOLockUnlock(fLock
);
4137 services
->iterateObjects(^bool (OSObject
* obj
) {
4138 IOService
* service
;
4139 service
= (IOService
*) obj
;
4140 if (-1U != service
->reserved
->uvars
->powerOverride
) {
4141 if (kIODKLogPM
& gIODKDebug
) {
4142 DKLOG("changePowerStateWithOverrideTo(" DKS
", %d)\n", DKN(service
), service
->reserved
->uvars
->powerOverride
);
4144 service
->changePowerStateWithOverrideTo(service
->reserved
->uvars
->powerOverride
, 0);
4145 service
->reserved
->uvars
->powerOverride
= -1U;
4151 OSSafeReleaseNULL(services
);
4156 IOUserServer::systemHalt(void)
4160 if (true || (kIODKLogPM
& gIODKDebug
)) {
4161 DKLOG("%s::systemHalt()\n", getName());
4165 services
= OSArray::withArray(fServices
);
4166 IOLockUnlock(fLock
);
4169 services
->iterateObjects(^bool (OSObject
* obj
) {
4170 IOService
* service
;
4171 IOService
* provider
;
4172 IOOptionBits terminateOptions
;
4175 service
= (IOService
*) obj
;
4176 provider
= service
->getProvider();
4178 DKLOG("stale service " DKS
" found, skipping termination\n", DKN(service
));
4181 root
= (NULL
== provider
->getProperty(gIOUserServerNameKey
, gIOServicePlane
));
4182 if (true || (kIODKLogPM
& gIODKDebug
)) {
4183 DKLOG("%d: terminate(" DKS
")\n", root
, DKN(service
));
4188 terminateOptions
= kIOServiceRequired
| kIOServiceTerminateNeedWillTerminate
;
4189 if (!service
->terminate(terminateOptions
)) {
4190 IOLog("failed to terminate service %s-0x%llx\n", service
->getName(), service
->getRegistryEntryID());
4195 OSSafeReleaseNULL(services
);
4199 IOUserServer::serviceStarted(IOService
* service
, IOService
* provider
, bool result
)
4202 IOService
* pmProvider
;
4205 DKLOG(DKS
"::start(" DKS
") %s\n", DKN(service
), DKN(provider
), result
? "ok" : "fail");
4208 ret
= kIOReturnSuccess
;
4212 if (!fRootNotifier
) {
4213 ret
= registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
4214 assert(kIOReturnSuccess
== ret
);
4215 IOServicePH::serverAdd(this);
4216 fRootNotifier
= true;
4220 if (!(kIODKDisablePM
& gIODKDebug
) && !service
->pm_vars
) {
4222 ret
= service
->registerPowerDriver(this, sPowerStates
, sizeof(sPowerStates
) / sizeof(sPowerStates
[0]));
4223 assert(kIOReturnSuccess
== ret
);
4227 pmProvider
= service
;
4228 while (pmProvider
&& !pmProvider
->inPlane(gIOPowerPlane
)) {
4229 pmProvider
= pmProvider
->getProvider();
4234 OSObject
* nextProp
;
4240 nextProp
= entry
->copyProperty("non-removable");
4242 OSSafeReleaseNULL(prop
);
4245 entry
= entry
->getProvider();
4248 str
= OSDynamicCast(OSString
, prop
);
4249 if (str
&& str
->isEqualTo("yes")) {
4256 if (!(kIODKDisablePM
& gIODKDebug
) && pmProvider
) {
4258 unsigned int idx
= fServices
->getNextIndexOfObject(service
, 0);
4260 fPowerStates
|= (1ULL << idx
);
4261 IOLockUnlock(fLock
);
4264 pmProvider
->joinPMtree(service
);
4265 service
->reserved
->uvars
->userServerPM
= true;
4269 service
->registerInterestedDriver(this);
4270 service
->reserved
->uvars
->started
= true;
4272 return kIOReturnSuccess
;
4277 IOUserServer::serviceOpen(IOService
* provider
, IOService
* client
)
4279 OSObjectUserVars
* uvars
;
4281 uvars
= client
->reserved
->uvars
;
4282 if (!uvars
->openProviders
) {
4283 uvars
->openProviders
= OSArray::withObjects((const OSObject
**) &provider
, 1);
4284 } else if (-1U == uvars
->openProviders
->getNextIndexOfObject(client
, 0)) {
4285 uvars
->openProviders
->setObject(provider
);
4288 return kIOReturnSuccess
;
4292 IOUserServer::serviceClose(IOService
* provider
, IOService
* client
)
4294 OSObjectUserVars
* uvars
;
4297 uvars
= client
->reserved
->uvars
;
4298 if (!uvars
->openProviders
) {
4299 return kIOReturnNotOpen
;
4301 idx
= uvars
->openProviders
->getNextIndexOfObject(client
, 0);
4303 return kIOReturnNotOpen
;
4305 uvars
->openProviders
->removeObject(idx
);
4307 return kIOReturnSuccess
;
4312 IOUserServer::serviceStop(IOService
* service
, IOService
*)
4315 uint32_t idx
, queueAlloc
;
4316 OSObjectUserVars
* uvars
;
4319 idx
= fServices
->getNextIndexOfObject(service
, 0);
4321 fServices
->removeObject(idx
);
4322 uvars
= service
->reserved
->uvars
;
4323 uvars
->stopped
= true;
4325 IOLockUnlock(fLock
);
4328 return kIOReturnSuccess
;
4331 if (uvars
->queueArray
&& uvars
->userMeta
) {
4333 if (uvars
->userMeta
->queueNames
) {
4334 queueAlloc
+= uvars
->userMeta
->queueNames
->count
;
4336 for (idx
= 0; idx
< queueAlloc
; idx
++) {
4337 OSSafeReleaseNULL(uvars
->queueArray
[idx
]);
4339 IOSafeDeleteNULL(uvars
->queueArray
, IODispatchQueue
*, queueAlloc
);
4342 (void) service
->deRegisterInterestedDriver(this);
4343 if (uvars
->userServerPM
) {
4347 ret
= kIOReturnSuccess
;
4352 IOUserServer::serviceFree(IOService
* service
)
4354 OSObjectUserVars
* uvars
;
4356 uvars
= service
->reserved
->uvars
;
4360 OSSafeReleaseNULL(uvars
->userServer
);
4361 IOSafeDeleteNULL(service
->reserved
->uvars
, OSObjectUserVars
, 1);
4365 IOUserServer::serviceWillTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
)
4370 willTerminate
= false;
4371 if (client
->lockForArbitration(true)) {
4372 if (!client
->reserved
->uvars
->serverDied
4373 && !client
->reserved
->uvars
->willTerminate
) {
4374 client
->reserved
->uvars
->willTerminate
= true;
4375 willTerminate
= true;
4377 client
->unlockForArbitration();
4380 if (willTerminate
) {
4381 if ((true) || IOServicePH::serverSlept()) {
4382 client
->Stop_async(provider
);
4383 ret
= kIOReturnOffline
;
4385 ret
= client
->Stop(provider
);
4387 if (kIOReturnSuccess
!= ret
) {
4388 IOUserServer::serviceDidStop(client
, provider
);
4389 ret
= kIOReturnSuccess
;
4395 IOUserServer::serviceDidTerminate(IOService
* client
, IOService
* provider
, IOOptionBits options
, bool * defer
)
4397 if (client
->lockForArbitration(true)) {
4398 client
->reserved
->uvars
->didTerminate
= true;
4399 if (!client
->reserved
->uvars
->serverDied
4400 && !client
->reserved
->uvars
->stopped
) {
4403 client
->unlockForArbitration();
4408 IOUserServer::serviceDidStop(IOService
* client
, IOService
* provider
)
4411 OSArray
* closeArray
;
4416 if (client
->lockForArbitration(true)) {
4417 if (client
->reserved
->uvars
4418 && client
->reserved
->uvars
->willTerminate
4419 && !client
->reserved
->uvars
->stopped
) {
4420 client
->reserved
->uvars
->stopped
= true;
4421 complete
= client
->reserved
->uvars
->didTerminate
;
4424 if (client
->reserved
->uvars
) {
4425 closeArray
= client
->reserved
->uvars
->openProviders
;
4426 client
->reserved
->uvars
->openProviders
= NULL
;
4428 client
->unlockForArbitration();
4430 closeArray
->iterateObjects(^bool (OSObject
* obj
) {
4431 IOService
* toClose
;
4432 toClose
= OSDynamicCast(IOService
, obj
);
4434 DKLOG(DKS
":force close (" DKS
")\n", DKN(client
), DKN(toClose
));
4435 toClose
->close(client
);
4439 closeArray
->release();
4444 client
->didTerminate(provider
, 0, &defer
);
4449 IOService::ClientCrashed_Impl(
4453 return kIOReturnUnsupported
;
4457 IOService::Stop_Impl(
4458 IOService
* provider
)
4460 IOUserServer::serviceDidStop(this, provider
);
4462 return kIOReturnSuccess
;
4466 IOService::Stop_async_Impl(
4467 IOService
* provider
)
4471 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4474 #define super IOUserClient
4476 OSDefineMetaClassAndStructors(IOUserUserClient
, IOUserClient
)
4478 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4481 IOUserUserClient::setTask(task_t task
)
4483 task_reference(task
);
4486 return kIOReturnSuccess
;
4490 IOUserUserClient::stop(IOService
* provider
)
4493 task_deallocate(fTask
);
4496 super::stop(provider
);
4500 IOUserUserClient::clientClose(void)
4502 terminate(kIOServiceTerminateNeedWillTerminate
);
4503 return kIOReturnSuccess
;
4507 IOUserUserClient::setProperties(OSObject
* properties
)
4509 IOReturn ret
= kIOReturnUnsupported
;
4513 struct IOUserUserClientActionRef
{
4514 OSAsyncReference64 asyncRef
;
4518 IOUserClient::KernelCompletion_Impl(
4521 const unsigned long long * asyncData
,
4522 uint32_t asyncDataCount
)
4524 IOUserUserClientActionRef
* ref
;
4526 ref
= (typeof(ref
))action
->GetReference();
4528 IOUserClient::sendAsyncResult64(ref
->asyncRef
, status
, (io_user_reference_t
*) asyncData
, asyncDataCount
);
4532 IOUserClient::_ExternalMethod_Impl(
4534 const unsigned long long * scalarInput
,
4535 uint32_t scalarInputCount
,
4536 OSData
* structureInput
,
4537 IOMemoryDescriptor
* structureInputDescriptor
,
4538 unsigned long long * scalarOutput
,
4539 uint32_t * scalarOutputCount
,
4540 uint64_t structureOutputMaximumSize
,
4541 OSData
** structureOutput
,
4542 IOMemoryDescriptor
* structureOutputDescriptor
,
4543 OSAction
* completion
)
4545 return kIOReturnUnsupported
;
4549 IOUserUserClient::clientMemoryForType(UInt32 type
,
4550 IOOptionBits
* koptions
,
4551 IOMemoryDescriptor
** kmemory
)
4555 IOMemoryDescriptor
* memory
;
4557 kr
= CopyClientMemoryForType(type
, &options
, &memory
);
4561 if (kIOReturnSuccess
!= kr
) {
4565 if (kIOUserClientMemoryReadOnly
& options
) {
4566 *koptions
|= kIOMapReadOnly
;
4574 IOUserUserClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
4575 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
4578 OSData
* structureInput
;
4579 OSData
* structureOutput
;
4581 uint64_t structureOutputSize
;
4583 IOUserUserClientActionRef
* ref
;
4585 kr
= kIOReturnUnsupported
;
4586 structureInput
= NULL
;
4590 if (args
->structureInputSize
) {
4591 structureInput
= OSData::withBytesNoCopy((void *) args
->structureInput
, args
->structureInputSize
);
4594 if (MACH_PORT_NULL
!= args
->asyncWakePort
) {
4595 // this retain is for the OSAction to release
4596 iokit_make_port_send(args
->asyncWakePort
);
4597 kr
= CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef
), &action
);
4598 assert(KERN_SUCCESS
== kr
);
4599 ref
= (typeof(ref
))action
->GetReference();
4600 bcopy(args
->asyncReference
, &ref
->asyncRef
[0], args
->asyncReferenceCount
* sizeof(ref
->asyncRef
[0]));
4601 kr
= action
->SetAbortedHandler(^(void) {
4602 IOUserUserClientActionRef
* ref
;
4605 ref
= (typeof(ref
))action
->GetReference();
4606 ret
= releaseAsyncReference64(ref
->asyncRef
);
4607 assert(kIOReturnSuccess
== ret
);
4608 bzero(&ref
->asyncRef
[0], sizeof(ref
->asyncRef
));
4610 assert(KERN_SUCCESS
== kr
);
4613 if (args
->structureVariableOutputData
) {
4614 structureOutputSize
= kIOUserClientVariableStructureSize
;
4615 } else if (args
->structureOutputDescriptor
) {
4616 structureOutputSize
= args
->structureOutputDescriptor
->getLength();
4618 structureOutputSize
= args
->structureOutputSize
;
4621 kr
= _ExternalMethod(selector
, &args
->scalarInput
[0], args
->scalarInputCount
,
4622 structureInput
, args
->structureInputDescriptor
,
4623 args
->scalarOutput
, &args
->scalarOutputCount
,
4624 structureOutputSize
, &structureOutput
, args
->structureOutputDescriptor
,
4627 OSSafeReleaseNULL(structureInput
);
4628 OSSafeReleaseNULL(action
);
4630 if (kIOReturnSuccess
!= kr
) {
4631 // mig will destroy any async port
4634 if (MACH_PORT_NULL
!= args
->asyncWakePort
) {
4635 // this release is for the mig created send right
4636 iokit_release_port_send(args
->asyncWakePort
);
4639 if (structureOutput
) {
4640 if (args
->structureVariableOutputData
) {
4641 *args
->structureVariableOutputData
= structureOutput
;
4643 copylen
= structureOutput
->getLength();
4644 if (copylen
> args
->structureOutputSize
) {
4645 kr
= kIOReturnBadArgument
;
4647 bcopy((const void *) structureOutput
->getBytesNoCopy(), args
->structureOutput
, copylen
);
4649 OSSafeReleaseNULL(structureOutput
);
4656 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4659 IOUserServerCheckInToken::setNoSendersNotification(IOUserServerCheckInNotificationHandler handler
,
4662 this->handler
= handler
;
4663 this->handlerArgs
= handlerArgs
;
4667 IOUserServerCheckInToken::notifyNoSenders(IOUserServerCheckInToken
*token
)
4669 if (token
->handler
) {
4670 token
->handler(token
, token
->handlerArgs
);
4675 IOUserServerCheckInToken::clearNotification()
4677 this->handler
= NULL
;
4678 this->handlerArgs
= NULL
;
4681 IOUserServerCheckInToken
*
4682 IOUserServerCheckInToken::create()
4684 IOUserServerCheckInToken
*me
= new IOUserServerCheckInToken
;
4685 if (me
&& !me
->init()) {
4689 me
->clearNotification();
4693 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */