]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOUserServer.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserServer.cpp
CommitLineData
cb323159
A
1/*
2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
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>
f427ee49
A
38#include <IOKit/IOSubMemoryDescriptor.h>
39#include <IOKit/IOMultiMemoryDescriptor.h>
eb6b6ca3 40#include <IOKit/IOMapper.h>
cb323159
A
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>
f427ee49 49#include <libkern/c++/OSSharedPtr.h>
cb323159
A
50#include <libkern/OSDebug.h>
51#include <libkern/Block.h>
52#include <sys/proc.h>
53#include "IOKitKernelInternal.h"
54
f427ee49 55/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
56
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>
ea3f0419 67#include <DriverKit/IOServiceNotificationDispatchSource.h>
cb323159
A
68#include <DriverKit/IOUserServer.h>
69
f427ee49 70/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
71
72#include <System/IODataQueueDispatchSourceShared.h>
73
f427ee49 74/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159 75
f427ee49 76SECURITY_READ_ONLY_LATE(SInt64) gIODKDebug = kIODKEnable;
cb323159 77
f427ee49 78/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
79
80struct IOPStrings;
81
82class OSUserMetaClass : public OSObject
83{
84 OSDeclareDefaultStructors(OSUserMetaClass);
85public:
86 const OSSymbol * name;
87 const OSMetaClass * meta;
88 OSUserMetaClass * superMeta;
89
90 queue_chain_t link;
91
92 OSClassDescription * description;
93 IOPStrings * queueNames;
94 uint32_t methodCount;
95 uint64_t * methods;
96
97 virtual void free() override;
98 virtual kern_return_t Dispatch(const IORPC rpc) APPLE_KEXT_OVERRIDE;
99};
100OSDefineMetaClassAndStructors(OSUserMetaClass, OSObject);
101
102/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
103
104class IOUserService : public IOService
105{
106 friend class IOService;
107
108 OSDeclareDefaultStructors(IOUserService)
109
110 virtual bool
111 start(IOService * provider) APPLE_KEXT_OVERRIDE;
cb323159
A
112};
113
114OSDefineMetaClassAndStructors(IOUserService, IOService)
115
116/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
117
118class IOUserUserClient : public IOUserClient
119{
120 OSDeclareDefaultStructors(IOUserUserClient);
121public:
122 task_t fTask;
123
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;
133};
134
f427ee49 135OSDefineMetaClassAndStructors(IOUserServerCheckInToken, OSObject);
cb323159
A
136
137/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
138
139
140bool
141IOUserService::start(IOService * provider)
142{
143 bool ok = true;
144 IOReturn ret;
145
146 ret = Start(provider);
147 if (kIOReturnSuccess != ret) {
148 return false;
149 }
150
151 return ok;
152}
153
f427ee49 154/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
155
156#undef super
157
f427ee49 158/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
159
160struct IODispatchQueue_IVars {
161 IOUserServer * userServer;
162 IODispatchQueue * queue;
163 queue_chain_t link;
164 uint64_t tid;
165
166 mach_port_t serverPort;
167};
168
169struct OSAction_IVars {
170 OSObject * target;
171 uint64_t targetmsgid;
172 uint64_t msgid;
173 OSActionAbortedHandler abortedHandler;
174 size_t referenceSize;
f427ee49 175 OSString * typeName;
cb323159
A
176 void * reference[0];
177};
178
f427ee49 179/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
180
181kern_return_t
f427ee49
A
182IOService::GetRegistryEntryID_Impl(
183 uint64_t * registryEntryID)
cb323159
A
184{
185 IOReturn ret = kIOReturnSuccess;
186
187 *registryEntryID = getRegistryEntryID();
188
189 return ret;
190}
191
192kern_return_t
f427ee49
A
193IOService::SetName_Impl(
194 const char * name)
cb323159
A
195{
196 IOReturn ret = kIOReturnSuccess;
197
198 setName(name);
199
200 return ret;
201}
202
203kern_return_t
f427ee49
A
204IOService::Start_Impl(
205 IOService * provider)
cb323159
A
206{
207 IOReturn ret = kIOReturnSuccess;
208 return ret;
209}
210
211kern_return_t
f427ee49 212IOService::RegisterService_Impl()
cb323159
A
213{
214 IOReturn ret = kIOReturnSuccess;
215
216 registerService();
217
218 return ret;
219}
220
221kern_return_t
f427ee49
A
222IOService::CopyDispatchQueue_Impl(
223 const char * name,
224 IODispatchQueue ** queue)
cb323159
A
225{
226 IODispatchQueue * result;
227 IOService * service;
228 IOReturn ret;
229 uint32_t index;
230
f427ee49
A
231 if (!reserved->uvars) {
232 return kIOReturnError;
233 }
234
cb323159
A
235 ret = kIOReturnNotFound;
236 index = -1U;
237 if (!strcmp("Default", name)) {
238 index = 0;
239 } else if (reserved->uvars->userMeta
240 && reserved->uvars->userMeta->queueNames) {
241 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
242 if (index != -1U) {
243 index++;
244 }
245 }
246 if (index == -1U) {
247 if ((service = getProvider())) {
248 ret = service->CopyDispatchQueue(name, queue);
249 }
250 } else {
251 result = reserved->uvars->queueArray[index];
252 if (result) {
253 result->retain();
254 *queue = result;
255 ret = kIOReturnSuccess;
256 }
257 }
258
259 return ret;
260}
261
262kern_return_t
f427ee49
A
263IOService::SetDispatchQueue_Impl(
264 const char * name,
265 IODispatchQueue * queue)
cb323159
A
266{
267 IOReturn ret = kIOReturnSuccess;
268 uint32_t index;
269
f427ee49
A
270 if (!reserved->uvars) {
271 return kIOReturnError;
272 }
273
cb323159
A
274 if (kIODKLogSetup & gIODKDebug) {
275 DKLOG(DKS "::SetDispatchQueue(%s)\n", DKN(this), name);
276 }
277 queue->ivars->userServer = reserved->uvars->userServer;
278 index = -1U;
279 if (!strcmp("Default", name)) {
280 index = 0;
281 } else if (reserved->uvars->userMeta
282 && reserved->uvars->userMeta->queueNames) {
283 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
284 if (index != -1U) {
285 index++;
286 }
287 }
288 if (index == -1U) {
289 ret = kIOReturnBadArgument;
290 } else {
291 reserved->uvars->queueArray[index] = queue;
292 queue->retain();
293 }
294
295 return ret;
296}
297
298kern_return_t
f427ee49
A
299IOService::SetProperties_Impl(
300 OSDictionary * properties)
cb323159 301{
ea3f0419
A
302 IOUserServer * us;
303 OSDictionary * dict;
304 IOReturn ret;
cb323159
A
305
306 ret = setProperties(properties);
307
ea3f0419
A
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;
314 IOReturn ret;
315
316 userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
317 if (userProps) {
318 userProps = (typeof(userProps))userProps->copyCollection();
319 } else {
320 userProps = OSDictionary::withCapacity(4);
321 }
322 if (!userProps) {
323 ret = kIOReturnNoMemory;
324 } else {
325 bool ok = userProps->merge(dict);
326 if (ok) {
327 ok = setProperty(gIOUserServicePropertiesKey, userProps);
328 }
329 OSSafeReleaseNULL(userProps);
330 ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
331 }
332 return ret;
333 });
334 }
335 }
336
cb323159
A
337 return ret;
338}
339
340kern_return_t
f427ee49
A
341IOService::CopyProperties_Impl(
342 OSDictionary ** properties)
cb323159
A
343{
344 IOReturn ret = kIOReturnSuccess;
345 *properties = dictionaryWithProperties();
346 return ret;
347}
348
f427ee49
A
349kern_return_t
350IOService::RequireMaxBusStall_Impl(
351 uint64_t u64ns)
352{
353 IOReturn ret;
354 UInt32 ns;
355
356 if (os_convert_overflow(u64ns, &ns)) {
357 return kIOReturnBadArgument;
358 }
359 ret = requireMaxBusStall(ns);
360
361 return kIOReturnSuccess;
362}
363
364/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
365
366kern_return_t
f427ee49
A
367IOMemoryDescriptor::_CopyState_Impl(
368 _IOMDPrivateState * state)
cb323159
A
369{
370 IOReturn ret;
371
372 state->length = _length;
373 state->options = _flags;
374
375 ret = kIOReturnSuccess;
376
377 return ret;
378}
379
380kern_return_t
381IOMemoryDescriptor::GetLength(uint64_t * returnLength)
382{
383 *returnLength = getLength();
384
385 return kIOReturnSuccess;
386}
387
388kern_return_t
f427ee49
A
389IOMemoryDescriptor::CreateMapping_Impl(
390 uint64_t options,
391 uint64_t address,
392 uint64_t offset,
393 uint64_t length,
394 uint64_t alignment,
395 IOMemoryMap ** map)
cb323159
A
396{
397 IOReturn ret;
398 IOMemoryMap * resultMap;
399 IOOptionBits koptions;
400 mach_vm_address_t atAddress;
401
402 ret = kIOReturnSuccess;
403 koptions = 0;
404 resultMap = NULL;
405
406 if (kIOMemoryMapFixedAddress & options) {
407 atAddress = address;
408 koptions = 0;
409 } else {
410 atAddress = 0;
411 koptions |= kIOMapAnywhere;
412 }
413
414 if (kIOMemoryMapReadOnly & options || (kIODirectionOut == getDirection())) {
415 if (!reserved || (current_task() != reserved->creator)) {
416 koptions |= kIOMapReadOnly;
417 }
418 }
419
420 switch (0xFF00 & options) {
421 case kIOMemoryMapCacheModeDefault:
422 koptions |= kIOMapDefaultCache;
423 break;
424 case kIOMemoryMapCacheModeInhibit:
425 koptions |= kIOMapInhibitCache;
426 break;
427 case kIOMemoryMapCacheModeCopyback:
428 koptions |= kIOMapCopybackCache;
429 break;
430 case kIOMemoryMapCacheModeWriteThrough:
431 koptions |= kIOMapWriteThruCache;
432 break;
433 default:
434 ret = kIOReturnBadArgument;
435 }
436
437 if (kIOReturnSuccess == ret) {
438 resultMap = createMappingInTask(current_task(), atAddress, koptions, offset, length);
439 if (!resultMap) {
440 ret = kIOReturnError;
441 }
442 }
443
444 *map = resultMap;
445
446 return ret;
447}
448
449kern_return_t
f427ee49
A
450IOMemoryDescriptor::CreateSubMemoryDescriptor_Impl(
451 uint64_t memoryDescriptorCreateOptions,
452 uint64_t offset,
453 uint64_t length,
454 IOMemoryDescriptor * ofDescriptor,
455 IOMemoryDescriptor ** memory)
456{
457 IOReturn ret;
458 IOMemoryDescriptor * iomd;
459 IOByteCount mdOffset;
460 IOByteCount mdLength;
461 IOByteCount mdEnd;
462
463 if (!ofDescriptor) {
464 return kIOReturnBadArgument;
465 }
466 if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
467 return kIOReturnBadArgument;
468 }
469 if (os_convert_overflow(offset, &mdOffset)) {
470 return kIOReturnBadArgument;
471 }
472 if (os_convert_overflow(length, &mdLength)) {
473 return kIOReturnBadArgument;
474 }
475 if (os_add_overflow(mdOffset, mdLength, &mdEnd)) {
476 return kIOReturnBadArgument;
477 }
478 if (mdEnd > ofDescriptor->getLength()) {
479 return kIOReturnBadArgument;
480 }
481
482 iomd = IOSubMemoryDescriptor::withSubRange(
483 ofDescriptor, mdOffset, mdLength, (IOOptionBits) memoryDescriptorCreateOptions);
484
485 if (iomd) {
486 ret = kIOReturnSuccess;
487 *memory = iomd;
488 } else {
489 ret = kIOReturnNoMemory;
490 *memory = NULL;
491 }
492
493 return ret;
494}
495
496/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
497
498kern_return_t
499IOMemoryDescriptor::CreateWithMemoryDescriptors_Impl(
500 uint64_t memoryDescriptorCreateOptions,
501 uint32_t withDescriptorsCount,
502 IOMemoryDescriptor ** const withDescriptors,
503 IOMemoryDescriptor ** memory)
cb323159 504{
f427ee49
A
505 IOReturn ret;
506 IOMemoryDescriptor * iomd;
cb323159 507
f427ee49
A
508 if (!withDescriptors) {
509 return kIOReturnBadArgument;
510 }
511 if (!withDescriptorsCount) {
512 return kIOReturnBadArgument;
513 }
514 if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
cb323159
A
515 return kIOReturnBadArgument;
516 }
517
f427ee49
A
518 for (unsigned int idx = 0; idx < withDescriptorsCount; idx++) {
519 if (NULL == withDescriptors[idx]) {
520 return kIOReturnBadArgument;
cb323159 521 }
cb323159 522 }
cb323159 523
f427ee49
A
524 iomd = IOMultiMemoryDescriptor::withDescriptors(withDescriptors, withDescriptorsCount,
525 (IODirection) memoryDescriptorCreateOptions, false);
526
527 if (iomd) {
528 ret = kIOReturnSuccess;
529 *memory = iomd;
530 } else {
531 ret = kIOReturnNoMemory;
532 *memory = NULL;
cb323159 533 }
f427ee49
A
534
535 return ret;
536}
537
538/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
539
540kern_return_t
541IOUserClient::CreateMemoryDescriptorFromClient_Impl(
542 uint64_t memoryDescriptorCreateOptions,
543 uint32_t segmentsCount,
544 const IOAddressSegment segments[32],
545 IOMemoryDescriptor ** memory)
546{
547 IOReturn ret;
548 IOMemoryDescriptor * iomd;
549 IOOptionBits mdOptions;
550 IOUserUserClient * me;
551 IOAddressRange * ranges;
552
553 me = OSDynamicCast(IOUserUserClient, this);
554 if (!me) {
555 return kIOReturnBadArgument;
cb323159
A
556 }
557
f427ee49
A
558 mdOptions = 0;
559 if (kIOMemoryDirectionOut & memoryDescriptorCreateOptions) {
560 mdOptions |= kIODirectionOut;
561 }
562 if (kIOMemoryDirectionIn & memoryDescriptorCreateOptions) {
563 mdOptions |= kIODirectionIn;
564 }
565 if (!(kIOMemoryDisableCopyOnWrite & memoryDescriptorCreateOptions)) {
566 mdOptions |= kIOMemoryMapCopyOnWrite;
567 }
568
569 static_assert(sizeof(IOAddressRange) == sizeof(IOAddressSegment));
570 ranges = __DECONST(IOAddressRange *, &segments[0]);
571
572 iomd = IOMemoryDescriptor::withAddressRanges(
573 ranges, segmentsCount,
574 mdOptions, me->fTask);
575
576 if (iomd) {
577 ret = kIOReturnSuccess;
578 *memory = iomd;
579 } else {
580 ret = kIOReturnNoMemory;
581 *memory = NULL;
582 }
cb323159
A
583
584 return ret;
585}
586
f427ee49 587/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
588
589kern_return_t
f427ee49
A
590IOMemoryMap::_CopyState_Impl(
591 _IOMemoryMapPrivateState * state)
cb323159
A
592{
593 IOReturn ret;
594
595 state->offset = fOffset;
596 state->length = getLength();
597 state->address = getAddress();
598 state->options = getMapOptions();
599
600 ret = kIOReturnSuccess;
601
602 return ret;
603}
604
f427ee49 605/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
606
607kern_return_t
f427ee49
A
608IOBufferMemoryDescriptor::Create_Impl(
609 uint64_t options,
610 uint64_t capacity,
611 uint64_t alignment,
612 IOBufferMemoryDescriptor ** memory)
cb323159
A
613{
614 IOReturn ret;
f427ee49 615 IOOptionBits bmdOptions;
cb323159
A
616 IOBufferMemoryDescriptor * bmd;
617 IOMemoryDescriptorReserved * reserved;
618
619 if (options & ~((uint64_t) kIOMemoryDirectionOutIn)) {
620 // no other options currently defined
621 return kIOReturnBadArgument;
622 }
f427ee49 623 bmdOptions = (options & kIOMemoryDirectionOutIn) | kIOMemoryKernelUserShared;
cb323159 624 bmd = IOBufferMemoryDescriptor::inTaskWithOptions(
f427ee49 625 kernel_task, bmdOptions, capacity, alignment);
cb323159
A
626
627 *memory = bmd;
628
629 if (!bmd) {
630 return kIOReturnNoMemory;
631 }
632
633 reserved = bmd->getKernelReserved();
634 reserved->creator = current_task();
635 task_reference(reserved->creator);
636
637 ret = kIOReturnSuccess;
638
639 return ret;
640}
641
642kern_return_t
f427ee49
A
643IOBufferMemoryDescriptor::SetLength_Impl(
644 uint64_t length)
cb323159
A
645{
646 setLength(length);
647 return kIOReturnSuccess;
648}
649
eb6b6ca3 650
f427ee49 651/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
eb6b6ca3
A
652
653kern_return_t
f427ee49
A
654IODMACommand::Create_Impl(
655 IOService * device,
656 uint64_t options,
657 const IODMACommandSpecification * specification,
658 IODMACommand ** command)
eb6b6ca3
A
659{
660 IOReturn ret;
661 IODMACommand * dma;
662 IODMACommand::SegmentOptions segmentOptions;
663 IOMapper * mapper;
664
665 if (options & ~((uint64_t) kIODMACommandCreateNoOptions)) {
666 // no other options currently defined
667 return kIOReturnBadArgument;
668 }
669
670 if (os_convert_overflow(specification->maxAddressBits, &segmentOptions.fNumAddressBits)) {
671 return kIOReturnBadArgument;
672 }
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);
679
680 mapper = IOMapper::copyMapperForDevice(device);
681
682 dma = IODMACommand::withSpecification(
683 kIODMACommandOutputHost64,
684 &segmentOptions,
685 kIODMAMapOptionMapped,
686 mapper,
687 NULL);
688
689 OSSafeReleaseNULL(mapper);
690 *command = dma;
691
692 if (!dma) {
693 return kIOReturnNoMemory;
694 }
695 ret = kIOReturnSuccess;
696
697 return ret;
698}
699
700kern_return_t
f427ee49
A
701IODMACommand::PrepareForDMA_Impl(
702 uint64_t options,
703 IOMemoryDescriptor * memory,
704 uint64_t offset,
705 uint64_t length,
706 uint64_t * flags,
707 uint32_t * segmentsCount,
708 IOAddressSegment * segments)
eb6b6ca3
A
709{
710 IOReturn ret;
711 uint64_t lflags, mdFlags;
712 UInt32 numSegments;
713 UInt64 genOffset;
714
715 if (options & ~((uint64_t) kIODMACommandPrepareForDMANoOptions)) {
716 // no other options currently defined
717 return kIOReturnBadArgument;
718 }
719
f427ee49
A
720 // uses IOMD direction
721 ret = memory->prepare();
722 if (kIOReturnSuccess != ret) {
723 return ret;
724 }
725
eb6b6ca3
A
726 ret = setMemoryDescriptor(memory, false);
727 if (kIOReturnSuccess != ret) {
f427ee49 728 memory->complete();
eb6b6ca3
A
729 return ret;
730 }
731
732 ret = prepare(offset, length);
733 if (kIOReturnSuccess != ret) {
734 clearMemoryDescriptor(false);
f427ee49 735 memory->complete();
eb6b6ca3
A
736 return ret;
737 }
738
739 static_assert(sizeof(IODMACommand::Segment64) == sizeof(IOAddressSegment));
740
741 numSegments = *segmentsCount;
742 genOffset = offset;
743 ret = genIOVMSegments(&genOffset, segments, &numSegments);
744
745 if (kIOReturnSuccess == ret) {
f427ee49 746 mdFlags = fMemory->getFlags();
eb6b6ca3
A
747 lflags = 0;
748 if (kIODirectionOut & mdFlags) {
749 lflags |= kIOMemoryDirectionOut;
750 }
751 if (kIODirectionIn & mdFlags) {
752 lflags |= kIOMemoryDirectionIn;
753 }
754 *flags = lflags;
755 *segmentsCount = numSegments;
756 }
757
758 return ret;
759}
760
761kern_return_t
f427ee49
A
762IODMACommand::CompleteDMA_Impl(
763 uint64_t options)
eb6b6ca3 764{
f427ee49
A
765 IOReturn ret, completeRet;
766 IOMemoryDescriptor * md;
eb6b6ca3
A
767
768 if (options & ~((uint64_t) kIODMACommandCompleteDMANoOptions)) {
769 // no other options currently defined
770 return kIOReturnBadArgument;
771 }
f427ee49
A
772 if (!fActive) {
773 return kIOReturnNotReady;
774 }
775
776 md = __DECONST(IOMemoryDescriptor *, fMemory);
777 if (md) {
778 md->retain();
779 }
eb6b6ca3
A
780
781 ret = clearMemoryDescriptor(true);
782
f427ee49
A
783 if (md) {
784 completeRet = md->complete();
785 OSSafeReleaseNULL(md);
786 if (kIOReturnSuccess == ret) {
787 ret = completeRet;
788 }
789 }
790
eb6b6ca3
A
791 return ret;
792}
793
794kern_return_t
f427ee49
A
795IODMACommand::GetPreparation_Impl(
796 uint64_t * offset,
797 uint64_t * length,
798 IOMemoryDescriptor ** memory)
eb6b6ca3
A
799{
800 IOReturn ret;
801 IOMemoryDescriptor * md;
802
803 if (!fActive) {
804 return kIOReturnNotReady;
805 }
806
807 ret = getPreparedOffsetAndLength(offset, length);
808 if (kIOReturnSuccess != ret) {
809 return ret;
810 }
811
812 if (memory) {
813 md = __DECONST(IOMemoryDescriptor *, fMemory);
814 *memory = md;
815 if (!md) {
816 ret = kIOReturnNotReady;
817 } else {
818 md->retain();
819 }
820 }
821 return ret;
822}
823
824kern_return_t
f427ee49
A
825IODMACommand::PerformOperation_Impl(
826 uint64_t options,
827 uint64_t dmaOffset,
828 uint64_t length,
829 uint64_t dataOffset,
830 IOMemoryDescriptor * data)
eb6b6ca3
A
831{
832 IOReturn ret;
833 void * buffer;
834 UInt64 copiedDMA;
835 IOByteCount mdOffset, mdLength, copied;
836
837 if (options & ~((uint64_t)
838 (kIODMACommandPerformOperationOptionRead
839 | kIODMACommandPerformOperationOptionWrite
840 | kIODMACommandPerformOperationOptionZero))) {
841 // no other options currently defined
842 return kIOReturnBadArgument;
843 }
844
845 if (!fActive) {
846 return kIOReturnNotReady;
847 }
848 if (os_convert_overflow(dataOffset, &mdOffset)) {
849 return kIOReturnBadArgument;
850 }
851 if (os_convert_overflow(length, &mdLength)) {
852 return kIOReturnBadArgument;
853 }
854 if (length > fMemory->getLength()) {
855 return kIOReturnBadArgument;
856 }
857 buffer = IONew(uint8_t, length);
858 if (NULL == buffer) {
859 return kIOReturnNoMemory;
860 }
861
862 switch (options) {
863 case kIODMACommandPerformOperationOptionZero:
864 bzero(buffer, length);
865 copiedDMA = writeBytes(dmaOffset, buffer, length);
866 if (copiedDMA != length) {
867 ret = kIOReturnUnderrun;
868 break;
869 }
870 ret = kIOReturnSuccess;
871 break;
872
873 case kIODMACommandPerformOperationOptionRead:
874 case kIODMACommandPerformOperationOptionWrite:
875
876 if (!data) {
877 ret = kIOReturnBadArgument;
878 break;
879 }
880 if (length > data->getLength()) {
881 ret = kIOReturnBadArgument;
882 break;
883 }
884 if (kIODMACommandPerformOperationOptionWrite == options) {
885 copied = data->readBytes(mdOffset, buffer, mdLength);
886 if (copied != mdLength) {
887 ret = kIOReturnUnderrun;
888 break;
889 }
890 copiedDMA = writeBytes(dmaOffset, buffer, length);
891 if (copiedDMA != length) {
892 ret = kIOReturnUnderrun;
893 break;
894 }
895 } else { /* kIODMACommandPerformOperationOptionRead */
896 copiedDMA = readBytes(dmaOffset, buffer, length);
897 if (copiedDMA != length) {
898 ret = kIOReturnUnderrun;
899 break;
900 }
901 copied = data->writeBytes(mdOffset, buffer, mdLength);
902 if (copied != mdLength) {
903 ret = kIOReturnUnderrun;
904 break;
905 }
906 }
907 ret = kIOReturnSuccess;
908 break;
909 default:
910 ret = kIOReturnBadArgument;
911 break;
912 }
913
914 IODelete(buffer, uint8_t, length);
915
916 return ret;
917}
918
919
f427ee49 920/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159 921
f427ee49
A
922static kern_return_t
923OSActionCreateWithTypeNameInternal(OSObject * target, uint64_t targetmsgid, uint64_t msgid, size_t referenceSize, OSString * typeName, bool fromKernel, OSAction ** action)
cb323159 924{
f427ee49 925 OSAction * inst = NULL;
cb323159 926 vm_size_t allocsize;
f427ee49
A
927 const OSSymbol *sym = NULL; // must release
928 OSObject *obj = NULL; // must release
929 const OSMetaClass *actionMetaClass = NULL; // do not release
930 kern_return_t ret;
cb323159
A
931
932 if (os_add_overflow(referenceSize, sizeof(OSAction_IVars), &allocsize)) {
f427ee49
A
933 ret = kIOReturnBadArgument;
934 goto finish;
cb323159 935 }
f427ee49
A
936
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();
943 if (!obj) {
944 ret = kIOReturnNoMemory;
945 goto finish;
946 }
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
950 } else {
951 DKLOG("Attempted to create action object with type \"%s\" which does not inherit from OSAction\n", typeName->getCStringNoCopy());
952 ret = kIOReturnBadArgument;
953 goto finish;
954 }
955 } else {
956 inst = OSTypeAlloc(OSAction);
957 if (!inst) {
958 ret = kIOReturnNoMemory;
959 goto finish;
960 }
cb323159 961 }
f427ee49 962
cb323159
A
963 inst->ivars = (typeof(inst->ivars))(uintptr_t) IONewZero(uint8_t, allocsize);
964 if (!inst->ivars) {
f427ee49
A
965 ret = kIOReturnNoMemory;
966 goto finish;
cb323159
A
967 }
968 target->retain();
969 inst->ivars->target = target;
970 inst->ivars->targetmsgid = targetmsgid;
971 inst->ivars->msgid = msgid;
972 inst->ivars->referenceSize = referenceSize;
f427ee49
A
973 if (typeName) {
974 typeName->retain();
975 }
976 inst->ivars->typeName = typeName;
cb323159
A
977
978 *action = inst;
f427ee49
A
979 inst = NULL; // prevent release
980 ret = kIOReturnSuccess;
cb323159 981
f427ee49
A
982finish:
983 OSSafeReleaseNULL(obj);
984 OSSafeReleaseNULL(sym);
985 OSSafeReleaseNULL(inst);
986
987 return ret;
988}
989
990kern_return_t
991OSAction::Create(OSAction_Create_Args)
992{
993 return OSAction::CreateWithTypeName(target, targetmsgid, msgid, referenceSize, NULL, action);
994}
995
996kern_return_t
997OSAction::CreateWithTypeName(OSAction_CreateWithTypeName_Args)
998{
999 return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, true, action);
1000}
1001
1002kern_return_t
1003OSAction::Create_Impl(
1004 OSObject * target,
1005 uint64_t targetmsgid,
1006 uint64_t msgid,
1007 size_t referenceSize,
1008 OSAction ** action)
1009{
1010 return OSAction::CreateWithTypeName_Impl(target, targetmsgid, msgid, referenceSize, NULL, action);
1011}
1012
1013kern_return_t
1014OSAction::CreateWithTypeName_Impl(
1015 OSObject * target,
1016 uint64_t targetmsgid,
1017 uint64_t msgid,
1018 size_t referenceSize,
1019 OSString * typeName,
1020 OSAction ** action)
1021{
1022 return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, false, action);
cb323159
A
1023}
1024
1025void
1026OSAction::free()
1027{
1028 if (ivars) {
1029 if (ivars->abortedHandler) {
1030 Block_release(ivars->abortedHandler);
1031 ivars->abortedHandler = NULL;
1032 }
1033 OSSafeReleaseNULL(ivars->target);
f427ee49 1034 OSSafeReleaseNULL(ivars->typeName);
cb323159
A
1035 IOSafeDeleteNULL(ivars, uint8_t, ivars->referenceSize + sizeof(OSAction_IVars));
1036 }
1037 return super::free();
1038}
1039
1040void *
1041OSAction::GetReference()
1042{
1043 assert(ivars && ivars->referenceSize);
1044 return &ivars->reference[0];
1045}
1046
1047kern_return_t
1048OSAction::SetAbortedHandler(OSActionAbortedHandler handler)
1049{
1050 ivars->abortedHandler = Block_copy(handler);
1051 return kIOReturnSuccess;
1052}
1053
1054void
1055OSAction::Aborted_Impl(void)
1056{
1057 if (ivars->abortedHandler) {
1058 ivars->abortedHandler();
1059 }
1060}
1061
f427ee49 1062/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
1063
1064struct IODispatchSource_IVars {
1065 queue_chain_t link;
1066 IODispatchSource * source;
1067 IOUserServer * server;
1068 IODispatchQueue_IVars * queue;
1069 bool enabled;
1070};
1071
1072bool
1073IODispatchSource::init()
1074{
1075 if (!super::init()) {
1076 return false;
1077 }
1078
1079 ivars = IONewZero(IODispatchSource_IVars, 1);
1080
1081 ivars->source = this;
1082
1083 return true;
1084}
1085
1086void
1087IODispatchSource::free()
1088{
1089 IOSafeDeleteNULL(ivars, IODispatchSource_IVars, 1);
1090 super::free();
1091}
1092
ea3f0419 1093kern_return_t
f427ee49
A
1094IODispatchSource::SetEnable_Impl(
1095 bool enable)
ea3f0419
A
1096{
1097 return SetEnableWithCompletion(enable, NULL);
1098}
1099
f427ee49 1100/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
1101
1102struct IOInterruptDispatchSource_IVars {
1103 IOService * provider;
1104 uint32_t intIndex;
f427ee49 1105 int interruptType;
cb323159
A
1106 IOSimpleLock * lock;
1107 thread_t waiter;
1108 uint64_t count;
1109 uint64_t time;
1110 OSAction * action;
1111 bool enable;
1112};
1113
1114static void
1115IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
1116 IOService * nub, int source )
1117{
1118 IOInterruptDispatchSource_IVars * ivars = (typeof(ivars))refCon;
1119 IOInterruptState is;
1120
1121 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1122 ivars->count++;
1123 if (ivars->waiter) {
1124 ivars->time = mach_absolute_time();
1125 thread_wakeup_thread((event_t) ivars, ivars->waiter);
1126 ivars->waiter = NULL;
1127 }
f427ee49
A
1128 if (kIOInterruptTypeLevel & ivars->interruptType) {
1129 ivars->provider->disableInterrupt(ivars->intIndex);
1130 }
cb323159
A
1131 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1132}
1133
1134kern_return_t
f427ee49
A
1135IOInterruptDispatchSource::Create_Impl(
1136 IOService * provider,
1137 uint32_t index,
1138 IODispatchQueue * queue,
1139 IOInterruptDispatchSource ** source)
cb323159
A
1140{
1141 IOReturn ret;
1142 IOInterruptDispatchSource * inst;
1143
1144 inst = OSTypeAlloc(IOInterruptDispatchSource);
1145 if (!inst->init()) {
1146 inst->free();
1147 return kIOReturnNoMemory;
1148 }
1149
1150 inst->ivars->lock = IOSimpleLockAlloc();
1151
f427ee49
A
1152 ret = provider->getInterruptType(index, &inst->ivars->interruptType);
1153 if (kIOReturnSuccess != ret) {
1154 OSSafeReleaseNULL(inst);
1155 return ret;
1156 }
cb323159
A
1157 ret = provider->registerInterrupt(index, inst, IOInterruptDispatchSourceInterrupt, inst->ivars);
1158 if (kIOReturnSuccess == ret) {
1159 inst->ivars->intIndex = index;
1160 inst->ivars->provider = provider;
f427ee49 1161 inst->ivars->provider->retain();
cb323159
A
1162 *source = inst;
1163 }
1164 return ret;
1165}
1166
eb6b6ca3 1167kern_return_t
f427ee49
A
1168IOInterruptDispatchSource::GetInterruptType_Impl(
1169 IOService * provider,
1170 uint32_t index,
1171 uint64_t * interruptType)
eb6b6ca3
A
1172{
1173 IOReturn ret;
1174 int type;
1175
1176 *interruptType = 0;
1177 ret = provider->getInterruptType(index, &type);
1178 if (kIOReturnSuccess == ret) {
1179 *interruptType = type;
1180 }
1181
1182 return ret;
1183}
1184
cb323159
A
1185bool
1186IOInterruptDispatchSource::init()
1187{
1188 if (!super::init()) {
1189 return false;
1190 }
1191 ivars = IONewZero(IOInterruptDispatchSource_IVars, 1);
1192 if (!ivars) {
1193 return false;
1194 }
1195
1196 return true;
1197}
1198
1199void
1200IOInterruptDispatchSource::free()
1201{
1202 IOReturn ret;
1203
1204 if (ivars && ivars->provider) {
1205 ret = ivars->provider->unregisterInterrupt(ivars->intIndex);
1206 assert(kIOReturnSuccess == ret);
f427ee49 1207 ivars->provider->release();
cb323159
A
1208 }
1209
ea3f0419
A
1210 if (ivars && ivars->lock) {
1211 IOSimpleLockFree(ivars->lock);
1212 }
1213
cb323159
A
1214 IOSafeDeleteNULL(ivars, IOInterruptDispatchSource_IVars, 1);
1215
1216 super::free();
1217}
1218
1219kern_return_t
f427ee49
A
1220IOInterruptDispatchSource::SetHandler_Impl(
1221 OSAction * action)
cb323159
A
1222{
1223 IOReturn ret;
1224 OSAction * oldAction;
1225
1226 oldAction = (typeof(oldAction))ivars->action;
1227 if (oldAction && OSCompareAndSwapPtr(oldAction, NULL, &ivars->action)) {
1228 oldAction->release();
1229 }
1230 action->retain();
1231 ivars->action = action;
1232
1233 ret = kIOReturnSuccess;
1234
1235 return ret;
1236}
1237
1238kern_return_t
f427ee49
A
1239IOInterruptDispatchSource::SetEnableWithCompletion_Impl(
1240 bool enable,
1241 IODispatchSourceCancelHandler handler)
cb323159
A
1242{
1243 IOReturn ret;
1244 IOInterruptState is;
1245
1246 if (enable == ivars->enable) {
1247 return kIOReturnSuccess;
1248 }
1249
1250 if (enable) {
1251 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1252 ivars->enable = enable;
1253 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1254 ret = ivars->provider->enableInterrupt(ivars->intIndex);
1255 } else {
1256 ret = ivars->provider->disableInterrupt(ivars->intIndex);
1257 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1258 ivars->enable = enable;
1259 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1260 }
1261
1262 return ret;
1263}
1264
1265kern_return_t
f427ee49
A
1266IOInterruptDispatchSource::Cancel_Impl(
1267 IODispatchSourceCancelHandler handler)
cb323159 1268{
ea3f0419 1269 return kIOReturnUnsupported;
cb323159
A
1270}
1271
1272kern_return_t
f427ee49
A
1273IOInterruptDispatchSource::CheckForWork_Impl(
1274 const IORPC rpc,
1275 bool synchronous)
cb323159
A
1276{
1277 IOReturn ret = kIOReturnNotReady;
1278 IOInterruptState is;
f427ee49 1279 bool willWait;
cb323159
A
1280 wait_result_t waitResult;
1281 uint64_t icount;
1282 uint64_t itime;
1283 thread_t self;
1284
1285 self = current_thread();
1286 icount = 0;
1287 do {
1288 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1289 if ((icount = ivars->count)) {
1290 itime = ivars->time;
1291 ivars->count = 0;
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);
1297 }
f427ee49
A
1298 willWait = (synchronous && (waitResult == THREAD_WAITING));
1299 if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
1300 ivars->provider->enableInterrupt(ivars->intIndex);
1301 }
cb323159 1302 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
f427ee49 1303 if (willWait) {
cb323159
A
1304 waitResult = thread_block(THREAD_CONTINUE_NULL);
1305 if (THREAD_INTERRUPTED == waitResult) {
f427ee49
A
1306 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1307 ivars->waiter = NULL;
1308 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
cb323159
A
1309 break;
1310 }
1311 }
1312 } while (synchronous && !icount);
1313
1314 if (icount && ivars->action) {
1315 ret = InterruptOccurred(rpc, ivars->action, icount, itime);
1316 }
1317
1318 return ret;
1319}
1320
1321void
f427ee49
A
1322IOInterruptDispatchSource::InterruptOccurred_Impl(
1323 OSAction * action,
1324 uint64_t count,
1325 uint64_t time)
cb323159
A
1326{
1327}
1328
f427ee49 1329/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159 1330
ea3f0419
A
1331enum {
1332 kIOServiceNotificationTypeCount = kIOServiceNotificationTypeLast + 1,
1333};
1334
1335struct IOServiceNotificationDispatchSource_IVars {
1336 OSObject * serverName;
1337 OSAction * action;
1338 IOLock * lock;
1339 IONotifier * notifier;
1340 OSDictionary * interestNotifiers;
1341 OSArray * pending[kIOServiceNotificationTypeCount];
1342 bool enable;
1343};
1344
1345kern_return_t
f427ee49
A
1346IOServiceNotificationDispatchSource::Create_Impl(
1347 OSDictionary * matching,
1348 uint64_t options,
1349 IODispatchQueue * queue,
1350 IOServiceNotificationDispatchSource ** notification)
ea3f0419
A
1351{
1352 IOUserServer * us;
1353 IOReturn ret;
1354 IOServiceNotificationDispatchSource * inst;
1355
1356 inst = OSTypeAlloc(IOServiceNotificationDispatchSource);
1357 if (!inst->init()) {
1358 OSSafeReleaseNULL(inst);
1359 return kIOReturnNoMemory;
1360 }
1361
1362 us = (typeof(us))thread_iokit_tls_get(0);
1363 assert(OSDynamicCast(IOUserServer, us));
1364 if (!us) {
1365 OSSafeReleaseNULL(inst);
1366 return kIOReturnError;
1367 }
1368 inst->ivars->serverName = us->copyProperty(gIOUserServerNameKey);
1369 if (!inst->ivars->serverName) {
1370 OSSafeReleaseNULL(inst);
1371 return kIOReturnNoMemory;
1372 }
1373
1374 inst->ivars->lock = IOLockAlloc();
1375 if (!inst->ivars->lock) {
1376 OSSafeReleaseNULL(inst);
1377 return kIOReturnNoMemory;
1378 }
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;
1384 }
1385 }
1386 inst->ivars->interestNotifiers = OSDictionary::withCapacity(4);
1387 if (!inst->ivars->interestNotifiers) {
1388 OSSafeReleaseNULL(inst);
1389 return kIOReturnNoMemory;
1390 }
1391
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;
1397 bool okToUse;
1398
1399 serverName = newService->copyProperty(gIOUserServerNameKey);
1400 okToUse = (serverName && inst->ivars->serverName->isEqualTo(serverName));
1401 OSSafeReleaseNULL(serverName);
1402 if (!okToUse) {
1403 return false;
1404 }
1405
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);
1410
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;
1416
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);
1423 assert(interest);
1424 interest->remove();
1425 inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
1426 IOLockUnlock(inst->ivars->lock);
1427 break;
1428 default:
1429 break;
1430 }
1431 if (notifyReady && inst->ivars->action) {
1432 inst->ServiceNotificationReady(inst->ivars->action);
1433 }
1434 return kIOReturnSuccess;
1435 });
1436 if (interest) {
1437 IOLockLock(inst->ivars->lock);
1438 inst->ivars->interestNotifiers->setObject((const OSSymbol *) newService, interest);
1439 IOLockUnlock(inst->ivars->lock);
1440 }
1441 if (notifyReady) {
1442 if (inst->ivars->action) {
1443 inst->ServiceNotificationReady(inst->ivars->action);
1444 }
1445 }
1446 return false;
1447 });
1448
1449 if (!inst->ivars->notifier) {
1450 OSSafeReleaseNULL(inst);
1451 ret = kIOReturnError;
1452 }
1453
1454 *notification = inst;
1455 ret = kIOReturnSuccess;
1456
1457 return ret;
1458}
1459
1460kern_return_t
f427ee49
A
1461IOServiceNotificationDispatchSource::CopyNextNotification_Impl(
1462 uint64_t * type,
1463 IOService ** service,
1464 uint64_t * options)
ea3f0419
A
1465{
1466 IOService * next;
1467 uint32_t idx;
1468
1469 IOLockLock(ivars->lock);
1470 for (idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1471 next = (IOService *) ivars->pending[idx]->getObject(0);
1472 if (next) {
1473 next->retain();
1474 ivars->pending[idx]->removeObject(0);
1475 break;
1476 }
1477 }
1478 IOLockUnlock(ivars->lock);
1479
1480 if (idx == kIOServiceNotificationTypeCount) {
1481 idx = kIOServiceNotificationTypeNone;
1482 }
1483 *type = idx;
1484 *service = next;
1485 *options = 0;
1486
1487 return kIOReturnSuccess;
1488}
1489
1490bool
1491IOServiceNotificationDispatchSource::init()
1492{
1493 if (!super::init()) {
1494 return false;
1495 }
1496 ivars = IONewZero(IOServiceNotificationDispatchSource_IVars, 1);
1497 if (!ivars) {
1498 return false;
1499 }
1500
1501 return true;
1502}
1503
1504void
1505IOServiceNotificationDispatchSource::free()
1506{
1507 if (ivars) {
1508 OSSafeReleaseNULL(ivars->serverName);
1509 if (ivars->interestNotifiers) {
1510 ivars->interestNotifiers->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
1511 IONotifier * interest = (typeof(interest))object;
1512 interest->remove();
1513 return false;
1514 });
1515 OSSafeReleaseNULL(ivars->interestNotifiers);
1516 }
1517 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1518 OSSafeReleaseNULL(ivars->pending[idx]);
1519 }
1520 if (ivars->lock) {
1521 IOLockFree(ivars->lock);
1522 ivars->lock = NULL;
1523 }
1524 if (ivars->notifier) {
1525 ivars->notifier->remove();
1526 ivars->notifier = NULL;
1527 }
1528 IOSafeDeleteNULL(ivars, IOServiceNotificationDispatchSource_IVars, 1);
1529 }
1530
1531 super::free();
1532}
1533
1534kern_return_t
f427ee49
A
1535IOServiceNotificationDispatchSource::SetHandler_Impl(
1536 OSAction * action)
ea3f0419
A
1537{
1538 IOReturn ret;
1539 bool notifyReady;
1540
1541 notifyReady = false;
1542
1543 IOLockLock(ivars->lock);
1544 OSSafeReleaseNULL(ivars->action);
1545 action->retain();
1546 ivars->action = action;
1547 if (action) {
1548 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1549 notifyReady = (ivars->pending[idx]->getCount());
1550 if (notifyReady) {
1551 break;
1552 }
1553 }
1554 }
1555 IOLockUnlock(ivars->lock);
1556
1557 if (notifyReady) {
1558 ServiceNotificationReady(action);
1559 }
1560 ret = kIOReturnSuccess;
1561
1562 return ret;
1563}
1564
1565kern_return_t
f427ee49
A
1566IOServiceNotificationDispatchSource::SetEnableWithCompletion_Impl(
1567 bool enable,
1568 IODispatchSourceCancelHandler handler)
ea3f0419
A
1569{
1570 if (enable == ivars->enable) {
1571 return kIOReturnSuccess;
1572 }
1573
1574 IOLockLock(ivars->lock);
1575 ivars->enable = enable;
1576 IOLockUnlock(ivars->lock);
1577
1578 return kIOReturnSuccess;
1579}
1580
1581kern_return_t
f427ee49
A
1582IOServiceNotificationDispatchSource::Cancel_Impl(
1583 IODispatchSourceCancelHandler handler)
ea3f0419
A
1584{
1585 return kIOReturnUnsupported;
1586}
1587
1588kern_return_t
f427ee49
A
1589IOServiceNotificationDispatchSource::CheckForWork_Impl(
1590 const IORPC rpc,
1591 bool synchronous)
ea3f0419
A
1592{
1593 return kIOReturnNotReady;
1594}
1595
1596kern_return_t
1597IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block)
1598{
1599 return kIOReturnUnsupported;
1600}
1601
f427ee49 1602/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ea3f0419 1603
cb323159
A
1604kern_return_t
1605IOUserServer::waitInterruptTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
1606{
1607 IOReturn ret = kIOReturnBadArgument;
1608 IOInterruptState is;
1609 IOInterruptDispatchSource * interrupt;
1610 IOInterruptDispatchSource_IVars * ivars;
1611 IOInterruptDispatchSourcePayload payload;
1612
f427ee49 1613 bool willWait;
cb323159
A
1614 wait_result_t waitResult;
1615 thread_t self;
1616
1617 OSObject * object;
1618
1619 object = iokit_lookup_object_with_port_name((mach_port_name_t)(uintptr_t)p1, IKOT_UEXT_OBJECT, current_task());
1620
1621 if (!object) {
1622 return kIOReturnBadArgument;
1623 }
1624 if (!(interrupt = OSDynamicCast(IOInterruptDispatchSource, object))) {
1625 ret = kIOReturnBadArgument;
1626 } else {
1627 self = current_thread();
1628 ivars = interrupt->ivars;
1629 payload.count = 0;
1630 do {
1631 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1632 if ((payload.count = ivars->count)) {
1633 payload.time = ivars->time;
1634 ivars->count = 0;
1635 waitResult = THREAD_AWAKENED;
1636 } else {
1637 assert(NULL == ivars->waiter);
1638 ivars->waiter = self;
1639 waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
1640 }
f427ee49
A
1641 willWait = (waitResult == THREAD_WAITING);
1642 if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
1643 ivars->provider->enableInterrupt(ivars->intIndex);
1644 }
cb323159 1645 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
f427ee49 1646 if (willWait) {
cb323159
A
1647 waitResult = thread_block(THREAD_CONTINUE_NULL);
1648 if (THREAD_INTERRUPTED == waitResult) {
f427ee49
A
1649 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1650 ivars->waiter = NULL;
1651 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
cb323159
A
1652 break;
1653 }
1654 }
1655 } while (!payload.count);
1656 ret = (payload.count ? kIOReturnSuccess : kIOReturnAborted);
1657 }
1658
1659 if (kIOReturnSuccess == ret) {
1660 int copyerr = copyout(&payload, (user_addr_t) p2, sizeof(payload));
1661 if (copyerr) {
1662 ret = kIOReturnVMError;
1663 }
1664 }
1665
1666 object->release();
1667
1668 return ret;
1669}
1670
f427ee49 1671/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
1672
1673kern_return_t
f427ee49
A
1674IOUserServer::Create_Impl(
1675 const char * name,
1676 uint64_t tag,
1677 uint64_t options,
1678 IOUserServer ** server)
cb323159
A
1679{
1680 IOReturn ret;
1681 IOUserServer * us;
1682 const OSSymbol * sym;
1683 OSNumber * serverTag;
1684 io_name_t rname;
1685
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);
1690 }
1691 if (!us) {
1692 return kIOReturnError;
1693 }
1694
1695 sym = OSSymbol::withCString(name);
1696 serverTag = OSNumber::withNumber(tag, 64);
1697
1698 us->setProperty(gIOUserServerNameKey, (OSObject *) sym);
1699 us->setProperty(gIOUserServerTagKey, serverTag);
1700
1701 serverTag->release();
1702 OSSafeReleaseNULL(sym);
1703
1704 snprintf(rname, sizeof(rname), "IOUserServer(%s-0x%qx)", name, tag);
1705 us->setName(rname);
1706
1707 us->retain();
1708 *server = us;
1709 ret = kIOReturnSuccess;
1710
1711 return ret;
1712}
1713
1714kern_return_t
f427ee49
A
1715IOUserServer::Exit_Impl(
1716 const char * reason)
cb323159
A
1717{
1718 return kIOReturnUnsupported;
1719}
1720
1721kern_return_t
f427ee49
A
1722IOUserServer::LoadModule_Impl(
1723 const char * path)
cb323159
A
1724{
1725 return kIOReturnUnsupported;
1726}
1727
1728
f427ee49 1729/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
1730
1731kern_return_t
f427ee49
A
1732IODispatchQueue::Create_Impl(
1733 const char * name,
1734 uint64_t options,
1735 uint64_t priority,
1736 IODispatchQueue ** queue)
cb323159
A
1737{
1738 IODispatchQueue * result;
1739 IOUserServer * us;
1740
1741 result = OSTypeAlloc(IODispatchQueue);
1742 if (!result) {
1743 return kIOReturnNoMemory;
1744 }
1745 if (!result->init()) {
1746 return kIOReturnNoMemory;
1747 }
1748
1749 *queue = result;
1750
1751 if (!strcmp("Root", name)) {
1752 us = (typeof(us))thread_iokit_tls_get(0);
1753 assert(OSDynamicCast(IOUserServer, us));
1754 us->setRootQueue(result);
1755 }
1756
1757 if (kIODKLogSetup & gIODKDebug) {
1758 DKLOG("IODispatchQueue::Create %s %p\n", name, result);
1759 }
1760
1761 return kIOReturnSuccess;
1762}
1763
1764kern_return_t
f427ee49
A
1765IODispatchQueue::SetPort_Impl(
1766 mach_port_t port)
cb323159 1767{
ea3f0419
A
1768 if (MACH_PORT_NULL != ivars->serverPort) {
1769 return kIOReturnNotReady;
1770 }
1771
cb323159
A
1772 ivars->serverPort = port;
1773 return kIOReturnSuccess;
1774}
1775
1776bool
1777IODispatchQueue::init()
1778{
1779 ivars = IONewZero(IODispatchQueue_IVars, 1);
1780 if (!ivars) {
1781 return false;
1782 }
1783 ivars->queue = this;
1784
1785 return true;
1786}
1787
1788void
1789IODispatchQueue::free()
1790{
ea3f0419
A
1791 if (ivars && ivars->serverPort) {
1792 ipc_port_release_send(ivars->serverPort);
1793 ivars->serverPort = MACH_PORT_NULL;
1794 }
cb323159
A
1795 IOSafeDeleteNULL(ivars, IODispatchQueue_IVars, 1);
1796 super::free();
1797}
1798
1799bool
1800IODispatchQueue::OnQueue()
1801{
1802 return false;
1803}
1804
1805/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1806
1807
1808kern_return_t
1809OSMetaClassBase::Dispatch(IORPC rpc)
1810{
1811 return kIOReturnUnsupported;
1812}
1813
1814kern_return_t
1815OSMetaClassBase::Invoke(IORPC rpc)
1816{
1817 IOReturn ret = kIOReturnUnsupported;
1818 OSMetaClassBase * object;
1819 OSAction * action;
1820 IOService * service;
1821 IOUserServer * us;
1822 IORPCMessage * message;
1823
1824 assert(rpc.sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
1825 message = IORPCMessageFromMach(rpc.message, false);
1826 if (!message) {
1827 return kIOReturnIPCError;
1828 }
1829 message->flags |= kIORPCMessageKernel;
1830
1831 us = NULL;
1832 if (!(kIORPCMessageLocalHost & message->flags)) {
1833 us = OSDynamicCast(IOUserServer, this);
1834 if (!us) {
1835 if ((action = OSDynamicCast(OSAction, this))) {
1836 object = IOUserServer::target(action, message);
1837 } else {
1838 object = this;
1839 }
1840 if ((service = OSDynamicCast(IOService, object))
1841 && service->reserved->uvars) {
1842 // xxx other classes
1843 us = service->reserved->uvars->userServer;
1844 }
1845 }
1846 }
1847 if (us) {
1848 message->flags |= kIORPCMessageRemote;
1849 ret = us->rpc(rpc);
1850 if (kIOReturnSuccess != ret) {
1851 if (kIODKLogIPC & gIODKDebug) {
1852 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret);
1853 }
1854 }
1855 } else {
1856 if (kIODKLogIPC & gIODKDebug) {
1857 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message->msgid);
1858 }
1859 ret = Dispatch(rpc);
1860 }
1861
1862 return ret;
1863}
1864
1865/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1866
1867struct IOPStrings {
1868 uint32_t dataSize;
1869 uint32_t count;
1870 const char strings[0];
1871};
1872
1873kern_return_t
1874OSUserMetaClass::Dispatch(IORPC rpc)
1875{
ea3f0419
A
1876 if (meta) {
1877 return const_cast<OSMetaClass *>(meta)->Dispatch(rpc);
1878 } else {
1879 return kIOReturnUnsupported;
1880 }
cb323159
A
1881}
1882
1883void
1884OSUserMetaClass::free()
1885{
1886 if (queueNames) {
1887 IOFree(queueNames, sizeof(IOPStrings) + queueNames->dataSize * sizeof(char));
1888 queueNames = NULL;
1889 }
1890 if (description) {
1891 IOFree(description, description->descriptionSize);
1892 description = NULL;
1893 }
1894 IOSafeDeleteNULL(methods, uint64_t, 2 * methodCount);
1895 if (meta) {
1896 meta->releaseMetaClass();
1897 }
1898 if (name) {
1899 name->release();
1900 }
1901 OSObject::free();
1902}
1903
1904/*
1905 * Sets the loadTag of the associated OSKext
1906 * in the dext task.
1907 * NOTE: different instances of the same OSKext
1908 * (so same BounleID but different tasks)
1909 * will have the same loadTag.
1910 */
1911void
1912IOUserServer::setTaskLoadTag(OSKext *kext)
1913{
1914 task_t owningTask;
1915 uint32_t loadTag, prev_taskloadTag;
1916
1917 owningTask = this->fOwningTask;
1918 if (!owningTask) {
1919 printf("%s: fOwningTask not found\n", __FUNCTION__);
1920 return;
1921 }
1922
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);
1928 }
1929}
1930
1931/*
1932 * Sets the OSKext uuid as the uuid of the userspace
1933 * dext executable.
1934 */
1935void
1936IOUserServer::setDriverKitUUID(OSKext *kext)
1937{
1938 task_t task;
1939 proc_t p;
1940 uuid_t p_uuid, k_uuid;
1941 OSData *k_data_uuid;
1942 OSData *new_uuid;
1943 uuid_string_t uuid_string = "";
1944
1945 task = this->fOwningTask;
1946 if (!task) {
1947 printf("%s: fOwningTask not found\n", __FUNCTION__);
1948 return;
1949 }
1950
1951 p = (proc_t)(get_bsdtask_info(task));
1952 if (!p) {
1953 printf("%s: proc not found\n", __FUNCTION__);
1954 return;
1955 }
1956 proc_getexecutableuuid(p, p_uuid, sizeof(p_uuid));
1957
1958 k_data_uuid = kext->copyUUID();
1959 if (k_data_uuid) {
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__);
1964 }
1965 return;
1966 }
1967
1968 uuid_unparse(p_uuid, uuid_string);
1969 new_uuid = OSData::withBytes(p_uuid, sizeof(p_uuid));
1970 kext->setDriverKitUUID(new_uuid);
1971}
1972
f427ee49
A
1973void
1974IOUserServer::setCheckInToken(IOUserServerCheckInToken *token)
cb323159 1975{
f427ee49
A
1976 if (token != NULL && fCheckInToken == NULL) {
1977 token->retain();
1978 fCheckInToken = token;
1979 } else {
1980 printf("%s: failed to set check in token. token=%p, fCheckInToken=%p\n", __FUNCTION__, token, fCheckInToken);
cb323159 1981 }
f427ee49 1982}
cb323159 1983
f427ee49
A
1984bool
1985IOUserServer::serviceMatchesCheckInToken(IOUserServerCheckInToken *token)
1986{
1987 if (token != NULL) {
1988 return token == fCheckInToken;
1989 } else {
1990 printf("%s: null check in token\n", __FUNCTION__);
1991 return false;
cb323159 1992 }
cb323159
A
1993}
1994
1995bool
1996IOUserServer::checkEntitlements(
1997 OSDictionary * entitlements, OSObject * prop,
1998 IOService * provider, IOService * dext)
1999{
2000 OSDictionary * matching;
2001
2002 if (!prop) {
2003 return true;
2004 }
2005 if (!entitlements) {
2006 return false;
2007 }
2008
2009 matching = NULL;
2010 if (dext) {
2011 matching = dext->dictionaryWithProperties();
2012 if (!matching) {
2013 return false;
2014 }
2015 }
2016
2017 bool allPresent __block;
2018 prop->iterateObjects(^bool (OSObject * object) {
2019 allPresent = false;
2020 object->iterateObjects(^bool (OSObject * object) {
2021 OSString * string;
2022 OSObject * value;
2023 string = OSDynamicCast(OSString, object);
2024 value = entitlements->getObject(string);
2025 if (matching && value) {
2026 matching->setObject(string, value);
2027 }
2028 allPresent = (NULL != value);
2029 return !allPresent;
2030 });
2031 return allPresent;
2032 });
2033
2034 if (allPresent && matching && provider) {
2035 allPresent = provider->matchPropertyTable(matching);
2036 }
2037
2038 OSSafeReleaseNULL(matching);
2039 OSSafeReleaseNULL(prop);
2040
2041 return allPresent;
2042}
2043
2044bool
2045IOUserServer::checkEntitlements(IOService * provider, IOService * dext)
2046{
2047 OSObject * prop;
2048 bool ok;
2049
2050 if (!fOwningTask) {
2051 return false;
2052 }
2053
2054 prop = provider->copyProperty(gIOServiceDEXTEntitlementsKey);
2055 ok = checkEntitlements(fEntitlements, prop, provider, dext);
2056 if (!ok) {
2057 DKLOG(DKS ": provider entitlements check failed\n", DKN(dext));
2058 }
2059 if (ok) {
2060 prop = dext->copyProperty(gIOServiceDEXTEntitlementsKey);
2061 ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
2062 if (!ok) {
2063 DKLOG(DKS ": family entitlements check failed\n", DKN(dext));
2064 }
2065 }
2066
2067 return ok;
2068}
2069
2070IOReturn
2071IOUserServer::exit(const char * reason)
2072{
2073 DKLOG("%s::exit(%s)\n", getName(), reason);
2074 Exit(reason);
2075 return kIOReturnSuccess;
2076}
2077
2078OSObjectUserVars *
2079IOUserServer::varsForObject(OSObject * obj)
2080{
2081 IOService * service;
2082
2083 if ((service = OSDynamicCast(IOService, obj))) {
2084 return service->reserved->uvars;
2085 }
2086
2087 return NULL;
2088}
2089
2090IOPStrings *
2091IOUserServer::copyInStringArray(const char * string, uint32_t userSize)
2092{
2093 IOPStrings * array;
2094 vm_size_t alloc;
2095 size_t len;
2096 const char * cstr;
2097 const char * end;
2098
2099 if (userSize <= 1) {
2100 return NULL;
2101 }
2102
2103 if (os_add_overflow(sizeof(IOPStrings), userSize, &alloc)) {
2104 assert(false);
2105 return NULL;
2106 }
2107 if (alloc > 16384) {
2108 assert(false);
2109 return NULL;
2110 }
2111 array = (typeof(array))IOMalloc(alloc);
2112 if (!array) {
2113 return NULL;
2114 }
2115 array->dataSize = userSize;
2116 bcopy(string, (void *) &array->strings[0], userSize);
2117
2118 array->count = 0;
2119 cstr = &array->strings[0];
2120 end = &array->strings[array->dataSize];
ea3f0419 2121 while ((len = (unsigned char)cstr[0])) {
cb323159
A
2122 cstr++;
2123 if ((cstr + len) >= end) {
2124 break;
2125 }
2126 cstr += len;
2127 array->count++;
2128 }
2129 if (len) {
2130 IOFree(array, alloc);
2131 array = NULL;
2132 }
2133
2134 return array;
2135}
2136
2137uint32_t
2138IOUserServer::stringArrayIndex(IOPStrings * array, const char * look)
2139{
2140 uint32_t idx;
2141 size_t len, llen;
2142 const char * cstr;
2143 const char * end;
2144
2145 idx = 0;
2146 cstr = &array->strings[0];
2147 end = &array->strings[array->dataSize];
2148 llen = strlen(look);
ea3f0419 2149 while ((len = (unsigned char)cstr[0])) {
cb323159
A
2150 cstr++;
2151 if ((cstr + len) >= end) {
2152 break;
2153 }
2154 if ((len == llen) && !strncmp(cstr, look, len)) {
2155 return idx;
2156 }
2157 cstr += len;
2158 idx++;
2159 }
2160
2161 return -1U;
2162}
2163#define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
2164
2165IODispatchQueue *
2166IOUserServer::queueForObject(OSObject * obj, uint64_t msgid)
2167{
2168 IODispatchQueue * queue;
2169 OSObjectUserVars * uvars;
2170 uint64_t option;
2171
2172 uvars = varsForObject(obj);
2173 if (!uvars) {
2174 return NULL;
2175 }
2176 if (!uvars->queueArray) {
2177 if (uvars->stopped) {
2178 return kIODispatchQueueStopped;
2179 }
2180 return NULL;
2181 }
2182 queue = uvars->queueArray[0];
2183
2184 if (uvars->userMeta
2185 && uvars->userMeta->methods) {
2186 uint32_t idx, baseIdx;
2187 uint32_t lim;
2188 // bsearch
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];
2193 option &= 0xFF;
2194 if (option < uvars->userMeta->queueNames->count) {
2195 queue = uvars->queueArray[option + 1];
2196 }
2197 break;
2198 } else if (msgid > uvars->userMeta->methods[idx]) {
2199 // move right
2200 baseIdx += (lim >> 1) + 1;
2201 lim--;
2202 }
2203 // else move left
2204 }
2205 }
2206 return queue;
2207}
2208
2209IOReturn
2210IOUserServer::objectInstantiate(OSObject * obj, IORPC rpc, IORPCMessage * message)
2211{
2212 IOReturn ret;
2213 OSString * str;
2214 OSObject * prop;
2215 IOService * service;
2216
2217 OSAction * action;
2218 OSObject * target;
2219 uint32_t queueCount, queueAlloc;
2220 const char * resultClassName;
2221 uint64_t resultFlags;
2222
f427ee49 2223 mach_msg_size_t replySize;
cb323159
A
2224 uint32_t methodCount;
2225 const uint64_t * methods;
2226 IODispatchQueue * queue;
2227 OSUserMetaClass * userMeta;
2228 OSObjectUserVars * uvars;
2229 uint32_t idx;
2230 ipc_port_t sendPort;
2231
2232 OSObject_Instantiate_Rpl_Content * reply;
2233
2234 queueCount = 0;
2235 methodCount = 0;
2236 methods = NULL;
2237 str = NULL;
2238 prop = NULL;
2239 userMeta = NULL;
2240 resultClassName = NULL;
2241 resultFlags = 0;
2242 ret = kIOReturnUnsupportedMode;
2243
2244 service = OSDynamicCast(IOService, obj);
f427ee49 2245 action = OSDynamicCast(OSAction, obj);
cb323159
A
2246 if (!service) {
2247 // xxx other classes hosted
2248 resultFlags |= kOSObjectRPCKernel;
2249 resultFlags |= kOSObjectRPCRemote;
2250 } else {
2251 if (service->isInactive()) {
2252 DKLOG(DKS "::instantiate inactive\n", DKN(service));
2253 return kIOReturnOffline;
2254 }
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;
2263 }
2264 if (service->reserved->uvars && service->reserved->uvars->userServer) {
ea3f0419 2265 IOLockLock(service->reserved->uvars->userServer->fLock);
cb323159 2266 userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str);
ea3f0419 2267 IOLockUnlock(service->reserved->uvars->userServer->fLock);
cb323159
A
2268 }
2269 }
2270 if (!str && !userMeta) {
2271 const OSMetaClass * meta;
2272 meta = obj->getMetaClass();
ea3f0419 2273 IOLockLock(fLock);
f427ee49
A
2274 if (action) {
2275 str = action->ivars->typeName;
2276 if (str) {
2277 userMeta = (typeof(userMeta))fClasses->getObject(str);
2278 }
2279 }
cb323159
A
2280 while (meta && !userMeta) {
2281 str = (OSString *) meta->getClassNameSymbol();
2282 userMeta = (typeof(userMeta))fClasses->getObject(str);
2283 if (!userMeta) {
2284 meta = meta->getSuperClass();
2285 }
2286 }
ea3f0419 2287 IOLockUnlock(fLock);
cb323159
A
2288 }
2289 if (str) {
2290 if (!userMeta) {
ea3f0419 2291 IOLockLock(fLock);
cb323159 2292 userMeta = (typeof(userMeta))fClasses->getObject(str);
ea3f0419 2293 IOLockUnlock(fLock);
cb323159
A
2294 }
2295 if (kIODKLogSetup & gIODKDebug) {
2296 DKLOG("userMeta %s %p\n", str->getCStringNoCopy(), userMeta);
2297 }
2298 if (userMeta) {
2299 if (kOSObjectRPCRemote & resultFlags) {
f427ee49
A
2300 if (!action) {
2301 /* Special case: For OSAction subclasses, do not use the superclass */
2302 while (userMeta && !(kOSClassCanRemote & userMeta->description->flags)) {
2303 userMeta = userMeta->superMeta;
2304 }
cb323159
A
2305 }
2306 if (userMeta) {
2307 resultClassName = userMeta->description->name;
2308 ret = kIOReturnSuccess;
2309 }
2310 } else {
2311 service->reserved->uvars->userMeta = userMeta;
2312 queueAlloc = 1;
2313 if (userMeta->queueNames) {
2314 queueAlloc += userMeta->queueNames->count;
2315 }
2316 service->reserved->uvars->queueArray =
2317 IONewZero(IODispatchQueue *, queueAlloc);
2318 resultClassName = str->getCStringNoCopy();
2319 ret = kIOReturnSuccess;
2320 }
f427ee49
A
2321 } else if (kIODKLogSetup & gIODKDebug) {
2322 DKLOG("userMeta %s was not found in fClasses\n", str->getCStringNoCopy());
2323 IOLockLock(fLock);
2324 fClasses->iterateObjects(^bool (const OSSymbol * key, OSObject * val) {
2325 DKLOG(" fClasses[\"%s\"] => %p\n", key->getCStringNoCopy(), val);
2326 return false;
2327 });
2328 IOLockUnlock(fLock);
cb323159
A
2329 }
2330 }
2331 OSSafeReleaseNULL(prop);
2332
2333 IORPCMessageMach * machReply = rpc.reply;
2334 replySize = sizeof(OSObject_Instantiate_Rpl);
2335
2336 if ((kIOReturnSuccess == ret) && (kOSObjectRPCRemote & resultFlags)) {
2337 target = obj;
f427ee49 2338 if (action) {
cb323159
A
2339 if (action->ivars->referenceSize) {
2340 resultFlags |= kOSObjectRPCKernel;
2341 } else {
2342 resultFlags &= ~kOSObjectRPCKernel;
2343 target = action->ivars->target;
2344
2345 queueCount = 1;
2346 queue = queueForObject(target, action->ivars->targetmsgid);
2347 idx = 0;
2348 sendPort = NULL;
2349 if (queue && (kIODispatchQueueStopped != queue)) {
ea3f0419 2350 sendPort = ipc_port_copy_send(queue->ivars->serverPort);
cb323159
A
2351 }
2352 replySize = sizeof(OSObject_Instantiate_Rpl)
2353 + queueCount * sizeof(machReply->objects[0])
2354 + 2 * methodCount * sizeof(reply->methods[0]);
2355 if (replySize > rpc.replySize) {
2356 assert(false);
2357 return kIOReturnIPCError;
2358 }
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;
2364 }
2365 } else {
2366 uvars = varsForObject(target);
2367 if (uvars && uvars->userMeta) {
2368 queueCount = 1;
2369 if (uvars->userMeta->queueNames) {
2370 queueCount += uvars->userMeta->queueNames->count;
2371 }
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) {
2378 assert(false);
2379 return kIOReturnIPCError;
2380 }
2381 for (idx = 0; idx < queueCount; idx++) {
2382 queue = uvars->queueArray[idx];
2383 sendPort = NULL;
2384 if (queue) {
ea3f0419 2385 sendPort = ipc_port_copy_send(queue->ivars->serverPort);
cb323159
A
2386 }
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;
2392 }
2393 }
2394 }
2395 }
2396
2397 if (kIODKLogIPC & gIODKDebug) {
f427ee49 2398 DKLOG("instantiate object %s with user class %s\n", obj->getMetaClass()->getClassName(), str ? str->getCStringNoCopy() : "(null)");
cb323159
A
2399 }
2400
2401 if (kIOReturnSuccess != ret) {
2402 DKLOG("%s: no user class found\n", str ? str->getCStringNoCopy() : obj->getMetaClass()->getClassName());
2403 resultClassName = "unknown";
2404 }
2405
2406 machReply->msgh.msgh_id = kIORPCVersionCurrentReply;
2407 machReply->msgh.msgh_size = replySize;
2408 machReply->msgh_body.msgh_descriptor_count = queueCount;
2409
2410 reply = (typeof(reply))IORPCMessageFromMach(machReply, true);
2411 if (!reply) {
2412 return kIOReturnIPCError;
2413 }
2414 if (methodCount) {
2415 bcopy(methods, &reply->methods[0], methodCount * 2 * sizeof(reply->methods[0]));
2416 }
2417 reply->__hdr.msgid = OSObject_Instantiate_ID;
2418 reply->__hdr.flags = kIORPCMessageOneway;
2419 reply->__hdr.objectRefs = 0;
2420 reply->__pad = 0;
2421 reply->flags = resultFlags;
2422 strlcpy(reply->classname, resultClassName, sizeof(reply->classname));
2423 reply->__result = ret;
2424
2425 ret = kIOReturnSuccess;
2426
2427 return ret;
2428}
2429
f427ee49 2430/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
2431
2432IOReturn
2433IOUserServer::kernelDispatch(OSObject * obj, IORPC rpc)
2434{
2435 IOReturn ret;
2436 IORPCMessage * message;
2437
2438 message = IORPCMessageFromMach(rpc.message, false);
2439 if (!message) {
2440 return kIOReturnIPCError;
2441 }
2442
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);
2447 }
2448 } else {
2449 if (kIODKLogIPC & gIODKDebug) {
2450 DKLOG("%s::Dispatch kernel 0x%qx\n", obj->getMetaClass()->getClassName(), message->msgid);
2451 }
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);
2455 }
2456 }
2457
2458 return ret;
2459}
2460
2461
f427ee49 2462/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
2463
2464OSObject *
2465IOUserServer::target(OSAction * action, IORPCMessage * message)
2466{
2467 OSObject * object;
2468
2469 if (message->msgid != action->ivars->msgid) {
2470 return action;
2471 }
2472 object = action->ivars->target;
2473 message->msgid = action->ivars->targetmsgid;
2474 message->objects[0] = (OSObjectRef) object;
2475 if (kIORPCMessageRemote & message->flags) {
2476 object->retain();
f427ee49
A
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.
cb323159 2482 action->release();
f427ee49 2483#endif
cb323159
A
2484 }
2485 if (kIODKLogIPC & gIODKDebug) {
2486 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid, action->ivars->msgid);
2487 }
2488
2489 return object;
2490}
2491
f427ee49 2492/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
2493
2494kern_return_t
2495uext_server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
2496{
2497 kern_return_t ret;
2498 IORPCMessageMach * msgin;
2499 OSObject * object;
2500 IOUserServer * server;
2501
2502 msgin = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
2503
2504 object = IOUserServer::copyObjectForSendRight(msgin->msgh.msgh_remote_port, IKOT_UEXT_OBJECT);
2505 server = OSDynamicCast(IOUserServer, object);
2506 if (!server) {
2507 OSSafeReleaseNULL(object);
2508 return KERN_INVALID_NAME;
2509 }
2510 ret = server->server(requestkmsg, pReply);
2511 object->release();
2512
2513 return ret;
2514}
2515
2516#define MAX_UEXT_REPLY_SIZE 0x17c0
2517
2518kern_return_t
2519IOUserServer::server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
2520{
2521 kern_return_t ret;
2522 mach_msg_size_t replyAlloc;
2523 ipc_kmsg_t replykmsg;
2524 IORPCMessageMach * msgin;
2525 IORPCMessage * message;
2526 IORPCMessageMach * msgout;
2527 IORPCMessage * reply;
2528 uint32_t replySize;
2529 OSObject * object;
2530 OSAction * action;
2531 bool oneway;
2532 uint64_t msgid;
2533
2534 msgin = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
2535 replyAlloc = 0;
2536 msgout = NULL;
2537 replykmsg = NULL;
2538
2539 if (msgin->msgh.msgh_size < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
2540 if (kIODKLogIPC & gIODKDebug) {
2541 DKLOG("UEXT notify %o\n", msgin->msgh.msgh_id);
2542 }
2543 return KERN_NOT_SUPPORTED;
2544 }
2545
2546 if (!(MACH_MSGH_BITS_COMPLEX & msgin->msgh.msgh_bits)) {
2547 msgin->msgh_body.msgh_descriptor_count = 0;
2548 }
2549 message = IORPCMessageFromMach(msgin, false);
2550 if (!message) {
2551 return kIOReturnIPCError;
2552 }
ea3f0419
A
2553 if (message->objectRefs == 0) {
2554 return kIOReturnIPCError;
2555 }
cb323159
A
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);
2560 }
2561 return KERN_NOT_SUPPORTED;
2562 }
2563
2564 if (msgin->msgh_body.msgh_descriptor_count < 1) {
2565 return KERN_NOT_SUPPORTED;
2566 }
2567 object = (OSObject *) message->objects[0];
2568 msgid = message->msgid;
2569 message->flags &= ~kIORPCMessageKernel;
2570 message->flags |= kIORPCMessageRemote;
2571
2572 if ((action = OSDynamicCast(OSAction, object))) {
2573 object = target(action, message);
2574 msgid = message->msgid;
2575 }
2576
2577 oneway = (0 != (kIORPCMessageOneway & message->flags));
2578 assert(oneway || (MACH_PORT_NULL != msgin->msgh.msgh_local_port));
2579
2580 // includes trailer size
2581 replyAlloc = oneway ? 0 : MAX_UEXT_REPLY_SIZE;
2582 if (replyAlloc) {
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;
2590 }
2591
2592 msgout = (typeof(msgout))ipc_kmsg_msg_header(replykmsg);
2593 /*
2594 * MIG should really assure no data leakage -
2595 * but until it does, pessimistically zero the
2596 * whole reply buffer.
2597 */
2598 bzero((void *)msgout, replyAlloc);
2599 }
2600
ea3f0419 2601 IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc };
cb323159
A
2602
2603 if (object) {
2604 thread_iokit_tls_set(0, this);
2605 ret = kernelDispatch(object, rpc);
2606 thread_iokit_tls_set(0, NULL);
2607 } else {
2608 ret = kIOReturnBadArgument;
2609 }
2610
2611 // release objects
2612 consumeObjects(message, msgin->msgh.msgh_size);
2613
2614 // release ports
2615 copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
2616
2617 if (!oneway) {
2618 if (kIOReturnSuccess == ret) {
2619 replySize = msgout->msgh.msgh_size;
2620 reply = IORPCMessageFromMach(msgout, true);
2621 if (!reply) {
2622 ret = kIOReturnIPCError;
2623 } else {
2624 ret = copyOutObjects(msgout, reply, replySize, (kIORPCVersionCurrentReply == msgout->msgh.msgh_id) /* =>!InvokeReply */);
2625 }
2626 }
2627 if (kIOReturnSuccess != ret) {
2628 IORPCMessageErrorReturnContent * errorMsg;
2629
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;
2637 errorMsg->pad = 0;
2638 replySize = sizeof(IORPCMessageErrorReturn);
2639 }
2640
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);
2643
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;
2649 }
2650
2651 *pReply = replykmsg;
2652
2653 return oneway ? MIG_NO_REPLY : KERN_SUCCESS;
2654}
2655
f427ee49 2656/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
2657
2658#define MAX_OBJECT_COUNT(mach, size, message) \
f427ee49 2659 ((uint32_t)(((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))))
cb323159
A
2660
2661kern_return_t
2662IOUserServerUEXTTrap(OSObject * object, void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
2663{
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;
f427ee49 2668 mach_port_name_t objectName1 = (mach_port_name_t)(uintptr_t) p5;
cb323159
A
2669 size_t totalSize;
2670 OSObject * objectArg1;
2671
2672 IORPCMessageMach * mach;
2673 mach_msg_port_descriptor_t * descs;
2674
2675#pragma pack(4)
2676 struct {
2677 uint32_t pad;
2678 IORPCMessageMach mach;
2679 mach_msg_port_descriptor_t objects[2];
2680 IOTrapMessageBuffer buffer;
2681 } buffer;
2682#pragma pack()
2683
2684 IOReturn ret;
2685 OSAction * action;
2686 int copyerr;
2687 IORPCMessage * message;
2688 IORPCMessage * reply;
2689 IORPC rpc;
2690 uint64_t refs;
2691 uint32_t maxObjectCount;
2692 size_t copySize;
2693 uint64_t * replyHdr;
2694 uintptr_t p;
2695
2696 bzero(&buffer, sizeof(buffer));
2697
2698 p = (typeof(p)) & buffer.buffer[0];
2699 if (os_add_overflow(inSize, outSize, &totalSize)) {
2700 return kIOReturnMessageTooLarge;
2701 }
2702 if (totalSize > sizeof(buffer.buffer)) {
2703 return kIOReturnMessageTooLarge;
2704 }
2705 if (inSize < sizeof(IORPCMessage)) {
2706 return kIOReturnIPCError;
2707 }
2708 copyerr = copyin(msg, &buffer.buffer[0], inSize);
2709 if (copyerr) {
2710 return kIOReturnVMError;
2711 }
2712
2713 message = (typeof(message))p;
2714 refs = message->objectRefs;
2715 if ((refs > 2) || !refs) {
2716 return kIOReturnUnsupported;
2717 }
2718 if (!(kIORPCMessageSimpleReply & message->flags)) {
2719 return kIOReturnUnsupported;
2720 }
2721
2722 descs = (typeof(descs))(p - refs * sizeof(*descs));
2723 mach = (typeof(mach))(p - refs * sizeof(*descs) - sizeof(*mach));
2724
2725 mach->msgh.msgh_id = kIORPCVersionCurrent;
f427ee49
A
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);
cb323159
A
2728
2729 rpc.message = mach;
2730 rpc.sendSize = mach->msgh.msgh_size;
2731 rpc.reply = (IORPCMessageMach *) (p + inSize);
f427ee49 2732 rpc.replySize = ((uint32_t) (sizeof(buffer.buffer) - inSize)); // inSize was checked
cb323159
A
2733
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;
2739 }
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);
2744 }
2745 ret = object->Dispatch(rpc);
2746 } else {
2747 objectArg1 = NULL;
2748 if (refs > 1) {
eb6b6ca3
A
2749 if (objectName1) {
2750 objectArg1 = iokit_lookup_uext_ref_current_task(objectName1);
2751 if (!objectArg1) {
2752 return kIOReturnIPCError;
2753 }
cb323159
A
2754 }
2755 message->objects[1] = (OSObjectRef) objectArg1;
2756 }
2757 if (kIODKLogIPC & gIODKDebug) {
2758 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
2759 }
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);
2763 }
2764 OSSafeReleaseNULL(objectArg1);
2765
2766 if (kIOReturnSuccess == ret) {
2767 if (rpc.reply->msgh_body.msgh_descriptor_count) {
2768 return kIOReturnIPCError;
2769 }
2770 reply = IORPCMessageFromMach(rpc.reply, rpc.reply->msgh.msgh_size);
2771 if (!reply) {
2772 return kIOReturnIPCError;
2773 }
2774 copySize = rpc.reply->msgh.msgh_size - (((uintptr_t) reply) - ((uintptr_t) rpc.reply)) + sizeof(uint64_t);
2775 if (copySize > outSize) {
2776 return kIOReturnIPCError;
2777 }
2778 replyHdr = (uint64_t *) reply;
2779 replyHdr--;
2780 replyHdr[0] = copySize;
2781 copyerr = copyout(replyHdr, out, copySize);
2782 if (copyerr) {
2783 return kIOReturnVMError;
2784 }
2785 }
2786 }
2787
2788 return ret;
2789}
2790
f427ee49 2791/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
cb323159
A
2792
2793IOReturn
2794IOUserServer::rpc(IORPC rpc)
2795{
2796 if (isInactive() && !fRootQueue) {
2797 return kIOReturnOffline;
2798 }
2799
2800 IOReturn ret;
2801 IORPCMessage * message;
2802 IORPCMessageMach * mach;
2803 mach_msg_id_t machid;
2804 uint32_t sendSize, replySize;
2805 bool oneway;
2806 uint64_t msgid;
2807 IODispatchQueue * queue;
2808 IOService * service;
2809 ipc_port_t port;
2810 ipc_port_t sendPort;
2811
2812 queue = NULL;
2813 port = NULL;
2814 sendPort = NULL;
2815
2816 mach = rpc.message;
2817 sendSize = rpc.sendSize;
2818 replySize = rpc.replySize;
2819
2820 assert(sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2821
2822 message = IORPCMessageFromMach(mach, false);
2823 if (!message) {
f427ee49 2824 return kIOReturnIPCError;
cb323159
A
2825 }
2826 msgid = message->msgid;
2827 machid = (msgid >> 32);
2828
2829 if (mach->msgh_body.msgh_descriptor_count < 1) {
2830 return kIOReturnNoMedia;
2831 }
2832
2833 IOLockLock(gIOUserServerLock);
2834 if ((service = OSDynamicCast(IOService, (OSObject *) message->objects[0]))) {
2835 queue = queueForObject(service, msgid);
2836 }
2837 if (!queue) {
2838 queue = fRootQueue;
2839 }
2840 if (queue && (kIODispatchQueueStopped != queue)) {
2841 port = queue->ivars->serverPort;
2842 }
2843 if (port) {
ea3f0419 2844 sendPort = ipc_port_copy_send(port);
cb323159
A
2845 }
2846 IOLockUnlock(gIOUserServerLock);
2847 if (!sendPort) {
2848 return kIOReturnNotReady;
2849 }
2850
2851 oneway = (0 != (kIORPCMessageOneway & message->flags));
2852
2853 ret = copyOutObjects(mach, message, sendSize, false);
2854
2855 mach->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
ea3f0419 2856 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (oneway ? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE));
cb323159
A
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;
2861
ea3f0419
A
2862 boolean_t message_moved;
2863
cb323159 2864 if (oneway) {
ea3f0419
A
2865 ret = kernel_mach_msg_send(&mach->msgh, sendSize,
2866 MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_NOIMPORTANCE,
2867 0, &message_moved);
cb323159
A
2868 } else {
2869 assert(replySize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
c3c9b80d 2870 ret = kernel_mach_msg_rpc(&mach->msgh, sendSize, replySize, FALSE, FALSE, &message_moved);
ea3f0419
A
2871 }
2872
2873 ipc_port_release_send(sendPort);
2874
2875 if (MACH_MSG_SUCCESS != ret) {
2876 if (kIODKLogIPC & gIODKDebug) {
2877 DKLOG("mach_msg() failed 0x%x\n", ret);
2878 }
2879 if (!message_moved) {
2880 // release ports
2881 copyInObjects(mach, message, sendSize, false, true);
2882 }
2883 }
2884
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))) {
cb323159 2889// printf("BAD REPLY SIZE\n");
ea3f0419
A
2890 ret = MIG_BAD_ARGUMENTS;
2891 } else {
2892 if (!(MACH_MSGH_BITS_COMPLEX & mach->msgh.msgh_bits)) {
2893 mach->msgh_body.msgh_descriptor_count = 0;
2894 }
2895 message = IORPCMessageFromMach(mach, true);
2896 if (!message) {
2897 ret = kIOReturnIPCError;
2898 } else if (message->msgid != msgid) {
2899// printf("BAD REPLY ID\n");
cb323159
A
2900 ret = MIG_BAD_ARGUMENTS;
2901 } else {
ea3f0419
A
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);
cb323159 2907 }
ea3f0419
A
2908 return KERN_NOT_SUPPORTED;
2909 }
2910 if (isError) {
2911 IORPCMessageErrorReturnContent * errorMsg = (typeof(errorMsg))message;
2912 ret = errorMsg->result;
cb323159
A
2913 }
2914 }
2915 }
2916 }
2917
2918 return ret;
2919}
2920
2921/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2922
2923IORPCMessage *
2924IORPCMessageFromMach(IORPCMessageMach * msg, bool reply)
2925{
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;
2930 bool upgrade;
2931
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));
2937
2938 if (upgrade) {
2939 OSReportWithBacktrace("obsolete message");
2940 return NULL;
2941 }
2942
2943 for (idx = 0; idx < count; idx++) {
2944 if (desc >= maxDesc) {
2945 return NULL;
2946 }
2947 switch (desc->type) {
2948 case MACH_MSG_PORT_DESCRIPTOR:
2949 size = sizeof(mach_msg_port_descriptor_t);
2950 break;
2951 case MACH_MSG_OOL_DESCRIPTOR:
2952 size = sizeof(mach_msg_ool_descriptor_t);
2953 break;
2954 default:
2955 return NULL;
2956 }
2957 desc = (typeof(desc))(((uintptr_t) desc) + size);
2958 }
2959 return (IORPCMessage *)(uintptr_t) desc;
2960}
2961
2962ipc_port_t
2963IOUserServer::copySendRightForObject(OSObject * object, ipc_kobject_type_t type)
2964{
2965 ipc_port_t port;
2966 ipc_port_t sendPort = NULL;
2967
2968 port = iokit_port_for_object(object, type);
2969 if (port) {
2970 sendPort = ipc_port_make_send(port);
2971 iokit_release_port(port);
2972 }
2973
2974 return sendPort;
2975}
2976
2977OSObject *
2978IOUserServer::copyObjectForSendRight(ipc_port_t port, ipc_kobject_type_t type)
2979{
2980 OSObject * object;
2981 object = iokit_lookup_io_object(port, type);
2982 return object;
2983}
2984
2985/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2986
2987// Create a vm_map_copy_t or kalloc'ed data for memory
2988// to be copied out. ipc will free after the copyout.
2989
2990static kern_return_t
2991copyoutkdata(const void * data, vm_size_t len, void ** buf)
2992{
2993 kern_return_t err;
2994 vm_map_copy_t copy;
2995
2996 err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
2997 false /* src_destroy */, &copy);
2998
2999 assert( err == KERN_SUCCESS );
3000 if (err == KERN_SUCCESS) {
3001 *buf = (char *) copy;
3002 }
3003
3004 return err;
3005}
3006
3007/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3008
3009IOReturn
3010IOUserServer::copyOutObjects(IORPCMessageMach * mach, IORPCMessage * message,
3011 size_t size, bool consume)
3012{
3013 uint64_t refs;
3014 uint32_t idx, maxObjectCount;
3015 ipc_port_t port;
3016 OSObject * object;
3017 size_t descsize;
3018 mach_msg_port_descriptor_t * desc;
3019 mach_msg_ool_descriptor_t * ool;
3020 vm_map_copy_t copy;
3021 void * address;
3022 mach_msg_size_t length;
3023 kern_return_t kr;
3024 OSSerialize * s;
3025
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;
3032 }
3033 if (refs > maxObjectCount) {
3034 return kIOReturnBadArgument;
3035 }
3036
3037 desc = &mach->objects[0];
3038 for (idx = 0; idx < refs; idx++) {
3039 object = (OSObject *) message->objects[idx];
3040
3041 switch (desc->type) {
3042 case MACH_MSG_PORT_DESCRIPTOR:
3043 descsize = sizeof(mach_msg_port_descriptor_t);
3044 port = NULL;
3045 if (object) {
3046 port = copySendRightForObject(object, IKOT_UEXT_OBJECT);
3047 if (!port) {
3048 break;
3049 }
3050 if (consume) {
3051 object->release();
3052 }
3053 message->objects[idx] = 0;
3054 }
3055// desc->type = MACH_MSG_PORT_DESCRIPTOR;
3056 desc->disposition = MACH_MSG_TYPE_MOVE_SEND;
3057 desc->name = port;
3058 desc->pad2 = 0;
3059 desc->pad_end = 0;
3060 break;
3061
3062 case MACH_MSG_OOL_DESCRIPTOR:
3063 descsize = sizeof(mach_msg_ool_descriptor_t);
3064
3065 length = 0;
3066 address = NULL;
3067 if (object) {
3068 s = OSSerialize::binaryWithCapacity(4096);
3069 assert(s);
3070 if (!s) {
3071 break;
3072 }
3073 s->setIndexed(true);
3074 if (!object->serialize(s)) {
3075 assert(false);
3076 descsize = -1UL;
3077 s->release();
3078 break;
3079 }
3080 length = s->getLength();
3081 kr = copyoutkdata(s->text(), length, &address);
3082 s->release();
3083 if (KERN_SUCCESS != kr) {
3084 descsize = -1UL;
3085 address = NULL;
3086 length = 0;
3087 }
3088 if (consume) {
3089 object->release();
3090 }
3091 message->objects[idx] = 0;
3092 }
3093 ool = (typeof(ool))desc;
3094// ool->type = MACH_MSG_OOL_DESCRIPTOR;
3095 ool->deallocate = false;
3096 ool->copy = MACH_MSG_PHYSICAL_COPY;
3097 ool->size = length;
3098 ool->address = address;
3099 break;
3100
3101 default:
3102 descsize = -1UL;
3103 break;
3104 }
3105 if (-1UL == descsize) {
3106 break;
3107 }
3108 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3109 }
3110
3111 if (idx >= refs) {
3112 return kIOReturnSuccess;
3113 }
3114
3115 desc = &mach->objects[0];
3116 while (idx--) {
3117 switch (desc->type) {
3118 case MACH_MSG_PORT_DESCRIPTOR:
3119 descsize = sizeof(mach_msg_port_descriptor_t);
3120 port = desc->name;
3121 if (port) {
3122 ipc_port_release_send(port);
3123 }
3124 break;
3125
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;
3130 if (copy) {
3131 vm_map_copy_discard(copy);
3132 }
3133 break;
3134
3135 default:
3136 descsize = -1UL;
3137 break;
3138 }
3139 if (-1UL == descsize) {
3140 break;
3141 }
3142 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3143 }
3144
3145 return kIOReturnBadArgument;
3146}
3147
3148IOReturn
3149IOUserServer::copyInObjects(IORPCMessageMach * mach, IORPCMessage * message,
3150 size_t size, bool copyObjects, bool consumePorts)
3151{
3152 uint64_t refs;
3153 uint32_t idx, maxObjectCount;
3154 ipc_port_t port;
3155 OSObject * object;
3156 size_t descsize;
3157 mach_msg_port_descriptor_t * desc;
3158 mach_msg_ool_descriptor_t * ool;
3159 vm_map_address_t copyoutdata;
3160 kern_return_t kr;
3161
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;
3168 }
3169 if (refs > maxObjectCount) {
3170 return kIOReturnBadArgument;
3171 }
3172
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);
3178
3179 object = NULL;
3180 port = desc->name;
3181 if (port) {
3182 if (copyObjects) {
3183 object = copyObjectForSendRight(port, IKOT_UEXT_OBJECT);
3184 if (!object) {
3185 descsize = -1UL;
3186 break;
3187 }
3188 }
3189 if (consumePorts) {
3190 ipc_port_release_send(port);
3191 }
3192 }
3193 break;
3194
3195 case MACH_MSG_OOL_DESCRIPTOR:
3196 descsize = sizeof(mach_msg_ool_descriptor_t);
3197 ool = (typeof(ool))desc;
3198
3199 object = NULL;
3200 if (copyObjects && ool->size && ool->address) {
3201 kr = vm_map_copyout(kernel_map, &copyoutdata, (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
3205 ool->size = 0;
3206 ool->address = NULL;
3207 kr = vm_deallocate(kernel_map, copyoutdata, ool->size);
3208 assert(KERN_SUCCESS == kr);
3209 }
3210 if (!object) {
3211 descsize = -1UL;
3212 break;
3213 }
3214 }
3215 break;
3216
3217 default:
3218 descsize = -1UL;
3219 break;
3220 }
3221 if (-1UL == descsize) {
3222 break;
3223 }
3224 if (copyObjects) {
3225 message->objects[idx] = (OSObjectRef) object;
3226 }
3227 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3228 }
3229
3230 if (idx >= refs) {
3231 return kIOReturnSuccess;
3232 }
3233
3234 while (idx--) {
3235 object = (OSObject *) message->objects[idx];
3236 object->release();
3237 message->objects[idx] = 0;
3238 }
3239
3240 return kIOReturnBadArgument;
3241}
3242
3243IOReturn
3244IOUserServer::consumeObjects(IORPCMessage * message, size_t messageSize)
3245{
3246 uint64_t refs, idx;
3247 OSObject * object;
3248
3249 refs = message->objectRefs;
3250 for (idx = 0; idx < refs; idx++) {
3251 object = (OSObject *) message->objects[idx];
3252 if (object) {
3253 object->release();
3254 message->objects[idx] = 0;
3255 }
3256 }
3257
3258 return kIOReturnSuccess;
3259}
3260
3261/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3262
3263bool
3264IOUserServer::finalize(IOOptionBits options)
3265{
3266 OSArray * services;
3267
3268 if (kIODKLogSetup & gIODKDebug) {
3269 DKLOG("%s::finalize(%p)\n", getName(), this);
3270 }
3271
3272 IOLockLock(gIOUserServerLock);
3273 OSSafeReleaseNULL(fRootQueue);
3274 IOLockUnlock(gIOUserServerLock);
3275
3276 services = NULL;
3277 IOLockLock(fLock);
3278 if (fServices) {
3279 services = OSArray::withArray(fServices);
3280 }
3281 IOLockUnlock(fLock);
3282
3283 if (services) {
3284 services->iterateObjects(^bool (OSObject * obj) {
3285 IOService * service;
3286 IOService * provider;
3287 bool started = false;
3288
3289 service = (IOService *) obj;
3290 if (kIODKLogSetup & gIODKDebug) {
3291 DKLOG("%s::terminate(" DKS ")\n", getName(), DKN(service));
3292 }
3293 if (service->reserved->uvars) {
3294 started = service->reserved->uvars->started;
3295 service->reserved->uvars->serverDied = true;
3296 if (started) {
3297 provider = service->getProvider();
3298 serviceDidStop(service, provider);
3299 service->terminate(kIOServiceTerminateNeedWillTerminate | kIOServiceTerminateWithRematch);
3300 }
3301 }
3302 if (!started) {
3303 DKLOG("%s::terminate(" DKS ") server exit before start()\n", getName(), DKN(service));
3304 serviceStop(service, NULL);
3305 }
3306 return false;
3307 });
3308 services->release();
3309 }
3310
3311 return IOUserClient::finalize(options);
3312}
3313
3314/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3315
3316#undef super
3317#define super IOUserClient
3318
3319OSDefineMetaClassAndStructors(IOUserServer, IOUserClient)
3320
3321/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3322
3323IOUserClient * IOUserServer::withTask(task_t owningTask)
3324{
3325 IOUserServer * inst;
3326
3327 inst = new IOUserServer;
3328 if (inst && !inst->init()) {
3329 inst->release();
3330 inst = NULL;
3331 return inst;
3332 }
3333 inst->PMinit();
3334
3335 inst->fOwningTask = current_task();
3336 inst->fEntitlements = IOUserClient::copyClientEntitlements(inst->fOwningTask);
3337
3338 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
3339 if (!inst->fEntitlements || !inst->fEntitlements->getObject(gIODriverKitEntitlementKey)) {
3340 proc_t p;
3341 pid_t pid;
3342
3343 p = (proc_t)get_bsdtask_info(inst->fOwningTask);
3344 if (p) {
3345 pid = proc_pid(p);
3346 IOLog(kIODriverKitEntitlementKey " entitlement check failed for %s[%d]\n", proc_best_name(p), pid);
3347 }
3348 inst->release();
3349 inst = NULL;
3350 return inst;
3351 }
3352 }
3353
ea3f0419
A
3354 /* Mark the current task's space as eligible for uext object ports */
3355 iokit_label_dext_task(inst->fOwningTask);
3356
cb323159
A
3357 inst->fLock = IOLockAlloc();
3358 inst->fServices = OSArray::withCapacity(4);
3359 inst->fClasses = OSDictionary::withCapacity(16);
3360 inst->fClasses->setOptions(OSCollection::kSort, OSCollection::kSort);
3361
3362 return inst;
3363}
3364
3365IOReturn
3366IOUserServer::clientClose(void)
3367{
c3c9b80d
A
3368 OSArray * services;
3369
3370 if (kIODKLogSetup & gIODKDebug) {
3371 DKLOG("%s::clientClose(%p)\n", getName(), this);
3372 }
3373
3374 services = NULL;
3375 IOLockLock(fLock);
3376 if (fServices) {
3377 services = OSArray::withArray(fServices);
3378 }
3379 IOLockUnlock(fLock);
3380
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
3384 if (services) {
3385 services->iterateObjects(^bool (OSObject * obj) {
3386 IOService * service;
3387 IOService * provider;
3388
3389 service = (IOService *) obj;
3390 if (service->isInactive()) {
3391 return false;
3392 }
3393 provider = service->getProvider();
3394 if (provider
3395 && (!provider->reserved->uvars || (provider->reserved->uvars->userServer != this))) {
3396 if (kIODKLogSetup & gIODKDebug) {
3397 DKLOG(DKS "::ClientCrashed(" DKS ")\n", DKN(provider), DKN(service));
3398 }
3399 provider->ClientCrashed(service, 0);
3400 }
3401 return false;
3402 });
3403 services->release();
3404 }
3405
cb323159
A
3406 terminate();
3407 return kIOReturnSuccess;
3408}
3409
3410IOReturn
3411IOUserServer::setProperties(OSObject * properties)
3412{
3413 IOReturn kr = kIOReturnUnsupported;
3414 return kr;
3415}
3416
3417void
3418IOUserServer::stop(IOService * provider)
3419{
3420 fOwningTask = TASK_NULL;
3421
3422 PMstop();
3423
3424 IOServicePH::serverRemove(this);
3425
3426 OSSafeReleaseNULL(fRootQueue);
3427
3428 if (fInterruptLock) {
3429 IOSimpleLockFree(fInterruptLock);
3430 }
3431}
3432
3433void
3434IOUserServer::free()
3435{
3436 OSSafeReleaseNULL(fEntitlements);
3437 OSSafeReleaseNULL(fClasses);
3438 if (fLock) {
3439 IOLockFree(fLock);
3440 }
3441 OSSafeReleaseNULL(fServices);
f427ee49 3442 OSSafeReleaseNULL(fCheckInToken);
cb323159
A
3443 IOUserClient::free();
3444}
3445
3446IOReturn
3447IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSUserMetaClass ** pCls)
3448{
3449 OSUserMetaClass * cls;
3450 const OSSymbol * sym;
3451 uint64_t * methodOptions;
3452 const char * queueNames;
3453 uint32_t methodOptionsEnd, queueNamesEnd;
3454 IOReturn ret = kIOReturnSuccess;
3455
3456 if (size < sizeof(OSClassDescription)) {
3457 assert(false);
3458 return kIOReturnBadArgument;
3459 }
3460
3461 if (kIODKLogSetup & gIODKDebug) {
3462 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc->name, desc->queueNamesSize, desc->methodNamesSize);
3463 }
3464
3465 if (desc->descriptionSize != size) {
3466 assert(false);
3467 return kIOReturnBadArgument;
3468 }
3469 if (os_add_overflow(desc->queueNamesOffset, desc->queueNamesSize, &queueNamesEnd)) {
3470 assert(false);
3471 return kIOReturnBadArgument;
3472 }
3473 if (queueNamesEnd > size) {
3474 assert(false);
3475 return kIOReturnBadArgument;
3476 }
3477 if (os_add_overflow(desc->methodOptionsOffset, desc->methodOptionsSize, &methodOptionsEnd)) {
3478 assert(false);
3479 return kIOReturnBadArgument;
3480 }
3481 if (methodOptionsEnd > size) {
3482 assert(false);
3483 return kIOReturnBadArgument;
3484 }
3485 // overlaps?
3486 if ((desc->queueNamesOffset >= desc->methodOptionsOffset) && (desc->queueNamesOffset < methodOptionsEnd)) {
3487 assert(false);
3488 return kIOReturnBadArgument;
3489 }
3490 if ((queueNamesEnd >= desc->methodOptionsOffset) && (queueNamesEnd < methodOptionsEnd)) {
3491 assert(false);
3492 return kIOReturnBadArgument;
3493 }
3494
3495 if (desc->methodOptionsSize & ((2 * sizeof(uint64_t)) - 1)) {
3496 assert(false);
3497 return kIOReturnBadArgument;
3498 }
3499 if (sizeof(desc->name) == strnlen(desc->name, sizeof(desc->name))) {
3500 assert(false);
3501 return kIOReturnBadArgument;
3502 }
3503 if (sizeof(desc->superName) == strnlen(desc->superName, sizeof(desc->superName))) {
3504 assert(false);
3505 return kIOReturnBadArgument;
3506 }
3507
3508 cls = OSTypeAlloc(OSUserMetaClass);
3509 assert(cls);
3510 if (!cls) {
3511 return kIOReturnNoMemory;
3512 }
3513
3514 cls->description = (typeof(cls->description))IOMalloc(size);
3515 assert(cls->description);
3516 if (!cls->description) {
3517 assert(false);
3518 cls->release();
3519 return kIOReturnNoMemory;
3520 }
3521 bcopy(desc, cls->description, size);
3522
3523 cls->methodCount = desc->methodOptionsSize / (2 * sizeof(uint64_t));
3524 cls->methods = IONew(uint64_t, 2 * cls->methodCount);
3525 if (!cls->methods) {
3526 assert(false);
3527 cls->release();
3528 return kIOReturnNoMemory;
3529 }
3530
3531 methodOptions = (typeof(methodOptions))(((uintptr_t) desc) + desc->methodOptionsOffset);
3532 bcopy(methodOptions, cls->methods, 2 * cls->methodCount * sizeof(uint64_t));
3533
3534 queueNames = (typeof(queueNames))(((uintptr_t) desc) + desc->queueNamesOffset);
3535 cls->queueNames = copyInStringArray(queueNames, desc->queueNamesSize);
3536
3537 sym = OSSymbol::withCString(desc->name);
3538 assert(sym);
3539 if (!sym) {
3540 assert(false);
3541 cls->release();
3542 return kIOReturnNoMemory;
3543 }
3544
3545 cls->name = sym;
3546 cls->meta = OSMetaClass::copyMetaClassWithName(sym);
ea3f0419 3547 IOLockLock(fLock);
cb323159 3548 cls->superMeta = OSDynamicCast(OSUserMetaClass, fClasses->getObject(desc->superName));
ea3f0419
A
3549 if (fClasses->getObject(sym) != NULL) {
3550 /* class with this name exists */
3551 ret = kIOReturnBadArgument;
3552 } else {
3553 if (fClasses->setObject(sym, cls)) {
3554 *pCls = cls;
3555 } else {
3556 /* could not add class to fClasses */
3557 ret = kIOReturnNoMemory;
3558 }
3559 }
3560 IOLockUnlock(fLock);
cb323159 3561 cls->release();
cb323159
A
3562 return ret;
3563}
3564
f427ee49
A
3565IOReturn
3566IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSSharedPtr<OSUserMetaClass>& pCls)
3567{
3568 OSUserMetaClass* pClsRaw = NULL;
3569 IOReturn result = registerClass(desc, size, &pClsRaw);
3570 if (result == kIOReturnSuccess) {
3571 pCls.reset(pClsRaw, OSRetain);
3572 }
3573 return result;
3574}
3575
cb323159
A
3576IOReturn
3577IOUserServer::setRootQueue(IODispatchQueue * queue)
3578{
3579 assert(!fRootQueue);
3580 if (fRootQueue) {
3581 return kIOReturnStillOpen;
3582 }
3583 queue->retain();
3584 fRootQueue = queue;
3585
3586 return kIOReturnSuccess;
3587}
3588
3589IOReturn
3590IOUserServer::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
3591 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
3592{
3593 IOReturn ret = kIOReturnBadArgument;
3594 mach_port_name_t portname;
3595
3596 switch (selector) {
3597 case kIOUserServerMethodRegisterClass:
3598 {
3599 OSUserMetaClass * cls;
3600 if (!args->structureInputSize) {
3601 return kIOReturnBadArgument;
3602 }
3603 if (args->scalarOutputCount != 2) {
3604 return kIOReturnBadArgument;
3605 }
3606 ret = registerClass((OSClassDescription *) args->structureInput, args->structureInputSize, &cls);
3607 if (kIOReturnSuccess == ret) {
3608 portname = iokit_make_send_right(fOwningTask, cls, IKOT_UEXT_OBJECT);
3609 assert(portname);
3610 args->scalarOutput[0] = portname;
3611 args->scalarOutput[1] = kOSObjectRPCRemote;
3612 }
3613 break;
3614 }
3615 case kIOUserServerMethodStart:
3616 {
3617 if (args->scalarOutputCount != 1) {
3618 return kIOReturnBadArgument;
3619 }
f427ee49
A
3620 if (!(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
3621 if (args->scalarInputCount != 1) {
3622 return kIOReturnBadArgument;
3623 }
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);
3629 } else {
3630 OSSafeReleaseNULL(obj);
3631 return kIOReturnBadArgument;
3632 }
3633 OSSafeReleaseNULL(obj);
3634 }
cb323159
A
3635 portname = iokit_make_send_right(fOwningTask, this, IKOT_UEXT_OBJECT);
3636 assert(portname);
3637 args->scalarOutput[0] = portname;
3638 ret = kIOReturnSuccess;
3639 break;
3640 }
3641 default:
3642 break;
3643 }
3644
3645 return ret;
3646}
3647
3648IOExternalTrap *
3649IOUserServer::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
3650{
3651 static const IOExternalTrap trapTemplate[] = {
3652 { NULL, (IOTrap) & IOUserServer::waitInterruptTrap},
3653 };
3654 if (index >= (sizeof(trapTemplate) / sizeof(IOExternalTrap))) {
3655 return NULL;
3656 }
3657 *targetP = this;
3658 return (IOExternalTrap *)&trapTemplate[index];
3659}
3660
3661/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3662
3663IOReturn
3664IOUserServer::serviceAttach(IOService * service, IOService * provider)
3665{
3666 IOReturn ret;
3667 OSObjectUserVars * vars;
3668 OSObject * prop;
3669 OSString * str;
f427ee49 3670 OSSymbol const* bundleID;
cb323159
A
3671 char execPath[1024];
3672
3673 vars = IONewZero(OSObjectUserVars, 1);
3674 service->reserved->uvars = vars;
3675
3676 vars->userServer = this;
3677 vars->userServer->retain();
3678 IOLockLock(fLock);
3679 if (-1U == fServices->getNextIndexOfObject(service, 0)) {
3680 fServices->setObject(service);
3681 }
3682 IOLockUnlock(fLock);
3683
3684 prop = service->copyProperty(gIOUserClassKey);
3685 str = OSDynamicCast(OSString, prop);
3686 if (str) {
3687 service->setName(str);
3688 }
3689 OSSafeReleaseNULL(prop);
3690
3691 prop = service->copyProperty(gIOModuleIdentifierKey);
3692 bundleID = OSDynamicCast(OSSymbol, prop);
3693 if (bundleID) {
3694 execPath[0] = 0;
3695 bool ok = OSKext::copyUserExecutablePath(bundleID, execPath, sizeof(execPath));
3696 if (ok) {
3697 ret = LoadModule(execPath);
3698 if (kIODKLogSetup & gIODKDebug) {
3699 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret, execPath);
3700 }
3701 }
3702 }
3703 OSSafeReleaseNULL(prop);
3704
3705 ret = kIOReturnSuccess;
3706
3707 return ret;
3708}
3709
3710/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3711
3712#define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
3713
3714IOReturn
3715IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
3716 uint32_t type, OSDictionary * properties, IOUserClient ** handler)
3717{
3718 IOReturn ret;
3719 IOUserClient * uc;
3720 IOUserUserClient * userUC;
3721 OSDictionary * entitlements;
3722 OSObject * prop;
3723 OSObject * bundleID;
3724 bool ok;
3725
3726 *handler = NULL;
3727 ret = service->NewUserClient(type, &uc);
3728 if (kIOReturnSuccess != ret) {
3729 return ret;
3730 }
3731 userUC = OSDynamicCast(IOUserUserClient, uc);
3732 if (!userUC) {
3733 uc->terminate();
3734 OSSafeReleaseNULL(uc);
3735 return kIOReturnUnsupported;
3736 }
3737 userUC->setTask(owningTask);
3738
3739 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
eb6b6ca3 3740 bundleID = NULL;
c3c9b80d 3741 entitlements = IOUserClient::copyClientEntitlements(owningTask);
eb6b6ca3
A
3742 if (fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowAnyKey)) {
3743 ok = true;
3744 } else {
eb6b6ca3
A
3745 bundleID = service->copyProperty(gIOModuleIdentifierKey);
3746 ok = (entitlements
3747 && bundleID
3748 && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey)));
3749 if (ok) {
3750 bool found __block = false;
3751 ok = prop->iterateObjects(^bool (OSObject * object) {
3752 found = object->isEqualTo(bundleID);
3753 return found;
3754 });
3755 ok = found;
3756 }
cb323159
A
3757 }
3758 if (ok) {
3759 prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
3760 ok = checkEntitlements(entitlements, prop, NULL, NULL);
3761 }
3762 OSSafeReleaseNULL(bundleID);
3763 OSSafeReleaseNULL(entitlements);
3764 if (!ok) {
3765 DKLOG(DKS ":UC entitlements check failed\n", DKN(userUC));
3766 uc->terminate();
3767 OSSafeReleaseNULL(uc);
3768 return kIOReturnNotPermitted;
3769 }
3770 }
3771
cb323159
A
3772 *handler = userUC;
3773
3774 return ret;
3775}
3776
f427ee49
A
3777IOReturn
3778IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
3779 uint32_t type, OSDictionary * properties, OSSharedPtr<IOUserClient>& handler)
3780{
3781 IOUserClient* handlerRaw = NULL;
3782 IOReturn result = serviceNewUserClient(service, owningTask, securityID, type, properties, &handlerRaw);
3783 handler.reset(handlerRaw, OSNoRetain);
3784 return result;
3785}
3786
cb323159
A
3787/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3788
3789static IOPMPowerState
3790 sPowerStates[] = {
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},
3803};
3804
3805IOReturn
3806IOUserServer::setPowerState(unsigned long state, IOService * service)
3807{
3808 if (kIODKLogPM & gIODKDebug) {
3809 DKLOG(DKS "::setPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
3810 }
3811 return kIOPMAckImplied;
3812}
3813
3814IOReturn
f427ee49 3815IOUserServer::serviceSetPowerState(IOService * controllingDriver, IOService * service, IOPMPowerFlags flags, unsigned long state)
cb323159
A
3816{
3817 IOReturn ret;
3818
3819 if (service->reserved->uvars) {
3820 if (!fSystemOff && !(kIODKDisablePM & gIODKDebug)) {
3821 service->reserved->uvars->willPower = true;
f427ee49
A
3822 service->reserved->uvars->willPowerState = state;
3823 service->reserved->uvars->controllingDriver = controllingDriver;
cb323159 3824 if (kIODKLogPM & gIODKDebug) {
f427ee49 3825 DKLOG(DKS "::serviceSetPowerState(%ld) 0x%qx, %d\n", DKN(service), state, fPowerStates, fSystemPowerAck);
cb323159 3826 }
f427ee49 3827 ret = service->SetPowerState((uint32_t) flags);
cb323159
A
3828 if (kIOReturnSuccess == ret) {
3829 return 20 * 1000 * 1000;
3830 }
3831 }
3832 service->reserved->uvars->willPower = false;
3833 }
3834
3835 return kIOPMAckImplied;
3836}
3837
f427ee49
A
3838IOReturn
3839IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
3840{
3841 return kIOPMAckImplied;
3842}
3843
cb323159
A
3844IOReturn
3845IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
3846{
3847 unsigned int idx;
3848 bool pmAck;
3849
3850 pmAck = false;
3851 IOLockLock(fLock);
3852 idx = fServices->getNextIndexOfObject(service, 0);
3853 if (-1U == idx) {
3854 IOLockUnlock(fLock);
3855 return kIOPMAckImplied;
3856 }
3857 assert(idx <= 63);
3858
3859 if (state) {
3860 fPowerStates |= (1ULL << idx);
3861 } else {
3862 fPowerStates &= ~(1ULL << idx);
3863 }
3864 if (kIODKLogPM & gIODKDebug) {
3865 DKLOG(DKS "::powerStateDidChangeTo(%ld) 0x%qx, %d\n", DKN(service), state, fPowerStates, fSystemPowerAck);
3866 }
3867 if (!fPowerStates && (pmAck = fSystemPowerAck)) {
3868 fSystemPowerAck = false;
3869 fSystemOff = true;
3870 }
3871 IOLockUnlock(fLock);
3872
3873 if (pmAck) {
3874 IOServicePH::serverAck(this);
3875 }
3876
3877 return kIOPMAckImplied;
3878}
3879
3880kern_return_t
f427ee49
A
3881IOService::SetPowerState_Impl(
3882 uint32_t powerFlags)
cb323159
A
3883{
3884 if (kIODKLogPM & gIODKDebug) {
3885 DKLOG(DKS "::SetPowerState(%d), %d\n", DKN(this), powerFlags, reserved->uvars->willPower);
3886 }
3887 if (reserved->uvars
3888 && reserved->uvars->userServer
3889 && reserved->uvars->willPower) {
f427ee49 3890 IOReturn ret;
cb323159 3891 reserved->uvars->willPower = false;
f427ee49
A
3892 ret = reserved->uvars->controllingDriver->setPowerState(reserved->uvars->willPowerState, this);
3893 if (kIOPMAckImplied == ret) {
3894 acknowledgeSetPowerState();
3895 }
cb323159
A
3896 return kIOReturnSuccess;
3897 }
3898 return kIOReturnNotReady;
3899}
3900
3901kern_return_t
f427ee49
A
3902IOService::ChangePowerState_Impl(
3903 uint32_t powerFlags)
cb323159
A
3904{
3905 switch (powerFlags) {
3906 case kIOServicePowerCapabilityOff:
3907 changePowerStateToPriv(0);
3908 break;
3909 case kIOServicePowerCapabilityLow:
3910 changePowerStateToPriv(1);
3911 break;
3912 case kIOServicePowerCapabilityOn:
3913 changePowerStateToPriv(2);
3914 break;
3915 default:
3916 return kIOReturnBadArgument;
3917 }
3918
3919 return kIOReturnSuccess;
3920}
3921
3922kern_return_t
f427ee49
A
3923IOService::Create_Impl(
3924 IOService * provider,
3925 const char * propertiesKey,
3926 IOService ** result)
cb323159
A
3927{
3928 OSObject * inst;
3929 IOService * service;
3930 OSString * str;
3931 const OSSymbol * sym;
3932 OSObject * prop;
3933 OSDictionary * properties;
3934 kern_return_t ret;
3935
3936 if (provider != this) {
3937 return kIOReturnUnsupported;
3938 }
3939
3940 ret = kIOReturnUnsupported;
3941 inst = NULL;
3942 service = NULL;
3943
3944 prop = copyProperty(propertiesKey);
3945 properties = OSDynamicCast(OSDictionary, prop);
3946 assert(properties);
3947 if (properties) {
3948 str = OSDynamicCast(OSString, properties->getObject(gIOClassKey));
3949 assert(str);
3950 sym = OSSymbol::withString(str);
3951 if (sym) {
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);
ea3f0419 3956 service->reserved->uvars->started = true;
cb323159
A
3957 ret = kIOReturnSuccess;
3958 *result = service;
3959 }
3960 OSSafeReleaseNULL(sym);
3961 }
3962 }
3963
3964 OSSafeReleaseNULL(prop);
3965 if (kIOReturnSuccess != ret) {
3966 OSSafeReleaseNULL(inst);
3967 }
3968
3969 return ret;
3970}
3971
ea3f0419 3972kern_return_t
f427ee49
A
3973IOService::Terminate_Impl(
3974 uint64_t options)
ea3f0419
A
3975{
3976 IOUserServer * us;
3977
3978 if (options) {
3979 return kIOReturnUnsupported;
3980 }
3981
3982 us = (typeof(us))thread_iokit_tls_get(0);
3983 if (!reserved->uvars
3984 || (reserved->uvars->userServer != us)) {
3985 return kIOReturnNotPermitted;
3986 }
3987 terminate(kIOServiceTerminateNeedWillTerminate);
3988
3989 return kIOReturnSuccess;
3990}
3991
cb323159 3992kern_return_t
f427ee49
A
3993IOService::NewUserClient_Impl(
3994 uint32_t type,
3995 IOUserClient ** userClient)
cb323159
A
3996{
3997 return kIOReturnError;
3998}
3999
4000kern_return_t
f427ee49
A
4001IOService::SearchProperty_Impl(
4002 const char * name,
4003 const char * plane,
4004 uint64_t options,
4005 OSContainer ** property)
cb323159 4006{
f427ee49
A
4007 OSObject * object;
4008 IOOptionBits regOptions;
cb323159
A
4009
4010 if (kIOServiceSearchPropertyParents & options) {
f427ee49 4011 regOptions = kIORegistryIterateParents | kIORegistryIterateRecursively;
cb323159 4012 } else {
f427ee49 4013 regOptions = 0;
cb323159
A
4014 }
4015
f427ee49 4016 object = copyProperty(name, IORegistryEntry::getPlane(plane), regOptions);
cb323159
A
4017 *property = object;
4018
4019 return object ? kIOReturnSuccess : kIOReturnNotFound;
4020}
4021
ea3f0419 4022kern_return_t
f427ee49
A
4023IOService::CopyProviderProperties_Impl(
4024 OSArray * propertyKeys,
4025 OSArray ** properties)
ea3f0419
A
4026{
4027 IOReturn ret;
4028 OSArray * result;
4029 IOService * provider;
4030
4031 result = OSArray::withCapacity(8);
4032 if (!result) {
4033 return kIOReturnNoMemory;
4034 }
4035
4036 ret = kIOReturnSuccess;
4037 for (provider = this; provider; provider = provider->getProvider()) {
4038 OSObject * obj;
4039 OSDictionary * props;
4040
4041 obj = provider->copyProperty(gIOSupportedPropertiesKey);
4042 props = OSDynamicCast(OSDictionary, obj);
4043 if (!props) {
4044 OSSafeReleaseNULL(obj);
4045 props = provider->dictionaryWithProperties();
4046 }
4047 if (!props) {
4048 ret = kIOReturnNoMemory;
4049 break;
4050 }
4051 bool __block addClass = true;
4052 if (propertyKeys) {
4053 OSDictionary * retProps;
4054 retProps = OSDictionary::withCapacity(4);
4055 addClass = false;
4056 if (!retProps) {
4057 ret = kIOReturnNoMemory;
4058 break;
4059 }
4060 propertyKeys->iterateObjects(^bool (OSObject * _key) {
4061 OSString * key = OSDynamicCast(OSString, _key);
4062 if (gIOClassKey->isEqualTo(key)) {
4063 addClass = true;
4064 return false;
4065 }
4066 retProps->setObject(key, props->getObject(key));
4067 return false;
4068 });
4069 OSSafeReleaseNULL(props);
4070 props = retProps;
4071 }
4072 if (addClass) {
4073 OSArray * classes = OSArray::withCapacity(8);
4074 if (!classes) {
4075 ret = kIOReturnNoMemory;
4076 break;
4077 }
4078 for (const OSMetaClass * meta = provider->getMetaClass(); meta; meta = meta->getSuperClass()) {
4079 classes->setObject(meta->getClassNameSymbol());
4080 }
4081 props->setObject(gIOClassKey, classes);
4082 OSSafeReleaseNULL(classes);
4083 }
4084 bool ok = result->setObject(props);
4085 props->release();
4086 if (!ok) {
4087 ret = kIOReturnNoMemory;
4088 break;
4089 }
4090 }
4091 if (kIOReturnSuccess != ret) {
4092 OSSafeReleaseNULL(result);
4093 }
4094 *properties = result;
4095 return ret;
4096}
4097
cb323159
A
4098void
4099IOUserServer::systemPower(bool powerOff)
4100{
4101 OSArray * services;
4102
4103 if (kIODKLogPM & gIODKDebug) {
4104 DKLOG("%s::powerOff(%d) 0x%qx\n", getName(), powerOff, fPowerStates);
4105 }
4106
4107 IOLockLock(fLock);
4108 services = OSArray::withArray(fServices);
4109
4110 if (powerOff) {
4111 fSystemPowerAck = (0 != fPowerStates);
4112 if (!fSystemPowerAck) {
4113 fSystemOff = true;
4114 }
4115 IOLockUnlock(fLock);
4116
4117 if (!fSystemPowerAck) {
4118 IOServicePH::serverAck(this);
4119 } else {
4120 if (services) {
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);
4126 }
4127 service->reserved->uvars->powerOverride = service->getPowerState();
4128 service->changePowerStateWithOverrideTo(0, 0);
4129 return false;
4130 });
4131 }
4132 }
4133 } else {
4134 fSystemOff = false;
4135 IOLockUnlock(fLock);
4136 if (services) {
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);
4143 }
4144 service->changePowerStateWithOverrideTo(service->reserved->uvars->powerOverride, 0);
4145 service->reserved->uvars->powerOverride = -1U;
4146 }
4147 return false;
4148 });
4149 }
4150 }
4151 OSSafeReleaseNULL(services);
4152}
4153
4154
c3c9b80d
A
4155void
4156IOUserServer::systemHalt(void)
4157{
4158 OSArray * services;
4159
4160 if (true || (kIODKLogPM & gIODKDebug)) {
4161 DKLOG("%s::systemHalt()\n", getName());
4162 }
4163
4164 IOLockLock(fLock);
4165 services = OSArray::withArray(fServices);
4166 IOLockUnlock(fLock);
4167
4168 if (services) {
4169 services->iterateObjects(^bool (OSObject * obj) {
4170 IOService * service;
4171 IOService * provider;
4172 IOOptionBits terminateOptions;
4173 bool root;
4174
4175 service = (IOService *) obj;
4176 provider = service->getProvider();
4177 if (!provider) {
4178 DKLOG("stale service " DKS " found, skipping termination\n", DKN(service));
4179 return false;
4180 }
4181 root = (NULL == provider->getProperty(gIOUserServerNameKey, gIOServicePlane));
4182 if (true || (kIODKLogPM & gIODKDebug)) {
4183 DKLOG("%d: terminate(" DKS ")\n", root, DKN(service));
4184 }
4185 if (!root) {
4186 return false;
4187 }
4188 terminateOptions = kIOServiceRequired | kIOServiceTerminateNeedWillTerminate;
4189 if (!service->terminate(terminateOptions)) {
4190 IOLog("failed to terminate service %s-0x%llx\n", service->getName(), service->getRegistryEntryID());
4191 }
4192 return false;
4193 });
4194 }
4195 OSSafeReleaseNULL(services);
4196}
cb323159
A
4197
4198IOReturn
4199IOUserServer::serviceStarted(IOService * service, IOService * provider, bool result)
4200{
4201 IOReturn ret;
4202 IOService * pmProvider;
f427ee49 4203 bool joinTree;
cb323159
A
4204
4205 DKLOG(DKS "::start(" DKS ") %s\n", DKN(service), DKN(provider), result ? "ok" : "fail");
4206
4207 if (!result) {
4208 ret = kIOReturnSuccess;
4209 return ret;
4210 }
4211
4212 if (!fRootNotifier) {
4213 ret = registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4214 assert(kIOReturnSuccess == ret);
4215 IOServicePH::serverAdd(this);
4216 fRootNotifier = true;
4217 }
4218
f427ee49 4219 joinTree = false;
cb323159
A
4220 if (!(kIODKDisablePM & gIODKDebug) && !service->pm_vars) {
4221 service->PMinit();
4222 ret = service->registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4223 assert(kIOReturnSuccess == ret);
f427ee49
A
4224 joinTree = true;
4225 }
cb323159 4226
f427ee49
A
4227 pmProvider = service;
4228 while (pmProvider && !pmProvider->inPlane(gIOPowerPlane)) {
4229 pmProvider = pmProvider->getProvider();
4230 }
4231 if (pmProvider) {
c3c9b80d 4232 IOService * entry;
f427ee49 4233 OSObject * prop;
c3c9b80d 4234 OSObject * nextProp;
f427ee49 4235 OSString * str;
c3c9b80d
A
4236
4237 entry = pmProvider;
4238 prop = NULL;
4239 do {
4240 nextProp = entry->copyProperty("non-removable");
4241 if (nextProp) {
4242 OSSafeReleaseNULL(prop);
4243 prop = nextProp;
4244 }
4245 entry = entry->getProvider();
4246 } while (entry);
f427ee49
A
4247 if (prop) {
4248 str = OSDynamicCast(OSString, prop);
4249 if (str && str->isEqualTo("yes")) {
4250 pmProvider = NULL;
cb323159 4251 }
f427ee49 4252 prop->release();
cb323159 4253 }
f427ee49 4254 }
cb323159 4255
f427ee49
A
4256 if (!(kIODKDisablePM & gIODKDebug) && pmProvider) {
4257 IOLockLock(fLock);
4258 unsigned int idx = fServices->getNextIndexOfObject(service, 0);
4259 assert(idx <= 63);
4260 fPowerStates |= (1ULL << idx);
4261 IOLockUnlock(fLock);
4262
4263 if (joinTree) {
cb323159
A
4264 pmProvider->joinPMtree(service);
4265 service->reserved->uvars->userServerPM = true;
4266 }
4267 }
4268
4269 service->registerInterestedDriver(this);
4270 service->reserved->uvars->started = true;
4271
4272 return kIOReturnSuccess;
4273}
4274
4275
4276IOReturn
4277IOUserServer::serviceOpen(IOService * provider, IOService * client)
4278{
4279 OSObjectUserVars * uvars;
4280
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);
4286 }
4287
4288 return kIOReturnSuccess;
4289}
4290
4291IOReturn
4292IOUserServer::serviceClose(IOService * provider, IOService * client)
4293{
4294 OSObjectUserVars * uvars;
4295 unsigned int idx;
4296
4297 uvars = client->reserved->uvars;
4298 if (!uvars->openProviders) {
4299 return kIOReturnNotOpen;
4300 }
4301 idx = uvars->openProviders->getNextIndexOfObject(client, 0);
4302 if (-1U == idx) {
4303 return kIOReturnNotOpen;
4304 }
4305 uvars->openProviders->removeObject(idx);
4306
4307 return kIOReturnSuccess;
4308}
4309
4310
4311IOReturn
4312IOUserServer::serviceStop(IOService * service, IOService *)
4313{
4314 IOReturn ret;
4315 uint32_t idx, queueAlloc;
4316 OSObjectUserVars * uvars;
4317
4318 IOLockLock(fLock);
4319 idx = fServices->getNextIndexOfObject(service, 0);
4320 if (-1U != idx) {
4321 fServices->removeObject(idx);
4322 uvars = service->reserved->uvars;
4323 uvars->stopped = true;
4324 }
4325 IOLockUnlock(fLock);
4326
4327 if (-1U == idx) {
4328 return kIOReturnSuccess;
4329 }
4330
cb323159
A
4331 if (uvars->queueArray && uvars->userMeta) {
4332 queueAlloc = 1;
4333 if (uvars->userMeta->queueNames) {
4334 queueAlloc += uvars->userMeta->queueNames->count;
4335 }
4336 for (idx = 0; idx < queueAlloc; idx++) {
4337 OSSafeReleaseNULL(uvars->queueArray[idx]);
4338 }
4339 IOSafeDeleteNULL(uvars->queueArray, IODispatchQueue *, queueAlloc);
4340 }
4341
4342 (void) service->deRegisterInterestedDriver(this);
4343 if (uvars->userServerPM) {
4344 service->PMstop();
4345 }
4346
4347 ret = kIOReturnSuccess;
4348 return ret;
4349}
4350
4351void
4352IOUserServer::serviceFree(IOService * service)
4353{
4354 OSObjectUserVars * uvars;
4355
4356 uvars = service->reserved->uvars;
4357 if (!uvars) {
4358 return;
4359 }
4360 OSSafeReleaseNULL(uvars->userServer);
4361 IOSafeDeleteNULL(service->reserved->uvars, OSObjectUserVars, 1);
4362}
4363
4364void
4365IOUserServer::serviceWillTerminate(IOService * client, IOService * provider, IOOptionBits options)
4366{
4367 IOReturn ret;
4368 bool willTerminate;
4369
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;
4376 }
4377 client->unlockForArbitration();
4378 }
4379
4380 if (willTerminate) {
c3c9b80d 4381 if ((true) || IOServicePH::serverSlept()) {
f427ee49
A
4382 client->Stop_async(provider);
4383 ret = kIOReturnOffline;
4384 } else {
4385 ret = client->Stop(provider);
4386 }
cb323159 4387 if (kIOReturnSuccess != ret) {
f427ee49
A
4388 IOUserServer::serviceDidStop(client, provider);
4389 ret = kIOReturnSuccess;
cb323159
A
4390 }
4391 }
4392}
4393
4394void
4395IOUserServer::serviceDidTerminate(IOService * client, IOService * provider, IOOptionBits options, bool * defer)
4396{
4397 if (client->lockForArbitration(true)) {
4398 client->reserved->uvars->didTerminate = true;
4399 if (!client->reserved->uvars->serverDied
4400 && !client->reserved->uvars->stopped) {
4401 *defer = true;
4402 }
4403 client->unlockForArbitration();
4404 }
4405}
4406
4407void
4408IOUserServer::serviceDidStop(IOService * client, IOService * provider)
4409{
4410 bool complete;
4411 OSArray * closeArray;
4412
4413 complete = false;
4414 closeArray = NULL;
4415
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;
4422 }
4423
4424 if (client->reserved->uvars) {
4425 closeArray = client->reserved->uvars->openProviders;
4426 client->reserved->uvars->openProviders = NULL;
4427 }
4428 client->unlockForArbitration();
4429 if (closeArray) {
4430 closeArray->iterateObjects(^bool (OSObject * obj) {
4431 IOService * toClose;
4432 toClose = OSDynamicCast(IOService, obj);
4433 if (toClose) {
4434 DKLOG(DKS ":force close (" DKS ")\n", DKN(client), DKN(toClose));
4435 toClose->close(client);
4436 }
4437 return false;
4438 });
4439 closeArray->release();
4440 }
4441 }
4442 if (complete) {
4443 bool defer = false;
4444 client->didTerminate(provider, 0, &defer);
4445 }
4446}
4447
c3c9b80d
A
4448kern_return_t
4449IOService::ClientCrashed_Impl(
4450 IOService * client,
4451 uint64_t options)
4452{
4453 return kIOReturnUnsupported;
4454}
4455
cb323159 4456kern_return_t
f427ee49
A
4457IOService::Stop_Impl(
4458 IOService * provider)
cb323159
A
4459{
4460 IOUserServer::serviceDidStop(this, provider);
4461
4462 return kIOReturnSuccess;
4463}
4464
f427ee49
A
4465void
4466IOService::Stop_async_Impl(
4467 IOService * provider)
4468{
4469}
4470
cb323159
A
4471/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4472
4473#undef super
4474#define super IOUserClient
4475
4476OSDefineMetaClassAndStructors(IOUserUserClient, IOUserClient)
4477
4478/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4479
4480IOReturn
4481IOUserUserClient::setTask(task_t task)
4482{
4483 task_reference(task);
4484 fTask = task;
4485
4486 return kIOReturnSuccess;
4487}
4488
4489void
4490IOUserUserClient::stop(IOService * provider)
4491{
4492 if (fTask) {
4493 task_deallocate(fTask);
4494 fTask = NULL;
4495 }
4496 super::stop(provider);
4497}
4498
4499IOReturn
4500IOUserUserClient::clientClose(void)
4501{
ea3f0419 4502 terminate(kIOServiceTerminateNeedWillTerminate);
cb323159
A
4503 return kIOReturnSuccess;
4504}
4505
4506IOReturn
4507IOUserUserClient::setProperties(OSObject * properties)
4508{
4509 IOReturn ret = kIOReturnUnsupported;
4510 return ret;
4511}
4512
4513struct IOUserUserClientActionRef {
4514 OSAsyncReference64 asyncRef;
4515};
4516
4517void
f427ee49
A
4518IOUserClient::KernelCompletion_Impl(
4519 OSAction * action,
4520 IOReturn status,
4521 const unsigned long long * asyncData,
4522 uint32_t asyncDataCount)
cb323159
A
4523{
4524 IOUserUserClientActionRef * ref;
4525
4526 ref = (typeof(ref))action->GetReference();
4527
4528 IOUserClient::sendAsyncResult64(ref->asyncRef, status, (io_user_reference_t *) asyncData, asyncDataCount);
4529}
4530
4531kern_return_t
f427ee49
A
4532IOUserClient::_ExternalMethod_Impl(
4533 uint64_t selector,
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)
cb323159
A
4544{
4545 return kIOReturnUnsupported;
4546}
4547
4548IOReturn
4549IOUserUserClient::clientMemoryForType(UInt32 type,
4550 IOOptionBits * koptions,
4551 IOMemoryDescriptor ** kmemory)
4552{
4553 IOReturn kr;
4554 uint64_t options;
4555 IOMemoryDescriptor * memory;
4556
4557 kr = CopyClientMemoryForType(type, &options, &memory);
4558
4559 *koptions = 0;
4560 *kmemory = NULL;
4561 if (kIOReturnSuccess != kr) {
4562 return kr;
4563 }
4564
4565 if (kIOUserClientMemoryReadOnly & options) {
4566 *koptions |= kIOMapReadOnly;
4567 }
4568 *kmemory = memory;
4569
4570 return kr;
4571}
4572
4573IOReturn
4574IOUserUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
4575 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
4576{
4577 IOReturn kr;
4578 OSData * structureInput;
4579 OSData * structureOutput;
4580 size_t copylen;
4581 uint64_t structureOutputSize;
4582 OSAction * action;
4583 IOUserUserClientActionRef * ref;
4584
4585 kr = kIOReturnUnsupported;
4586 structureInput = NULL;
4587 action = NULL;
f427ee49 4588 ref = NULL;
cb323159
A
4589
4590 if (args->structureInputSize) {
4591 structureInput = OSData::withBytesNoCopy((void *) args->structureInput, args->structureInputSize);
4592 }
4593
4594 if (MACH_PORT_NULL != args->asyncWakePort) {
c3c9b80d
A
4595 // this retain is for the OSAction to release
4596 iokit_make_port_send(args->asyncWakePort);
cb323159
A
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]));
f427ee49
A
4601 kr = action->SetAbortedHandler(^(void) {
4602 IOUserUserClientActionRef * ref;
4603 IOReturn ret;
4604
4605 ref = (typeof(ref))action->GetReference();
4606 ret = releaseAsyncReference64(ref->asyncRef);
4607 assert(kIOReturnSuccess == ret);
4608 bzero(&ref->asyncRef[0], sizeof(ref->asyncRef));
4609 });
4610 assert(KERN_SUCCESS == kr);
cb323159
A
4611 }
4612
4613 if (args->structureVariableOutputData) {
4614 structureOutputSize = kIOUserClientVariableStructureSize;
4615 } else if (args->structureOutputDescriptor) {
4616 structureOutputSize = args->structureOutputDescriptor->getLength();
4617 } else {
4618 structureOutputSize = args->structureOutputSize;
4619 }
4620
4621 kr = _ExternalMethod(selector, &args->scalarInput[0], args->scalarInputCount,
4622 structureInput, args->structureInputDescriptor,
4623 args->scalarOutput, &args->scalarOutputCount,
4624 structureOutputSize, &structureOutput, args->structureOutputDescriptor,
4625 action);
4626
4627 OSSafeReleaseNULL(structureInput);
4628 OSSafeReleaseNULL(action);
4629
4630 if (kIOReturnSuccess != kr) {
c3c9b80d 4631 // mig will destroy any async port
cb323159
A
4632 return kr;
4633 }
c3c9b80d
A
4634 if (MACH_PORT_NULL != args->asyncWakePort) {
4635 // this release is for the mig created send right
4636 iokit_release_port_send(args->asyncWakePort);
4637 }
4638
cb323159
A
4639 if (structureOutput) {
4640 if (args->structureVariableOutputData) {
4641 *args->structureVariableOutputData = structureOutput;
4642 } else {
4643 copylen = structureOutput->getLength();
4644 if (copylen > args->structureOutputSize) {
4645 kr = kIOReturnBadArgument;
4646 } else {
4647 bcopy((const void *) structureOutput->getBytesNoCopy(), args->structureOutput, copylen);
4648 }
4649 OSSafeReleaseNULL(structureOutput);
4650 }
4651 }
4652
4653 return kr;
4654}
4655
4656/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
f427ee49
A
4657
4658void
4659IOUserServerCheckInToken::setNoSendersNotification(IOUserServerCheckInNotificationHandler handler,
4660 void* handlerArgs)
4661{
4662 this->handler = handler;
4663 this->handlerArgs = handlerArgs;
4664}
4665
4666void
4667IOUserServerCheckInToken::notifyNoSenders(IOUserServerCheckInToken *token)
4668{
4669 if (token->handler) {
4670 token->handler(token, token->handlerArgs);
4671 }
4672}
4673
4674void
4675IOUserServerCheckInToken::clearNotification()
4676{
4677 this->handler = NULL;
4678 this->handlerArgs = NULL;
4679}
4680
4681IOUserServerCheckInToken *
4682IOUserServerCheckInToken::create()
4683{
4684 IOUserServerCheckInToken *me = new IOUserServerCheckInToken;
4685 if (me && !me->init()) {
4686 me->release();
4687 return NULL;
4688 }
4689 me->clearNotification();
4690 return me;
4691}
4692
4693/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */