1 /*
2 * Copyright (c) 1998-2021 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/IOKernelReportStructs.h>
33 #include <IOKit/IOUserClient.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IORegistryEntry.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOMemoryDescriptor.h>
38 #include <IOKit/IOBufferMemoryDescriptor.h>
39 #include <IOKit/IOSubMemoryDescriptor.h>
40 #include <IOKit/IOMultiMemoryDescriptor.h>
41 #include <IOKit/IOMapper.h>
42 #include <IOKit/IOLib.h>
43 #include <IOKit/IOHibernatePrivate.h>
44 #include <IOKit/IOBSD.h>
45 #include <IOKit/system.h>
46 #include <IOKit/IOUserServer.h>
47 #include <IOKit/IOInterruptEventSource.h>
48 #include <IOKit/IOTimerEventSource.h>
49 #include <IOKit/pwr_mgt/RootDomain.h>
50 #include <libkern/c++/OSAllocation.h>
51 #include <libkern/c++/OSKext.h>
52 #include <libkern/c++/OSSharedPtr.h>
53 #include <libkern/OSDebug.h>
54 #include <libkern/Block.h>
55 #include <sys/proc.h>
56 #include <sys/reboot.h>
57 #include "IOKitKernelInternal.h"
58
59 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
60
61 #include <DriverKit/IODispatchQueue.h>
62 #include <DriverKit/OSObject.h>
63 #include <DriverKit/OSAction.h>
64 #include <DriverKit/IODispatchSource.h>
65 #include <DriverKit/IOInterruptDispatchSource.h>
66 #include <DriverKit/IOService.h>
67 #include <DriverKit/IOMemoryDescriptor.h>
68 #include <DriverKit/IOBufferMemoryDescriptor.h>
69 #include <DriverKit/IOMemoryMap.h>
70 #include <DriverKit/IODataQueueDispatchSource.h>
71 #include <DriverKit/IOServiceNotificationDispatchSource.h>
72 #include <DriverKit/IOServiceStateNotificationDispatchSource.h>
73 #include <DriverKit/IOEventLink.h>
74 #include <DriverKit/IOWorkGroup.h>
75 #include <DriverKit/IOUserServer.h>
76
77 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
78
79 #include <System/IODataQueueDispatchSourceShared.h>
80
81 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
82
83 TUNABLE(SInt64, gIODKDebug, "dk", kIODKEnable);
84
85 static OSString * gIOSystemStateSleepDescriptionKey;
86 static const OSSymbol * gIOSystemStateSleepDescriptionReasonKey;
87 static const OSSymbol * gIOSystemStateSleepDescriptionHibernateStateKey;
88
89 static OSString * gIOSystemStateHaltDescriptionKey;
90 static const OSSymbol * gIOSystemStateHaltDescriptionHaltStateKey;
91
92 static OSString * gIOSystemStatePowerSourceDescriptionKey;
93 static const OSSymbol * gIOSystemStatePowerSourceDescriptionACAttachedKey;
94
95 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
96
97 struct IOPStrings;
98
99 class OSUserMetaClass : public OSObject
100 {
101 OSDeclareDefaultStructors(OSUserMetaClass);
102 public:
103 const OSSymbol * name;
104 const OSMetaClass * meta;
105 OSUserMetaClass * superMeta;
106
107 queue_chain_t link;
108
109 OSClassDescription * description;
110 IOPStrings * queueNames;
111 uint32_t methodCount;
112 uint64_t * methods;
113
114 virtual void free() override;
115 virtual kern_return_t Dispatch(const IORPC rpc) APPLE_KEXT_OVERRIDE;
116 };
117 OSDefineMetaClassAndStructors(OSUserMetaClass, OSObject);
118
119 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
120
121 class IOUserService : public IOService
122 {
123 friend class IOService;
124
125 OSDeclareDefaultStructors(IOUserService)
126
127 virtual bool
128 start(IOService * provider) APPLE_KEXT_OVERRIDE;
129 };
130
131 OSDefineMetaClassAndStructors(IOUserService, IOService)
132
133 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
134
135 class IOUserUserClient : public IOUserClient
136 {
137 OSDeclareDefaultStructors(IOUserUserClient);
138 public:
139 task_t fTask;
140 OSDictionary * fWorkGroups;
141 OSDictionary * fEventLinks;
142 IOLock * fLock;
143
144 IOReturn setTask(task_t task);
145 IOReturn eventlinkConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
146 IOReturn workgroupConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
147
148 virtual bool init( OSDictionary * dictionary ) APPLE_KEXT_OVERRIDE;
149 virtual void free() APPLE_KEXT_OVERRIDE;
150 virtual void stop(IOService * provider) APPLE_KEXT_OVERRIDE;
151 virtual IOReturn clientClose(void) APPLE_KEXT_OVERRIDE;
152 virtual IOReturn setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
153 virtual IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments * args,
154 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) APPLE_KEXT_OVERRIDE;
155 virtual IOReturn clientMemoryForType(UInt32 type,
156 IOOptionBits * options,
157 IOMemoryDescriptor ** memory) APPLE_KEXT_OVERRIDE;
158 virtual IOExternalTrap * getTargetAndTrapForIndex( IOService **targetP, UInt32 index ) APPLE_KEXT_OVERRIDE;
159 };
160
161 OSDefineMetaClassAndStructors(IOUserServerCheckInToken, OSObject);
162 OSDefineMetaClassAndStructors(_IOUserServerCheckInCancellationHandler, OSObject);
163
164 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
165
166
167 bool
start(IOService * provider)168 IOUserService::start(IOService * provider)
169 {
170 bool ok = true;
171 IOReturn ret;
172
173 ret = Start(provider);
174 if (kIOReturnSuccess != ret) {
175 return false;
176 }
177
178 return ok;
179 }
180
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
182
183 #undef super
184
185 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
186
187 struct IODispatchQueue_IVars {
188 IOUserServer * userServer;
189 IODispatchQueue * queue;
190 queue_chain_t link;
191 uint64_t tid;
192
193 mach_port_t serverPort;
194 };
195
196 struct OSAction_IVars {
197 OSObject * target;
198 uint64_t targetmsgid;
199 uint64_t msgid;
200 IOUserServer * userServer;
201 OSActionAbortedHandler abortedHandler;
202 OSString * typeName;
203 void * reference;
204 size_t referenceSize;
205 };
206
207 struct IOWorkGroup_IVars {
208 IOUserServer * userServer;
209 OSString * name;
210 IOUserUserClient * userClient;
211 };
212
213 struct IOEventLink_IVars {
214 IOUserServer * userServer;
215 OSString * name;
216 IOUserUserClient * userClient;
217 };
218
219 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
220
221 kern_return_t
GetRegistryEntryID_Impl(uint64_t * registryEntryID)222 IOService::GetRegistryEntryID_Impl(
223 uint64_t * registryEntryID)
224 {
225 IOReturn ret = kIOReturnSuccess;
226
227 *registryEntryID = getRegistryEntryID();
228
229 return ret;
230 }
231
232 kern_return_t
SetName_Impl(const char * name)233 IOService::SetName_Impl(
234 const char * name)
235 {
236 IOReturn ret = kIOReturnSuccess;
237
238 setName(name);
239
240 return ret;
241 }
242
243 kern_return_t
CopyName_Impl(OSString ** name)244 IOService::CopyName_Impl(
245 OSString ** name)
246 {
247 const OSString * str = copyName();
248 *name = __DECONST(OSString *, str);
249 return str ? kIOReturnSuccess : kIOReturnError;
250 }
251
252
253 kern_return_t
Start_Impl(IOService * provider)254 IOService::Start_Impl(
255 IOService * provider)
256 {
257 IOReturn ret = kIOReturnSuccess;
258 return ret;
259 }
260
261
262 IOReturn
UpdateReport_Impl(OSData * channels,uint32_t action,uint32_t * outElementCount,uint64_t offset,uint64_t capacity,IOMemoryDescriptor * buffer)263 IOService::UpdateReport_Impl(OSData *channels, uint32_t action,
264 uint32_t *outElementCount,
265 uint64_t offset, uint64_t capacity,
266 IOMemoryDescriptor *buffer)
267 {
268 return kIOReturnUnsupported;
269 }
270
271 IOReturn
ConfigureReport_Impl(OSData * channels,uint32_t action,uint32_t * outCount)272 IOService::ConfigureReport_Impl(OSData *channels, uint32_t action, uint32_t *outCount)
273 {
274 return kIOReturnUnsupported;
275 }
276
277 // adapt old signature of configureReport to the iig-friendly signature of ConfigureReport
278 IOReturn
_ConfigureReport(IOReportChannelList * channelList,IOReportConfigureAction action,void * result,void * destination)279 IOService::_ConfigureReport(IOReportChannelList *channelList,
280 IOReportConfigureAction action,
281 void *result,
282 void *destination)
283 {
284 if (action != kIOReportEnable && action != kIOReportGetDimensions && action != kIOReportDisable) {
285 return kIOReturnUnsupported;
286 }
287 static_assert(sizeof(IOReportChannelList) == 8);
288 static_assert(sizeof(IOReportChannel) == 16);
289 unsigned int size_of_channels;
290 bool overflow = os_mul_and_add_overflow(channelList->nchannels, sizeof(IOReportChannel), sizeof(IOReportChannelList), &size_of_channels);
291 if (overflow) {
292 return kIOReturnOverrun;
293 }
294 OSSharedPtr<OSData> sp_channels(OSData::withBytesNoCopy(channelList, size_of_channels), libkern::no_retain);
295 if (!sp_channels) {
296 return kIOReturnNoMemory;
297 }
298 int *resultp = (int*) result;
299 uint32_t count = 0;
300 IOReturn r = ConfigureReport(sp_channels.get(), action, &count);
301 int new_result;
302 overflow = os_add_overflow(*resultp, count, &new_result);
303 if (overflow) {
304 return kIOReturnOverrun;
305 }
306 *resultp = new_result;
307 return r;
308 }
309
310 // adapt old signature of updateReport to the iig-friendly signature of UpdateReport
311 IOReturn
_UpdateReport(IOReportChannelList * channelList,IOReportUpdateAction action,void * result,void * destination)312 IOService::_UpdateReport(IOReportChannelList *channelList,
313 IOReportUpdateAction action,
314 void *result,
315 void *destination)
316 {
317 if (action != kIOReportCopyChannelData) {
318 return kIOReturnUnsupported;
319 }
320 unsigned int size_of_channels;
321 bool overflow = os_mul_and_add_overflow(channelList->nchannels, sizeof(IOReportChannel), sizeof(IOReportChannelList), &size_of_channels);
322 if (overflow) {
323 return kIOReturnOverrun;
324 }
325 OSSharedPtr<OSData> sp_channels(OSData::withBytesNoCopy(channelList, size_of_channels), libkern::no_retain);
326 if (!sp_channels) {
327 return kIOReturnNoMemory;
328 }
329 int *resultp = (int*) result;
330 uint32_t count = 0;
331 auto buffer = (IOBufferMemoryDescriptor*) destination;
332 uint64_t length = buffer->getLength();
333 buffer->setLength(buffer->getCapacity());
334 IOReturn r = UpdateReport(sp_channels.get(), action, &count, length, buffer->getCapacity() - length, buffer);
335 int new_result;
336 overflow = os_add_overflow(*resultp, count, &new_result);
337 size_t new_length;
338 overflow = overflow || os_mul_and_add_overflow(count, sizeof(IOReportElement), length, &new_length);
339 if (overflow || new_length > buffer->getCapacity()) {
340 buffer->setLength(length);
341 return kIOReturnOverrun;
342 }
343 *resultp = new_result;
344 buffer->setLength(new_length);
345 return r;
346 }
347
348
349 IOReturn
SetLegend_Impl(OSArray * legend,bool is_public)350 IOService::SetLegend_Impl(OSArray *legend, bool is_public)
351 {
352 bool ok = setProperty(kIOReportLegendKey, legend);
353 ok = ok && setProperty(kIOReportLegendPublicKey, is_public);
354 return ok ? kIOReturnSuccess : kIOReturnError;
355 }
356
357
358 kern_return_t
RegisterService_Impl()359 IOService::RegisterService_Impl()
360 {
361 IOReturn ret = kIOReturnSuccess;
362
363 registerService(kIOServiceAsynchronous);
364
365 return ret;
366 }
367
368 kern_return_t
CopyDispatchQueue_Impl(const char * name,IODispatchQueue ** queue)369 IOService::CopyDispatchQueue_Impl(
370 const char * name,
371 IODispatchQueue ** queue)
372 {
373 IODispatchQueue * result;
374 IOService * service;
375 IOReturn ret;
376 uint32_t index;
377
378 if (!reserved->uvars) {
379 return kIOReturnError;
380 }
381
382 ret = kIOReturnNotFound;
383 index = -1U;
384 if (!strcmp("Default", name)) {
385 index = 0;
386 } else if (reserved->uvars->userMeta
387 && reserved->uvars->userMeta->queueNames) {
388 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
389 if (index != -1U) {
390 index++;
391 }
392 }
393 if (index == -1U) {
394 if ((service = getProvider())) {
395 ret = service->CopyDispatchQueue(name, queue);
396 }
397 } else {
398 result = reserved->uvars->queueArray[index];
399 if (result) {
400 result->retain();
401 *queue = result;
402 ret = kIOReturnSuccess;
403 }
404 }
405
406 return ret;
407 }
408
409 kern_return_t
CreateDefaultDispatchQueue_Impl(IODispatchQueue ** queue)410 IOService::CreateDefaultDispatchQueue_Impl(
411 IODispatchQueue ** queue)
412 {
413 return kIOReturnError;
414 }
415
416 kern_return_t
CoreAnalyticsSendEvent_Impl(uint64_t options,OSString * eventName,OSDictionary * eventPayload)417 IOService::CoreAnalyticsSendEvent_Impl(
418 uint64_t options,
419 OSString * eventName,
420 OSDictionary * eventPayload)
421 {
422 kern_return_t ret;
423
424 if (NULL == gIOCoreAnalyticsSendEventProc) {
425 // perhaps save for later?
426 return kIOReturnNotReady;
427 }
428
429 ret = (*gIOCoreAnalyticsSendEventProc)(options, eventName, eventPayload);
430
431 return ret;
432 }
433
434 kern_return_t
SetDispatchQueue_Impl(const char * name,IODispatchQueue * queue)435 IOService::SetDispatchQueue_Impl(
436 const char * name,
437 IODispatchQueue * queue)
438 {
439 IOReturn ret = kIOReturnSuccess;
440 uint32_t index;
441
442 if (!reserved->uvars) {
443 return kIOReturnError;
444 }
445
446 if (kIODKLogSetup & gIODKDebug) {
447 DKLOG(DKS "::SetDispatchQueue(%s)\n", DKN(this), name);
448 }
449 queue->ivars->userServer = reserved->uvars->userServer;
450 index = -1U;
451 if (!strcmp("Default", name)) {
452 index = 0;
453 } else if (reserved->uvars->userMeta
454 && reserved->uvars->userMeta->queueNames) {
455 index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
456 if (index != -1U) {
457 index++;
458 }
459 }
460 if (index == -1U) {
461 ret = kIOReturnBadArgument;
462 } else {
463 reserved->uvars->queueArray[index] = queue;
464 queue->retain();
465 }
466
467 return ret;
468 }
469
470 IOService *
GetProvider() const471 IOService::GetProvider() const
472 {
473 return getProvider();
474 }
475
476 kern_return_t
SetProperties_Impl(OSDictionary * properties)477 IOService::SetProperties_Impl(
478 OSDictionary * properties)
479 {
480 IOUserServer * us;
481 OSDictionary * dict;
482 IOReturn ret;
483
484 us = (typeof(us))thread_iokit_tls_get(0);
485 dict = OSDynamicCast(OSDictionary, properties);
486 if (NULL == us) {
487 if (!dict) {
488 return kIOReturnBadArgument;
489 }
490 bool ok __block = true;
491 dict->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
492 ok = setProperty(key, value);
493 return !ok;
494 });
495 ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
496 return ret;
497 }
498
499 ret = setProperties(properties);
500
501 if (kIOReturnUnsupported == ret) {
502 if (dict && reserved->uvars && (reserved->uvars->userServer == us)) {
503 ret = runPropertyActionBlock(^IOReturn (void) {
504 OSDictionary * userProps;
505 IOReturn ret;
506
507 userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
508 if (userProps) {
509 userProps = (typeof(userProps))userProps->copyCollection();
510 } else {
511 userProps = OSDictionary::withCapacity(4);
512 }
513 if (!userProps) {
514 ret = kIOReturnNoMemory;
515 } else {
516 bool ok = userProps->merge(dict);
517 if (ok) {
518 ok = setProperty(gIOUserServicePropertiesKey, userProps);
519 }
520 OSSafeReleaseNULL(userProps);
521 ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
522 }
523 return ret;
524 });
525 }
526 }
527
528 return ret;
529 }
530
531 kern_return_t
RemoveProperty_Impl(OSString * propertyName)532 IOService::RemoveProperty_Impl(OSString * propertyName)
533 {
534 IOUserServer * us = (IOUserServer *)thread_iokit_tls_get(0);
535 IOReturn ret = kIOReturnUnsupported;
536
537 if (NULL == propertyName) {
538 return kIOReturnUnsupported;
539 }
540 if (NULL == us) {
541 removeProperty(propertyName);
542 return kIOReturnSuccess;
543 }
544 if (reserved && reserved->uvars && reserved->uvars->userServer == us) {
545 ret = runPropertyActionBlock(^IOReturn (void) {
546 OSDictionary * userProps;
547 userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
548 if (userProps) {
549 userProps = (OSDictionary *)userProps->copyCollection();
550 if (!userProps) {
551 return kIOReturnNoMemory;
552 }
553 userProps->removeObject(propertyName);
554 bool ok = setProperty(gIOUserServicePropertiesKey, userProps);
555 OSSafeReleaseNULL(userProps);
556 return ok ? kIOReturnSuccess : kIOReturnNotWritable;
557 } else {
558 return kIOReturnNotFound;
559 }
560 });
561 }
562 return ret;
563 }
564
565 kern_return_t
CopyProperties_Impl(OSDictionary ** properties)566 IOService::CopyProperties_Impl(
567 OSDictionary ** properties)
568 {
569 OSDictionary * props;
570 OSDictionary * userProps;
571
572 props = dictionaryWithProperties();
573 userProps = OSDynamicCast(OSDictionary, props->getObject(gIOUserServicePropertiesKey));
574 if (userProps) {
575 props->merge(userProps);
576 props->removeObject(gIOUserServicePropertiesKey);
577 }
578
579 *properties = props;
580
581 return props ? kIOReturnSuccess : kIOReturnNoMemory;
582 }
583
584 kern_return_t
RequireMaxBusStall_Impl(uint64_t u64ns)585 IOService::RequireMaxBusStall_Impl(
586 uint64_t u64ns)
587 {
588 IOReturn ret;
589 UInt32 ns;
590
591 if (os_convert_overflow(u64ns, &ns)) {
592 return kIOReturnBadArgument;
593 }
594 ret = requireMaxBusStall(ns);
595
596 return kIOReturnSuccess;
597 }
598
599 #if PRIVATE_WIFI_ONLY
600 kern_return_t
UserSetProperties_Impl(OSContainer * properties)601 IOService::UserSetProperties_Impl(
602 OSContainer * properties)
603 {
604 return kIOReturnUnsupported;
605 }
606 #endif /* PRIVATE_WIFI_ONLY */
607
608 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
609
610 kern_return_t
_CopyState_Impl(_IOMDPrivateState * state)611 IOMemoryDescriptor::_CopyState_Impl(
612 _IOMDPrivateState * state)
613 {
614 IOReturn ret;
615
616 state->length = _length;
617 state->options = _flags;
618
619 ret = kIOReturnSuccess;
620
621 return ret;
622 }
623
624 kern_return_t
GetLength(uint64_t * returnLength)625 IOMemoryDescriptor::GetLength(uint64_t * returnLength)
626 {
627 *returnLength = getLength();
628
629 return kIOReturnSuccess;
630 }
631
632 kern_return_t
CreateMapping_Impl(uint64_t options,uint64_t address,uint64_t offset,uint64_t length,uint64_t alignment,IOMemoryMap ** map)633 IOMemoryDescriptor::CreateMapping_Impl(
634 uint64_t options,
635 uint64_t address,
636 uint64_t offset,
637 uint64_t length,
638 uint64_t alignment,
639 IOMemoryMap ** map)
640 {
641 IOReturn ret;
642 IOMemoryMap * resultMap;
643 IOOptionBits koptions;
644 mach_vm_address_t atAddress;
645
646 ret = kIOReturnSuccess;
647 koptions = 0;
648 resultMap = NULL;
649
650 if (kIOMemoryMapFixedAddress & options) {
651 atAddress = address;
652 koptions = 0;
653 } else {
654 switch (kIOMemoryMapGuardedMask & options) {
655 default:
656 case kIOMemoryMapGuardedDefault:
657 koptions |= kIOMapGuardedSmall;
658 break;
659 case kIOMemoryMapGuardedNone:
660 break;
661 case kIOMemoryMapGuardedSmall:
662 koptions |= kIOMapGuardedSmall;
663 break;
664 case kIOMemoryMapGuardedLarge:
665 koptions |= kIOMapGuardedLarge;
666 break;
667 }
668 atAddress = 0;
669 koptions |= kIOMapAnywhere;
670 }
671
672 if ((kIOMemoryMapReadOnly & options) || (kIODirectionOut == getDirection())) {
673 if (!reserved || (current_task() != reserved->creator)) {
674 koptions |= kIOMapReadOnly;
675 }
676 }
677
678 switch (0xFF00 & options) {
679 case kIOMemoryMapCacheModeDefault:
680 koptions |= kIOMapDefaultCache;
681 break;
682 case kIOMemoryMapCacheModeInhibit:
683 koptions |= kIOMapInhibitCache;
684 break;
685 case kIOMemoryMapCacheModeCopyback:
686 koptions |= kIOMapCopybackCache;
687 break;
688 case kIOMemoryMapCacheModeWriteThrough:
689 koptions |= kIOMapWriteThruCache;
690 break;
691 default:
692 ret = kIOReturnBadArgument;
693 }
694
695 if (kIOReturnSuccess == ret) {
696 resultMap = createMappingInTask(current_task(), atAddress, koptions, offset, length);
697 if (!resultMap) {
698 ret = kIOReturnError;
699 }
700 }
701
702 *map = resultMap;
703
704 return ret;
705 }
706
707 kern_return_t
CreateSubMemoryDescriptor_Impl(uint64_t memoryDescriptorCreateOptions,uint64_t offset,uint64_t length,IOMemoryDescriptor * ofDescriptor,IOMemoryDescriptor ** memory)708 IOMemoryDescriptor::CreateSubMemoryDescriptor_Impl(
709 uint64_t memoryDescriptorCreateOptions,
710 uint64_t offset,
711 uint64_t length,
712 IOMemoryDescriptor * ofDescriptor,
713 IOMemoryDescriptor ** memory)
714 {
715 IOReturn ret;
716 IOMemoryDescriptor * iomd;
717 IOByteCount mdOffset;
718 IOByteCount mdLength;
719 IOByteCount mdEnd;
720
721 if (!ofDescriptor) {
722 return kIOReturnBadArgument;
723 }
724 if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
725 return kIOReturnBadArgument;
726 }
727 if (os_convert_overflow(offset, &mdOffset)) {
728 return kIOReturnBadArgument;
729 }
730 if (os_convert_overflow(length, &mdLength)) {
731 return kIOReturnBadArgument;
732 }
733 if (os_add_overflow(mdOffset, mdLength, &mdEnd)) {
734 return kIOReturnBadArgument;
735 }
736 if (mdEnd > ofDescriptor->getLength()) {
737 return kIOReturnBadArgument;
738 }
739
740 iomd = IOSubMemoryDescriptor::withSubRange(
741 ofDescriptor, mdOffset, mdLength, (IOOptionBits) memoryDescriptorCreateOptions);
742
743 if (iomd) {
744 ret = kIOReturnSuccess;
745 *memory = iomd;
746 } else {
747 ret = kIOReturnNoMemory;
748 *memory = NULL;
749 }
750
751 return ret;
752 }
753
754 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
755
756 kern_return_t
CreateWithMemoryDescriptors_Impl(uint64_t memoryDescriptorCreateOptions,uint32_t withDescriptorsCount,IOMemoryDescriptor ** const withDescriptors,IOMemoryDescriptor ** memory)757 IOMemoryDescriptor::CreateWithMemoryDescriptors_Impl(
758 uint64_t memoryDescriptorCreateOptions,
759 uint32_t withDescriptorsCount,
760 IOMemoryDescriptor ** const withDescriptors,
761 IOMemoryDescriptor ** memory)
762 {
763 IOReturn ret;
764 IOMemoryDescriptor * iomd;
765
766 if (!withDescriptors) {
767 return kIOReturnBadArgument;
768 }
769 if (!withDescriptorsCount) {
770 return kIOReturnBadArgument;
771 }
772 if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
773 return kIOReturnBadArgument;
774 }
775
776 for (unsigned int idx = 0; idx < withDescriptorsCount; idx++) {
777 if (NULL == withDescriptors[idx]) {
778 return kIOReturnBadArgument;
779 }
780 }
781
782 iomd = IOMultiMemoryDescriptor::withDescriptors(withDescriptors, withDescriptorsCount,
783 (IODirection) memoryDescriptorCreateOptions, false);
784
785 if (iomd) {
786 ret = kIOReturnSuccess;
787 *memory = iomd;
788 } else {
789 ret = kIOReturnNoMemory;
790 *memory = NULL;
791 }
792
793 return ret;
794 }
795
796 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
797
798 kern_return_t
CreateMemoryDescriptorFromClient_Impl(uint64_t memoryDescriptorCreateOptions,uint32_t segmentsCount,const IOAddressSegment segments[32],IOMemoryDescriptor ** memory)799 IOUserClient::CreateMemoryDescriptorFromClient_Impl(
800 uint64_t memoryDescriptorCreateOptions,
801 uint32_t segmentsCount,
802 const IOAddressSegment segments[32],
803 IOMemoryDescriptor ** memory)
804 {
805 IOReturn ret;
806 IOMemoryDescriptor * iomd;
807 IOOptionBits mdOptions;
808 IOUserUserClient * me;
809 IOAddressRange * ranges;
810
811 me = OSDynamicCast(IOUserUserClient, this);
812 if (!me) {
813 return kIOReturnBadArgument;
814 }
815 if (!me->fTask) {
816 return kIOReturnNotReady;
817 }
818
819 mdOptions = 0;
820 if (kIOMemoryDirectionOut & memoryDescriptorCreateOptions) {
821 mdOptions |= kIODirectionOut;
822 }
823 if (kIOMemoryDirectionIn & memoryDescriptorCreateOptions) {
824 mdOptions |= kIODirectionIn;
825 }
826 if (!(kIOMemoryDisableCopyOnWrite & memoryDescriptorCreateOptions)) {
827 mdOptions |= kIOMemoryMapCopyOnWrite;
828 }
829
830 static_assert(sizeof(IOAddressRange) == sizeof(IOAddressSegment));
831 ranges = __DECONST(IOAddressRange *, &segments[0]);
832
833 iomd = IOMemoryDescriptor::withAddressRanges(
834 ranges, segmentsCount,
835 mdOptions, me->fTask);
836
837 if (iomd) {
838 ret = kIOReturnSuccess;
839 *memory = iomd;
840 } else {
841 ret = kIOReturnNoMemory;
842 *memory = NULL;
843 }
844
845 return ret;
846 }
847
848 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
849
850 kern_return_t
_CopyState_Impl(_IOMemoryMapPrivateState * state)851 IOMemoryMap::_CopyState_Impl(
852 _IOMemoryMapPrivateState * state)
853 {
854 IOReturn ret;
855
856 state->offset = fOffset;
857 state->length = getLength();
858 state->address = getAddress();
859 state->options = getMapOptions();
860
861 ret = kIOReturnSuccess;
862
863 return ret;
864 }
865
866 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
867
868 kern_return_t
Create_Impl(uint64_t options,uint64_t capacity,uint64_t alignment,IOBufferMemoryDescriptor ** memory)869 IOBufferMemoryDescriptor::Create_Impl(
870 uint64_t options,
871 uint64_t capacity,
872 uint64_t alignment,
873 IOBufferMemoryDescriptor ** memory)
874 {
875 IOReturn ret;
876 IOOptionBits bmdOptions;
877 IOBufferMemoryDescriptor * bmd;
878 IOMemoryDescriptorReserved * reserved;
879
880 if (options & ~((uint64_t) kIOMemoryDirectionOutIn)) {
881 // no other options currently defined
882 return kIOReturnBadArgument;
883 }
884 bmdOptions = (options & kIOMemoryDirectionOutIn) | kIOMemoryKernelUserShared;
885 bmd = IOBufferMemoryDescriptor::inTaskWithOptions(
886 kernel_task, bmdOptions, capacity, alignment);
887
888 *memory = bmd;
889
890 if (!bmd) {
891 return kIOReturnNoMemory;
892 }
893
894 reserved = bmd->getKernelReserved();
895 reserved->creator = current_task();
896 task_reference(reserved->creator);
897
898 ret = kIOReturnSuccess;
899
900 return ret;
901 }
902
903 kern_return_t
SetLength_Impl(uint64_t length)904 IOBufferMemoryDescriptor::SetLength_Impl(
905 uint64_t length)
906 {
907 setLength(length);
908 return kIOReturnSuccess;
909 }
910
911
912 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
913
914 kern_return_t
Create_Impl(IOService * device,uint64_t options,const IODMACommandSpecification * specification,IODMACommand ** command)915 IODMACommand::Create_Impl(
916 IOService * device,
917 uint64_t options,
918 const IODMACommandSpecification * specification,
919 IODMACommand ** command)
920 {
921 IOReturn ret;
922 IODMACommand * dma;
923 IODMACommand::SegmentOptions segmentOptions;
924 IOMapper * mapper;
925
926 if (options & ~((uint64_t) kIODMACommandCreateNoOptions)) {
927 // no other options currently defined
928 return kIOReturnBadArgument;
929 }
930
931 if (os_convert_overflow(specification->maxAddressBits, &segmentOptions.fNumAddressBits)) {
932 return kIOReturnBadArgument;
933 }
934 segmentOptions.fMaxSegmentSize = 0;
935 segmentOptions.fMaxTransferSize = 0;
936 segmentOptions.fAlignment = 1;
937 segmentOptions.fAlignmentLength = 1;
938 segmentOptions.fAlignmentInternalSegments = 1;
939 segmentOptions.fStructSize = sizeof(segmentOptions);
940
941 mapper = IOMapper::copyMapperForDevice(device);
942
943 dma = IODMACommand::withSpecification(
944 kIODMACommandOutputHost64,
945 &segmentOptions,
946 kIODMAMapOptionMapped,
947 mapper,
948 NULL);
949
950 OSSafeReleaseNULL(mapper);
951 *command = dma;
952
953 if (!dma) {
954 return kIOReturnNoMemory;
955 }
956 ret = kIOReturnSuccess;
957
958 return ret;
959 }
960
961 kern_return_t
PrepareForDMA_Impl(uint64_t options,IOMemoryDescriptor * memory,uint64_t offset,uint64_t length,uint64_t * flags,uint32_t * segmentsCount,IOAddressSegment * segments)962 IODMACommand::PrepareForDMA_Impl(
963 uint64_t options,
964 IOMemoryDescriptor * memory,
965 uint64_t offset,
966 uint64_t length,
967 uint64_t * flags,
968 uint32_t * segmentsCount,
969 IOAddressSegment * segments)
970 {
971 IOReturn ret;
972 uint64_t lflags, mdFlags;
973 UInt32 numSegments;
974 UInt64 genOffset;
975
976 if (options & ~((uint64_t) kIODMACommandPrepareForDMANoOptions)) {
977 // no other options currently defined
978 return kIOReturnBadArgument;
979 }
980
981 // uses IOMD direction
982 ret = memory->prepare();
983 if (kIOReturnSuccess != ret) {
984 return ret;
985 }
986
987 ret = setMemoryDescriptor(memory, false);
988 if (kIOReturnSuccess != ret) {
989 memory->complete();
990 return ret;
991 }
992
993 ret = prepare(offset, length);
994 if (kIOReturnSuccess != ret) {
995 clearMemoryDescriptor(false);
996 memory->complete();
997 return ret;
998 }
999
1000 static_assert(sizeof(IODMACommand::Segment64) == sizeof(IOAddressSegment));
1001
1002 numSegments = *segmentsCount;
1003 genOffset = 0;
1004 ret = genIOVMSegments(&genOffset, segments, &numSegments);
1005
1006 if (kIOReturnSuccess == ret) {
1007 mdFlags = fMemory->getFlags();
1008 lflags = 0;
1009 if (kIODirectionOut & mdFlags) {
1010 lflags |= kIOMemoryDirectionOut;
1011 }
1012 if (kIODirectionIn & mdFlags) {
1013 lflags |= kIOMemoryDirectionIn;
1014 }
1015 *flags = lflags;
1016 *segmentsCount = numSegments;
1017 }
1018
1019 return ret;
1020 }
1021
1022 kern_return_t
CompleteDMA_Impl(uint64_t options)1023 IODMACommand::CompleteDMA_Impl(
1024 uint64_t options)
1025 {
1026 IOReturn ret, completeRet;
1027 IOMemoryDescriptor * md;
1028
1029 if (options & ~((uint64_t) kIODMACommandCompleteDMANoOptions)) {
1030 // no other options currently defined
1031 return kIOReturnBadArgument;
1032 }
1033 if (!fActive) {
1034 return kIOReturnNotReady;
1035 }
1036
1037 md = __DECONST(IOMemoryDescriptor *, fMemory);
1038 if (md) {
1039 md->retain();
1040 }
1041
1042 ret = clearMemoryDescriptor(true);
1043
1044 if (md) {
1045 completeRet = md->complete();
1046 OSSafeReleaseNULL(md);
1047 if (kIOReturnSuccess == ret) {
1048 ret = completeRet;
1049 }
1050 }
1051
1052 return ret;
1053 }
1054
1055 kern_return_t
GetPreparation_Impl(uint64_t * offset,uint64_t * length,IOMemoryDescriptor ** memory)1056 IODMACommand::GetPreparation_Impl(
1057 uint64_t * offset,
1058 uint64_t * length,
1059 IOMemoryDescriptor ** memory)
1060 {
1061 IOReturn ret;
1062 IOMemoryDescriptor * md;
1063
1064 if (!fActive) {
1065 return kIOReturnNotReady;
1066 }
1067
1068 ret = getPreparedOffsetAndLength(offset, length);
1069 if (kIOReturnSuccess != ret) {
1070 return ret;
1071 }
1072
1073 if (memory) {
1074 md = __DECONST(IOMemoryDescriptor *, fMemory);
1075 *memory = md;
1076 if (!md) {
1077 ret = kIOReturnNotReady;
1078 } else {
1079 md->retain();
1080 }
1081 }
1082 return ret;
1083 }
1084
1085 kern_return_t
PerformOperation_Impl(uint64_t options,uint64_t dmaOffset,uint64_t length,uint64_t dataOffset,IOMemoryDescriptor * data)1086 IODMACommand::PerformOperation_Impl(
1087 uint64_t options,
1088 uint64_t dmaOffset,
1089 uint64_t length,
1090 uint64_t dataOffset,
1091 IOMemoryDescriptor * data)
1092 {
1093 IOReturn ret;
1094 OSDataAllocation<uint8_t> buffer;
1095 UInt64 copiedDMA;
1096 IOByteCount mdOffset, mdLength, copied;
1097
1098 if (options & ~((uint64_t)
1099 (kIODMACommandPerformOperationOptionRead
1100 | kIODMACommandPerformOperationOptionWrite
1101 | kIODMACommandPerformOperationOptionZero))) {
1102 // no other options currently defined
1103 return kIOReturnBadArgument;
1104 }
1105
1106 if (!fActive) {
1107 return kIOReturnNotReady;
1108 }
1109 if (os_convert_overflow(dataOffset, &mdOffset)) {
1110 return kIOReturnBadArgument;
1111 }
1112 if (os_convert_overflow(length, &mdLength)) {
1113 return kIOReturnBadArgument;
1114 }
1115 if (length > fMemory->getLength()) {
1116 return kIOReturnBadArgument;
1117 }
1118 buffer = OSDataAllocation<uint8_t>(length, OSAllocateMemory);
1119 if (!buffer) {
1120 return kIOReturnNoMemory;
1121 }
1122
1123 switch (options) {
1124 case kIODMACommandPerformOperationOptionZero:
1125 bzero(buffer.data(), length);
1126 copiedDMA = writeBytes(dmaOffset, buffer.data(), length);
1127 if (copiedDMA != length) {
1128 ret = kIOReturnUnderrun;
1129 break;
1130 }
1131 ret = kIOReturnSuccess;
1132 break;
1133
1134 case kIODMACommandPerformOperationOptionRead:
1135 case kIODMACommandPerformOperationOptionWrite:
1136
1137 if (!data) {
1138 ret = kIOReturnBadArgument;
1139 break;
1140 }
1141 if (length > data->getLength()) {
1142 ret = kIOReturnBadArgument;
1143 break;
1144 }
1145 if (kIODMACommandPerformOperationOptionWrite == options) {
1146 copied = data->readBytes(mdOffset, buffer.data(), mdLength);
1147 if (copied != mdLength) {
1148 ret = kIOReturnUnderrun;
1149 break;
1150 }
1151 copiedDMA = writeBytes(dmaOffset, buffer.data(), length);
1152 if (copiedDMA != length) {
1153 ret = kIOReturnUnderrun;
1154 break;
1155 }
1156 } else { /* kIODMACommandPerformOperationOptionRead */
1157 copiedDMA = readBytes(dmaOffset, buffer.data(), length);
1158 if (copiedDMA != length) {
1159 ret = kIOReturnUnderrun;
1160 break;
1161 }
1162 copied = data->writeBytes(mdOffset, buffer.data(), mdLength);
1163 if (copied != mdLength) {
1164 ret = kIOReturnUnderrun;
1165 break;
1166 }
1167 }
1168 ret = kIOReturnSuccess;
1169 break;
1170 default:
1171 ret = kIOReturnBadArgument;
1172 break;
1173 }
1174
1175 return ret;
1176 }
1177
1178
1179 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1180
1181 static kern_return_t
OSActionCreateWithTypeNameInternal(OSObject * target,uint64_t targetmsgid,uint64_t msgid,size_t referenceSize,OSString * typeName,bool fromKernel,OSAction ** action)1182 OSActionCreateWithTypeNameInternal(OSObject * target, uint64_t targetmsgid, uint64_t msgid, size_t referenceSize, OSString * typeName, bool fromKernel, OSAction ** action)
1183 {
1184 OSAction * inst = NULL;
1185 void * reference = NULL; // must release
1186 const OSSymbol *sym = NULL; // must release
1187 OSObject *obj = NULL; // must release
1188 const OSMetaClass *actionMetaClass = NULL; // do not release
1189 kern_return_t ret;
1190
1191 if (fromKernel && typeName) {
1192 /* The action is being constructed in the kernel with a type name */
1193 sym = OSSymbol::withString(typeName);
1194 actionMetaClass = OSMetaClass::getMetaClassWithName(sym);
1195 if (actionMetaClass && actionMetaClass->getSuperClass() == OSTypeID(OSAction)) {
1196 obj = actionMetaClass->alloc();
1197 if (!obj) {
1198 ret = kIOReturnNoMemory;
1199 goto finish;
1200 }
1201 inst = OSDynamicCast(OSAction, obj);
1202 obj = NULL; // prevent release
1203 assert(inst); // obj is a subclass of OSAction so the dynamic cast should always work
1204 } else {
1205 DKLOG("Attempted to create action object with type \"%s\" which does not inherit from OSAction\n", typeName->getCStringNoCopy());
1206 ret = kIOReturnBadArgument;
1207 goto finish;
1208 }
1209 } else {
1210 inst = OSTypeAlloc(OSAction);
1211 if (!inst) {
1212 ret = kIOReturnNoMemory;
1213 goto finish;
1214 }
1215 }
1216
1217 if (referenceSize != 0) {
1218 reference = IONewZeroData(uint8_t, referenceSize);
1219 if (reference == NULL) {
1220 ret = kIOReturnNoMemory;
1221 goto finish;
1222 }
1223 }
1224
1225 inst->ivars = IONewZero(OSAction_IVars, 1);
1226 if (!inst->ivars) {
1227 ret = kIOReturnNoMemory;
1228 goto finish;
1229 }
1230 if (target) {
1231 target->retain();
1232 if (!fromKernel && !OSDynamicCast(IOService, target)) {
1233 IOUserServer * us;
1234 us = (typeof(us))thread_iokit_tls_get(0);
1235 inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
1236 assert(inst->ivars->userServer);
1237 inst->ivars->userServer->retain();
1238 }
1239 }
1240 inst->ivars->target = target;
1241 inst->ivars->targetmsgid = targetmsgid;
1242 inst->ivars->msgid = msgid;
1243
1244 inst->ivars->reference = reference;
1245 inst->ivars->referenceSize = referenceSize;
1246 reference = NULL; // prevent release
1247
1248 if (typeName) {
1249 typeName->retain();
1250 }
1251 inst->ivars->typeName = typeName;
1252
1253 *action = inst;
1254 inst = NULL; // prevent release
1255 ret = kIOReturnSuccess;
1256
1257 finish:
1258 OSSafeReleaseNULL(obj);
1259 OSSafeReleaseNULL(sym);
1260 OSSafeReleaseNULL(inst);
1261 if (reference) {
1262 IODeleteData(reference, uint8_t, referenceSize);
1263 }
1264
1265 return ret;
1266 }
1267
1268 kern_return_t
Create(OSAction_Create_Args)1269 OSAction::Create(OSAction_Create_Args)
1270 {
1271 return OSAction::CreateWithTypeName(target, targetmsgid, msgid, referenceSize, NULL, action);
1272 }
1273
1274 kern_return_t
CreateWithTypeName(OSAction_CreateWithTypeName_Args)1275 OSAction::CreateWithTypeName(OSAction_CreateWithTypeName_Args)
1276 {
1277 return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, true, action);
1278 }
1279
1280 kern_return_t
Create_Impl(OSObject * target,uint64_t targetmsgid,uint64_t msgid,size_t referenceSize,OSAction ** action)1281 OSAction::Create_Impl(
1282 OSObject * target,
1283 uint64_t targetmsgid,
1284 uint64_t msgid,
1285 size_t referenceSize,
1286 OSAction ** action)
1287 {
1288 return OSAction::CreateWithTypeName_Impl(target, targetmsgid, msgid, referenceSize, NULL, action);
1289 }
1290
1291 kern_return_t
CreateWithTypeName_Impl(OSObject * target,uint64_t targetmsgid,uint64_t msgid,size_t referenceSize,OSString * typeName,OSAction ** action)1292 OSAction::CreateWithTypeName_Impl(
1293 OSObject * target,
1294 uint64_t targetmsgid,
1295 uint64_t msgid,
1296 size_t referenceSize,
1297 OSString * typeName,
1298 OSAction ** action)
1299 {
1300 return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, false, action);
1301 }
1302
1303 void
free()1304 OSAction::free()
1305 {
1306 if (ivars) {
1307 if (ivars->abortedHandler) {
1308 Block_release(ivars->abortedHandler);
1309 ivars->abortedHandler = NULL;
1310 }
1311 OSSafeReleaseNULL(ivars->target);
1312 OSSafeReleaseNULL(ivars->typeName);
1313 OSSafeReleaseNULL(ivars->userServer);
1314 if (ivars->reference) {
1315 assert(ivars->referenceSize > 0);
1316 IODeleteData(ivars->reference, uint8_t, ivars->referenceSize);
1317 }
1318 IOSafeDeleteNULL(ivars, OSAction_IVars, 1);
1319 }
1320 return super::free();
1321 }
1322
1323 void *
GetReference()1324 OSAction::GetReference()
1325 {
1326 assert(ivars && ivars->referenceSize && ivars->reference);
1327 return ivars->reference;
1328 }
1329
1330 kern_return_t
SetAbortedHandler(OSActionAbortedHandler handler)1331 OSAction::SetAbortedHandler(OSActionAbortedHandler handler)
1332 {
1333 ivars->abortedHandler = Block_copy(handler);
1334 return kIOReturnSuccess;
1335 }
1336
1337 void
Aborted_Impl(void)1338 OSAction::Aborted_Impl(void)
1339 {
1340 if (ivars->abortedHandler) {
1341 ivars->abortedHandler();
1342 }
1343 }
1344
1345 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1346
1347 struct IODispatchSource_IVars {
1348 queue_chain_t link;
1349 IODispatchSource * source;
1350 IOUserServer * server;
1351 IODispatchQueue_IVars * queue;
1352 bool enabled;
1353 };
1354
1355 bool
init()1356 IODispatchSource::init()
1357 {
1358 if (!super::init()) {
1359 return false;
1360 }
1361
1362 ivars = IOMallocType(IODispatchSource_IVars);
1363
1364 ivars->source = this;
1365
1366 return true;
1367 }
1368
1369 void
free()1370 IODispatchSource::free()
1371 {
1372 IOFreeType(ivars, IODispatchSource_IVars);
1373 super::free();
1374 }
1375
1376 kern_return_t
SetEnable_Impl(bool enable)1377 IODispatchSource::SetEnable_Impl(
1378 bool enable)
1379 {
1380 return SetEnableWithCompletion(enable, NULL);
1381 }
1382
1383 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1384
1385 struct IOInterruptDispatchSource_IVars {
1386 IOService * provider;
1387 uint32_t intIndex;
1388 uint32_t flags;
1389 int interruptType;
1390 IOSimpleLock * lock;
1391 thread_t waiter;
1392 uint64_t count;
1393 uint64_t time;
1394 OSAction * action;
1395 bool enable;
1396 };
1397
1398 static void
IOInterruptDispatchSourceInterrupt(OSObject * target,void * refCon,IOService * nub,int source)1399 IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
1400 IOService * nub, int source )
1401 {
1402 IOInterruptDispatchSource_IVars * ivars = (typeof(ivars))refCon;
1403 IOInterruptState is;
1404
1405 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1406 ivars->count++;
1407 ivars->time = (kIOInterruptSourceContinuousTime & ivars->flags)
1408 ? mach_continuous_time() : mach_absolute_time();
1409 if (ivars->waiter) {
1410 thread_wakeup_thread((event_t) ivars, ivars->waiter);
1411 ivars->waiter = NULL;
1412 }
1413 if (kIOInterruptTypeLevel & ivars->interruptType) {
1414 ivars->provider->disableInterrupt(ivars->intIndex);
1415 }
1416 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1417 }
1418
1419 kern_return_t
Create_Impl(IOService * provider,uint32_t indexAndFlags,IODispatchQueue * queue,IOInterruptDispatchSource ** source)1420 IOInterruptDispatchSource::Create_Impl(
1421 IOService * provider,
1422 uint32_t indexAndFlags,
1423 IODispatchQueue * queue,
1424 IOInterruptDispatchSource ** source)
1425 {
1426 IOReturn ret;
1427 IOInterruptDispatchSource * inst;
1428 uint32_t index;
1429 uint32_t flags;
1430
1431 index = indexAndFlags & kIOInterruptSourceIndexMask;
1432 flags = indexAndFlags & ~kIOInterruptSourceIndexMask;
1433
1434 inst = OSTypeAlloc(IOInterruptDispatchSource);
1435 if (!inst->init()) {
1436 inst->free();
1437 return kIOReturnNoMemory;
1438 }
1439
1440 inst->ivars->lock = IOSimpleLockAlloc();
1441
1442 ret = provider->getInterruptType(index, &inst->ivars->interruptType);
1443 if (kIOReturnSuccess != ret) {
1444 OSSafeReleaseNULL(inst);
1445 return ret;
1446 }
1447 ret = provider->registerInterrupt(index, inst, IOInterruptDispatchSourceInterrupt, inst->ivars);
1448 if (kIOReturnSuccess == ret) {
1449 inst->ivars->intIndex = index;
1450 inst->ivars->flags = flags;
1451 inst->ivars->provider = provider;
1452 inst->ivars->provider->retain();
1453 *source = inst;
1454 }
1455 return ret;
1456 }
1457
1458 kern_return_t
GetInterruptType_Impl(IOService * provider,uint32_t index,uint64_t * interruptType)1459 IOInterruptDispatchSource::GetInterruptType_Impl(
1460 IOService * provider,
1461 uint32_t index,
1462 uint64_t * interruptType)
1463 {
1464 IOReturn ret;
1465 int type;
1466
1467 *interruptType = 0;
1468 ret = provider->getInterruptType(index, &type);
1469 if (kIOReturnSuccess == ret) {
1470 *interruptType = type;
1471 }
1472
1473 return ret;
1474 }
1475
1476 bool
init()1477 IOInterruptDispatchSource::init()
1478 {
1479 if (!super::init()) {
1480 return false;
1481 }
1482 ivars = IOMallocType(IOInterruptDispatchSource_IVars);
1483
1484 return true;
1485 }
1486
1487 void
free()1488 IOInterruptDispatchSource::free()
1489 {
1490 IOReturn ret;
1491
1492 if (ivars && ivars->provider) {
1493 ret = ivars->provider->unregisterInterrupt(ivars->intIndex);
1494 assert(kIOReturnSuccess == ret);
1495 ivars->provider->release();
1496 }
1497
1498 if (ivars && ivars->lock) {
1499 IOSimpleLockFree(ivars->lock);
1500 }
1501
1502 IOFreeType(ivars, IOInterruptDispatchSource_IVars);
1503
1504 super::free();
1505 }
1506
1507 kern_return_t
SetHandler_Impl(OSAction * action)1508 IOInterruptDispatchSource::SetHandler_Impl(
1509 OSAction * action)
1510 {
1511 IOReturn ret;
1512 OSAction * oldAction;
1513
1514 oldAction = (typeof(oldAction))ivars->action;
1515 if (oldAction && OSCompareAndSwapPtr(oldAction, NULL, &ivars->action)) {
1516 oldAction->release();
1517 }
1518 action->retain();
1519 ivars->action = action;
1520
1521 ret = kIOReturnSuccess;
1522
1523 return ret;
1524 }
1525
1526 kern_return_t
SetEnableWithCompletion_Impl(bool enable,IODispatchSourceCancelHandler handler)1527 IOInterruptDispatchSource::SetEnableWithCompletion_Impl(
1528 bool enable,
1529 IODispatchSourceCancelHandler handler)
1530 {
1531 IOReturn ret;
1532 IOInterruptState is;
1533
1534 if (enable == ivars->enable) {
1535 return kIOReturnSuccess;
1536 }
1537
1538 if (enable) {
1539 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1540 ivars->enable = enable;
1541 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1542 ret = ivars->provider->enableInterrupt(ivars->intIndex);
1543 } else {
1544 ret = ivars->provider->disableInterrupt(ivars->intIndex);
1545 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1546 ivars->enable = enable;
1547 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1548 }
1549
1550 return ret;
1551 }
1552
1553 kern_return_t
Cancel_Impl(IODispatchSourceCancelHandler handler)1554 IOInterruptDispatchSource::Cancel_Impl(
1555 IODispatchSourceCancelHandler handler)
1556 {
1557 return kIOReturnUnsupported;
1558 }
1559
1560 kern_return_t
CheckForWork_Impl(const IORPC rpc,bool synchronous)1561 IOInterruptDispatchSource::CheckForWork_Impl(
1562 const IORPC rpc,
1563 bool synchronous)
1564 {
1565 IOReturn ret = kIOReturnNotReady;
1566 IOInterruptState is;
1567 bool willWait;
1568 wait_result_t waitResult;
1569 uint64_t icount;
1570 uint64_t itime;
1571 thread_t self;
1572
1573 self = current_thread();
1574 icount = 0;
1575 do {
1576 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1577 if ((icount = ivars->count)) {
1578 itime = ivars->time;
1579 ivars->count = 0;
1580 waitResult = THREAD_AWAKENED;
1581 } else if (synchronous) {
1582 assert(NULL == ivars->waiter);
1583 ivars->waiter = self;
1584 waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
1585 }
1586 willWait = (synchronous && (waitResult == THREAD_WAITING));
1587 if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
1588 ivars->provider->enableInterrupt(ivars->intIndex);
1589 }
1590 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1591 if (willWait) {
1592 waitResult = thread_block(THREAD_CONTINUE_NULL);
1593 if (THREAD_INTERRUPTED == waitResult) {
1594 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1595 ivars->waiter = NULL;
1596 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1597 break;
1598 }
1599 }
1600 } while (synchronous && !icount);
1601
1602 if (icount && ivars->action) {
1603 ret = InterruptOccurred(rpc, ivars->action, icount, itime);
1604 }
1605
1606 return ret;
1607 }
1608
1609 void
InterruptOccurred_Impl(OSAction * action,uint64_t count,uint64_t time)1610 IOInterruptDispatchSource::InterruptOccurred_Impl(
1611 OSAction * action,
1612 uint64_t count,
1613 uint64_t time)
1614 {
1615 }
1616
1617 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1618
1619 enum {
1620 kIOServiceNotificationTypeCount = kIOServiceNotificationTypeLast + 1,
1621 };
1622
1623 struct IOServiceNotificationDispatchSource_IVars {
1624 OSObject * serverName;
1625 OSAction * action;
1626 IOLock * lock;
1627 IONotifier * notifier;
1628 OSDictionary * interestNotifiers;
1629 OSArray * pending[kIOServiceNotificationTypeCount];
1630 bool enable;
1631 };
1632
1633 kern_return_t
Create_Impl(OSDictionary * matching,uint64_t options,IODispatchQueue * queue,IOServiceNotificationDispatchSource ** notification)1634 IOServiceNotificationDispatchSource::Create_Impl(
1635 OSDictionary * matching,
1636 uint64_t options,
1637 IODispatchQueue * queue,
1638 IOServiceNotificationDispatchSource ** notification)
1639 {
1640 IOUserServer * us;
1641 IOReturn ret;
1642 IOServiceNotificationDispatchSource * inst;
1643
1644 inst = OSTypeAlloc(IOServiceNotificationDispatchSource);
1645 if (!inst->init()) {
1646 OSSafeReleaseNULL(inst);
1647 return kIOReturnNoMemory;
1648 }
1649
1650 us = (typeof(us))thread_iokit_tls_get(0);
1651 assert(OSDynamicCast(IOUserServer, us));
1652 if (!us) {
1653 OSSafeReleaseNULL(inst);
1654 return kIOReturnError;
1655 }
1656 inst->ivars->serverName = us->copyProperty(gIOUserServerNameKey);
1657 if (!inst->ivars->serverName) {
1658 OSSafeReleaseNULL(inst);
1659 return kIOReturnNoMemory;
1660 }
1661
1662 inst->ivars->lock = IOLockAlloc();
1663 if (!inst->ivars->lock) {
1664 OSSafeReleaseNULL(inst);
1665 return kIOReturnNoMemory;
1666 }
1667 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1668 inst->ivars->pending[idx] = OSArray::withCapacity(4);
1669 if (!inst->ivars->pending[idx]) {
1670 OSSafeReleaseNULL(inst);
1671 return kIOReturnNoMemory;
1672 }
1673 }
1674 inst->ivars->interestNotifiers = OSDictionary::withCapacity(4);
1675 if (!inst->ivars->interestNotifiers) {
1676 OSSafeReleaseNULL(inst);
1677 return kIOReturnNoMemory;
1678 }
1679
1680 inst->ivars->notifier = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0 /*priority*/,
1681 ^bool (IOService * newService, IONotifier * notifier) {
1682 bool notifyReady = false;
1683 IONotifier * interest;
1684 OSObject * serverName;
1685 bool okToUse;
1686
1687 serverName = newService->copyProperty(gIOUserServerNameKey);
1688 okToUse = (serverName && inst->ivars->serverName->isEqualTo(serverName));
1689 OSSafeReleaseNULL(serverName);
1690 if (!okToUse) {
1691 return false;
1692 }
1693
1694 IOLockLock(inst->ivars->lock);
1695 notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeMatched]->getCount());
1696 inst->ivars->pending[kIOServiceNotificationTypeMatched]->setObject(newService);
1697 IOLockUnlock(inst->ivars->lock);
1698
1699 interest = newService->registerInterest(gIOGeneralInterest,
1700 ^IOReturn (uint32_t messageType, IOService * provider,
1701 void * messageArgument, size_t argSize) {
1702 IONotifier * interest;
1703 bool notifyReady = false;
1704
1705 switch (messageType) {
1706 case kIOMessageServiceIsTerminated:
1707 IOLockLock(inst->ivars->lock);
1708 notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeTerminated]->getCount());
1709 inst->ivars->pending[kIOServiceNotificationTypeTerminated]->setObject(provider);
1710 interest = (typeof(interest))inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService);
1711 assert(interest);
1712 interest->remove();
1713 inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
1714 IOLockUnlock(inst->ivars->lock);
1715 break;
1716 default:
1717 break;
1718 }
1719 if (notifyReady && inst->ivars->action) {
1720 inst->ServiceNotificationReady(inst->ivars->action);
1721 }
1722 return kIOReturnSuccess;
1723 });
1724 if (interest) {
1725 IOLockLock(inst->ivars->lock);
1726 inst->ivars->interestNotifiers->setObject((const OSSymbol *) newService, interest);
1727 IOLockUnlock(inst->ivars->lock);
1728 }
1729 if (notifyReady) {
1730 if (inst->ivars->action) {
1731 inst->ServiceNotificationReady(inst->ivars->action);
1732 }
1733 }
1734 return false;
1735 });
1736
1737 if (!inst->ivars->notifier) {
1738 OSSafeReleaseNULL(inst);
1739 ret = kIOReturnError;
1740 }
1741
1742 *notification = inst;
1743 ret = kIOReturnSuccess;
1744
1745 return ret;
1746 }
1747
1748 kern_return_t
CopyNextNotification_Impl(uint64_t * type,IOService ** service,uint64_t * options)1749 IOServiceNotificationDispatchSource::CopyNextNotification_Impl(
1750 uint64_t * type,
1751 IOService ** service,
1752 uint64_t * options)
1753 {
1754 IOService * next;
1755 uint32_t idx;
1756
1757 IOLockLock(ivars->lock);
1758 for (idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1759 next = (IOService *) ivars->pending[idx]->getObject(0);
1760 if (next) {
1761 next->retain();
1762 ivars->pending[idx]->removeObject(0);
1763 break;
1764 }
1765 }
1766 IOLockUnlock(ivars->lock);
1767
1768 if (idx == kIOServiceNotificationTypeCount) {
1769 idx = kIOServiceNotificationTypeNone;
1770 }
1771 *type = idx;
1772 *service = next;
1773 *options = 0;
1774
1775 return kIOReturnSuccess;
1776 }
1777
1778 bool
init()1779 IOServiceNotificationDispatchSource::init()
1780 {
1781 if (!super::init()) {
1782 return false;
1783 }
1784 ivars = IOMallocType(IOServiceNotificationDispatchSource_IVars);
1785
1786 return true;
1787 }
1788
1789 void
free()1790 IOServiceNotificationDispatchSource::free()
1791 {
1792 if (ivars) {
1793 OSSafeReleaseNULL(ivars->serverName);
1794 if (ivars->interestNotifiers) {
1795 ivars->interestNotifiers->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
1796 IONotifier * interest = (typeof(interest))object;
1797 interest->remove();
1798 return false;
1799 });
1800 OSSafeReleaseNULL(ivars->interestNotifiers);
1801 }
1802 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1803 OSSafeReleaseNULL(ivars->pending[idx]);
1804 }
1805 if (ivars->lock) {
1806 IOLockFree(ivars->lock);
1807 ivars->lock = NULL;
1808 }
1809 if (ivars->notifier) {
1810 ivars->notifier->remove();
1811 ivars->notifier = NULL;
1812 }
1813 IOFreeType(ivars, IOServiceNotificationDispatchSource_IVars);
1814 }
1815
1816 super::free();
1817 }
1818
1819 kern_return_t
SetHandler_Impl(OSAction * action)1820 IOServiceNotificationDispatchSource::SetHandler_Impl(
1821 OSAction * action)
1822 {
1823 IOReturn ret;
1824 bool notifyReady;
1825
1826 notifyReady = false;
1827
1828 IOLockLock(ivars->lock);
1829 OSSafeReleaseNULL(ivars->action);
1830 action->retain();
1831 ivars->action = action;
1832 if (action) {
1833 for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1834 notifyReady = (ivars->pending[idx]->getCount());
1835 if (notifyReady) {
1836 break;
1837 }
1838 }
1839 }
1840 IOLockUnlock(ivars->lock);
1841
1842 if (notifyReady) {
1843 ServiceNotificationReady(action);
1844 }
1845 ret = kIOReturnSuccess;
1846
1847 return ret;
1848 }
1849
1850 kern_return_t
SetEnableWithCompletion_Impl(bool enable,IODispatchSourceCancelHandler handler)1851 IOServiceNotificationDispatchSource::SetEnableWithCompletion_Impl(
1852 bool enable,
1853 IODispatchSourceCancelHandler handler)
1854 {
1855 if (enable == ivars->enable) {
1856 return kIOReturnSuccess;
1857 }
1858
1859 IOLockLock(ivars->lock);
1860 ivars->enable = enable;
1861 IOLockUnlock(ivars->lock);
1862
1863 return kIOReturnSuccess;
1864 }
1865
1866 kern_return_t
Cancel_Impl(IODispatchSourceCancelHandler handler)1867 IOServiceNotificationDispatchSource::Cancel_Impl(
1868 IODispatchSourceCancelHandler handler)
1869 {
1870 return kIOReturnUnsupported;
1871 }
1872
1873 kern_return_t
CheckForWork_Impl(const IORPC rpc,bool synchronous)1874 IOServiceNotificationDispatchSource::CheckForWork_Impl(
1875 const IORPC rpc,
1876 bool synchronous)
1877 {
1878 return kIOReturnNotReady;
1879 }
1880
1881 kern_return_t
DeliverNotifications(IOServiceNotificationBlock block)1882 IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block)
1883 {
1884 return kIOReturnUnsupported;
1885 }
1886
1887
1888 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1889
1890 OSDictionary *
CreatePropertyMatchingDictionary(const char * key,OSObjectPtr value,OSDictionary * matching)1891 IOService::CreatePropertyMatchingDictionary(const char * key, OSObjectPtr value, OSDictionary * matching)
1892 {
1893 OSDictionary * result;
1894 const OSSymbol * keySym;
1895
1896 keySym = OSSymbol::withCString(key);
1897 result = propertyMatching(keySym, (const OSObject *) value, matching);
1898 OSSafeReleaseNULL(keySym);
1899
1900 return result;
1901 }
1902
1903 OSDictionary *
CreatePropertyMatchingDictionary(const char * key,const char * stringValue,OSDictionary * matching)1904 IOService::CreatePropertyMatchingDictionary(const char * key, const char * stringValue, OSDictionary * matching)
1905 {
1906 OSDictionary * result;
1907 OSString * value;
1908
1909 value = OSString::withCString(stringValue);
1910 result = CreatePropertyMatchingDictionary(key, value, matching);
1911 OSSafeReleaseNULL(value);
1912
1913 return result;
1914 }
1915
1916 OSDictionary *
CreateKernelClassMatchingDictionary(OSString * className,OSDictionary * matching)1917 IOService::CreateKernelClassMatchingDictionary(OSString * className, OSDictionary * matching)
1918 {
1919 if (!className) {
1920 return NULL;
1921 }
1922 if (!matching) {
1923 matching = OSDictionary::withCapacity(2);
1924 if (!matching) {
1925 return NULL;
1926 }
1927 }
1928 matching->setObject(kIOProviderClassKey, className);
1929
1930 return matching;
1931 }
1932
1933 OSDictionary *
CreateKernelClassMatchingDictionary(const char * className,OSDictionary * matching)1934 IOService::CreateKernelClassMatchingDictionary(const char * className, OSDictionary * matching)
1935 {
1936 OSDictionary * result;
1937 OSString * string;
1938
1939 string = OSString::withCString(className);
1940 result = CreateKernelClassMatchingDictionary(string, matching);
1941 OSSafeReleaseNULL(string);
1942
1943 return result;
1944 }
1945
1946 OSDictionary *
CreateUserClassMatchingDictionary(OSString * className,OSDictionary * matching)1947 IOService::CreateUserClassMatchingDictionary(OSString * className, OSDictionary * matching)
1948 {
1949 return CreatePropertyMatchingDictionary(kIOUserClassKey, className, matching);
1950 }
1951
1952 OSDictionary *
CreateUserClassMatchingDictionary(const char * className,OSDictionary * matching)1953 IOService::CreateUserClassMatchingDictionary(const char * className, OSDictionary * matching)
1954 {
1955 return CreatePropertyMatchingDictionary(kIOUserClassKey, className, matching);
1956 }
1957
1958 OSDictionary *
CreateNameMatchingDictionary(OSString * serviceName,OSDictionary * matching)1959 IOService::CreateNameMatchingDictionary(OSString * serviceName, OSDictionary * matching)
1960 {
1961 if (!serviceName) {
1962 return NULL;
1963 }
1964 if (!matching) {
1965 matching = OSDictionary::withCapacity(2);
1966 if (!matching) {
1967 return NULL;
1968 }
1969 }
1970 matching->setObject(kIONameMatchKey, serviceName);
1971
1972 return matching;
1973 }
1974
1975 OSDictionary *
CreateNameMatchingDictionary(const char * serviceName,OSDictionary * matching)1976 IOService::CreateNameMatchingDictionary(const char * serviceName, OSDictionary * matching)
1977 {
1978 OSDictionary * result;
1979 OSString * string;
1980
1981 string = OSString::withCString(serviceName);
1982 result = CreateNameMatchingDictionary(string, matching);
1983 OSSafeReleaseNULL(string);
1984
1985 return result;
1986 }
1987
1988
1989
1990 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1991
1992 kern_return_t
waitInterruptTrap(void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)1993 IOUserServer::waitInterruptTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
1994 {
1995 IOReturn ret = kIOReturnBadArgument;
1996 IOInterruptState is;
1997 IOInterruptDispatchSource * interrupt;
1998 IOInterruptDispatchSource_IVars * ivars;
1999 IOInterruptDispatchSourcePayload payload;
2000
2001 bool willWait;
2002 wait_result_t waitResult;
2003 thread_t self;
2004
2005 OSObject * object;
2006
2007 object = iokit_lookup_object_with_port_name((mach_port_name_t)(uintptr_t)p1, IKOT_UEXT_OBJECT, current_task());
2008
2009 if (!object) {
2010 return kIOReturnBadArgument;
2011 }
2012 if (!(interrupt = OSDynamicCast(IOInterruptDispatchSource, object))) {
2013 ret = kIOReturnBadArgument;
2014 } else {
2015 self = current_thread();
2016 ivars = interrupt->ivars;
2017 payload.count = 0;
2018 do {
2019 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
2020 if ((payload.count = ivars->count)) {
2021 payload.time = ivars->time;
2022 ivars->count = 0;
2023 waitResult = THREAD_AWAKENED;
2024 } else {
2025 assert(NULL == ivars->waiter);
2026 ivars->waiter = self;
2027 waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
2028 }
2029 willWait = (waitResult == THREAD_WAITING);
2030 if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
2031 ivars->provider->enableInterrupt(ivars->intIndex);
2032 }
2033 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2034 if (willWait) {
2035 waitResult = thread_block(THREAD_CONTINUE_NULL);
2036 if (THREAD_INTERRUPTED == waitResult) {
2037 is = IOSimpleLockLockDisableInterrupt(ivars->lock);
2038 ivars->waiter = NULL;
2039 IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2040 break;
2041 }
2042 }
2043 } while (!payload.count);
2044 ret = (payload.count ? kIOReturnSuccess : kIOReturnAborted);
2045 }
2046
2047 if (kIOReturnSuccess == ret) {
2048 int copyerr = copyout(&payload, (user_addr_t) p2, sizeof(payload));
2049 if (copyerr) {
2050 ret = kIOReturnVMError;
2051 }
2052 }
2053
2054 object->release();
2055
2056 return ret;
2057 }
2058
2059 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2060
2061 kern_return_t
Create_Impl(const char * name,uint64_t tag,uint64_t options,OSString * bundleID,IOUserServer ** server)2062 IOUserServer::Create_Impl(
2063 const char * name,
2064 uint64_t tag,
2065 uint64_t options,
2066 OSString * bundleID,
2067 IOUserServer ** server)
2068 {
2069 IOReturn ret;
2070 IOUserServer * us;
2071 const OSSymbol * sym;
2072 OSNumber * serverTag;
2073 io_name_t rname;
2074 OSKext * kext;
2075
2076 us = (typeof(us))thread_iokit_tls_get(0);
2077 assert(OSDynamicCast(IOUserServer, us));
2078 if (kIODKLogSetup & gIODKDebug) {
2079 DKLOG(DKS "::Create(" DKS ") %p\n", DKN(us), name, tag, us);
2080 }
2081 if (!us) {
2082 return kIOReturnError;
2083 }
2084
2085 if (bundleID) {
2086 kext = OSKext::lookupKextWithIdentifier(bundleID->getCStringNoCopy());
2087 if (kext) {
2088 us->setTaskLoadTag(kext);
2089 us->setDriverKitUUID(kext);
2090 OSKext::OSKextLogDriverKitInfoLoad(kext);
2091 OSSafeReleaseNULL(kext);
2092 } else {
2093 DKLOG(DKS "::Create(" DKS "): could not find OSKext for %s\n", DKN(us), name, tag, bundleID->getCStringNoCopy());
2094 }
2095
2096 us->fAllocationName = kern_allocation_name_allocate(bundleID->getCStringNoCopy(), 0);
2097 assert(us->fAllocationName);
2098 }
2099
2100 sym = OSSymbol::withCString(name);
2101 serverTag = OSNumber::withNumber(tag, 64);
2102
2103 us->setProperty(gIOUserServerNameKey, (OSObject *) sym);
2104 us->setProperty(gIOUserServerTagKey, serverTag);
2105
2106 serverTag->release();
2107 OSSafeReleaseNULL(sym);
2108
2109 snprintf(rname, sizeof(rname), "IOUserServer(%s-0x%qx)", name, tag);
2110 us->setName(rname);
2111
2112 us->retain();
2113 *server = us;
2114 ret = kIOReturnSuccess;
2115
2116 return ret;
2117 }
2118
2119 kern_return_t
RegisterService_Impl()2120 IOUserServer::RegisterService_Impl()
2121 {
2122 kern_return_t ret = IOService::RegisterService_Impl();
2123
2124 return ret;
2125 }
2126
2127 kern_return_t
Exit_Impl(const char * reason)2128 IOUserServer::Exit_Impl(
2129 const char * reason)
2130 {
2131 return kIOReturnUnsupported;
2132 }
2133
2134 kern_return_t
LoadModule_Impl(const char * path)2135 IOUserServer::LoadModule_Impl(
2136 const char * path)
2137 {
2138 return kIOReturnUnsupported;
2139 }
2140
2141
2142 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2143
2144 kern_return_t
Create_Impl(const char * name,uint64_t options,uint64_t priority,IODispatchQueue ** queue)2145 IODispatchQueue::Create_Impl(
2146 const char * name,
2147 uint64_t options,
2148 uint64_t priority,
2149 IODispatchQueue ** queue)
2150 {
2151 IODispatchQueue * result;
2152 IOUserServer * us;
2153
2154 result = OSTypeAlloc(IODispatchQueue);
2155 if (!result) {
2156 return kIOReturnNoMemory;
2157 }
2158 if (!result->init()) {
2159 OSSafeReleaseNULL(result);
2160 return kIOReturnNoMemory;
2161 }
2162
2163 *queue = result;
2164
2165 if (!strcmp("Root", name)) {
2166 us = (typeof(us))thread_iokit_tls_get(0);
2167 assert(OSDynamicCast(IOUserServer, us));
2168 us->setRootQueue(result);
2169 }
2170
2171 if (kIODKLogSetup & gIODKDebug) {
2172 DKLOG("IODispatchQueue::Create %s %p\n", name, result);
2173 }
2174
2175 return kIOReturnSuccess;
2176 }
2177
2178 kern_return_t
SetPort_Impl(mach_port_t port)2179 IODispatchQueue::SetPort_Impl(
2180 mach_port_t port)
2181 {
2182 if (MACH_PORT_NULL != ivars->serverPort) {
2183 return kIOReturnNotReady;
2184 }
2185
2186 ivars->serverPort = port;
2187 return kIOReturnSuccess;
2188 }
2189
2190 bool
init()2191 IODispatchQueue::init()
2192 {
2193 ivars = IOMallocType(IODispatchQueue_IVars);
2194 ivars->queue = this;
2195
2196 return true;
2197 }
2198
2199 void
free()2200 IODispatchQueue::free()
2201 {
2202 if (ivars && ivars->serverPort) {
2203 ipc_port_release_send(ivars->serverPort);
2204 ivars->serverPort = MACH_PORT_NULL;
2205 }
2206 IOFreeType(ivars, IODispatchQueue_IVars);
2207 super::free();
2208 }
2209
2210 bool
OnQueue()2211 IODispatchQueue::OnQueue()
2212 {
2213 return false;
2214 }
2215
2216 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2217
2218
2219 kern_return_t
Dispatch(IORPC rpc)2220 OSMetaClassBase::Dispatch(IORPC rpc)
2221 {
2222 return kIOReturnUnsupported;
2223 }
2224
2225 kern_return_t
Invoke(IORPC rpc)2226 OSMetaClassBase::Invoke(IORPC rpc)
2227 {
2228 IOReturn ret = kIOReturnUnsupported;
2229 OSMetaClassBase * object;
2230 OSAction * action;
2231 IOService * service;
2232 IOUserServer * us;
2233 IORPCMessage * message;
2234
2235 assert(rpc.sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2236 message = IORPCMessageFromMach(rpc.message, false);
2237 if (!message) {
2238 return kIOReturnIPCError;
2239 }
2240 message->flags |= kIORPCMessageKernel;
2241
2242 us = NULL;
2243 if (!(kIORPCMessageLocalHost & message->flags)) {
2244 us = OSDynamicCast(IOUserServer, this);
2245 if (!us) {
2246 IOEventLink * eventLink = NULL;
2247 IOWorkGroup * workgroup = NULL;
2248
2249 if ((action = OSDynamicCast(OSAction, this))) {
2250 object = IOUserServer::target(action, message);
2251 } else {
2252 object = this;
2253 }
2254 if ((service = OSDynamicCast(IOService, object))
2255 && service->reserved->uvars) {
2256 // xxx other classes
2257 us = service->reserved->uvars->userServer;
2258 } else if (action) {
2259 us = action->ivars->userServer;
2260 } else if ((eventLink = OSDynamicCast(IOEventLink, object))) {
2261 us = eventLink->ivars->userServer;
2262 } else if ((workgroup = OSDynamicCast(IOWorkGroup, object))) {
2263 us = workgroup->ivars->userServer;
2264 }
2265 }
2266 }
2267 if (us) {
2268 message->flags |= kIORPCMessageRemote;
2269 ret = us->rpc(rpc);
2270 if (kIOReturnSuccess != ret) {
2271 if (kIODKLogIPC & gIODKDebug) {
2272 DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret);
2273 }
2274 }
2275 } else {
2276 if (kIODKLogIPC & gIODKDebug) {
2277 DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message->msgid);
2278 }
2279 void * prior = thread_iokit_tls_get(0);
2280 thread_iokit_tls_set(0, NULL);
2281 ret = Dispatch(rpc);
2282 thread_iokit_tls_set(0, prior);
2283 }
2284
2285 return ret;
2286 }
2287
2288 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2289
2290 struct IOPStrings {
2291 uint32_t dataSize;
2292 uint32_t count;
2293 const char strings[0];
2294 };
2295
2296 kern_return_t
Dispatch(IORPC rpc)2297 OSUserMetaClass::Dispatch(IORPC rpc)
2298 {
2299 if (meta) {
2300 return const_cast<OSMetaClass *>(meta)->Dispatch(rpc);
2301 } else {
2302 return kIOReturnUnsupported;
2303 }
2304 }
2305
2306 void
free()2307 OSUserMetaClass::free()
2308 {
2309 if (queueNames) {
2310 IOFreeData(queueNames, sizeof(IOPStrings) + queueNames->dataSize * sizeof(char));
2311 queueNames = NULL;
2312 }
2313 if (description) {
2314 IOFreeData(description, description->descriptionSize);
2315 description = NULL;
2316 }
2317 IODeleteData(methods, uint64_t, 2 * methodCount);
2318 if (meta) {
2319 meta->releaseMetaClass();
2320 }
2321 if (name) {
2322 name->release();
2323 }
2324 OSObject::free();
2325 }
2326
2327 /*
2328 * Sets the loadTag of the associated OSKext
2329 * in the dext task.
2330 * NOTE: different instances of the same OSKext
2331 * (so same BounleID but different tasks)
2332 * will have the same loadTag.
2333 */
2334 void
setTaskLoadTag(OSKext * kext)2335 IOUserServer::setTaskLoadTag(OSKext *kext)
2336 {
2337 task_t owningTask;
2338 uint32_t loadTag, prev_taskloadTag;
2339
2340 owningTask = this->fOwningTask;
2341 if (!owningTask) {
2342 printf("%s: fOwningTask not found\n", __FUNCTION__);
2343 return;
2344 }
2345
2346 loadTag = kext->getLoadTag();
2347 prev_taskloadTag = set_task_loadTag(owningTask, loadTag);
2348 if (prev_taskloadTag) {
2349 printf("%s: found the task loadTag already set to %u (set to %u)\n",
2350 __FUNCTION__, prev_taskloadTag, loadTag);
2351 }
2352 }
2353
2354 /*
2355 * Sets the OSKext uuid as the uuid of the userspace
2356 * dext executable.
2357 */
2358 void
setDriverKitUUID(OSKext * kext)2359 IOUserServer::setDriverKitUUID(OSKext *kext)
2360 {
2361 task_t task;
2362 proc_t p;
2363 uuid_t p_uuid, k_uuid;
2364 OSData *k_data_uuid;
2365 OSData *new_uuid;
2366 uuid_string_t uuid_string = "";
2367
2368 task = this->fOwningTask;
2369 if (!task) {
2370 printf("%s: fOwningTask not found\n", __FUNCTION__);
2371 return;
2372 }
2373
2374 p = (proc_t)(get_bsdtask_info(task));
2375 if (!p) {
2376 printf("%s: proc not found\n", __FUNCTION__);
2377 return;
2378 }
2379 proc_getexecutableuuid(p, p_uuid, sizeof(p_uuid));
2380
2381 k_data_uuid = kext->copyUUID();
2382 if (k_data_uuid) {
2383 memcpy(&k_uuid, k_data_uuid->getBytesNoCopy(), sizeof(k_uuid));
2384 OSSafeReleaseNULL(k_data_uuid);
2385 if (uuid_compare(k_uuid, p_uuid) != 0) {
2386 printf("%s: uuid not matching\n", __FUNCTION__);
2387 }
2388 return;
2389 }
2390
2391 uuid_unparse(p_uuid, uuid_string);
2392 new_uuid = OSData::withBytes(p_uuid, sizeof(p_uuid));
2393 kext->setDriverKitUUID(new_uuid);
2394 }
2395
2396 void
setCheckInToken(IOUserServerCheckInToken * token)2397 IOUserServer::setCheckInToken(IOUserServerCheckInToken *token)
2398 {
2399 if (token != NULL && fCheckInToken == NULL) {
2400 token->retain();
2401 fCheckInToken = token;
2402 } else {
2403 printf("%s: failed to set check in token. token=%p, fCheckInToken=%p\n", __FUNCTION__, token, fCheckInToken);
2404 }
2405 }
2406
2407 bool
serviceMatchesCheckInToken(IOUserServerCheckInToken * token)2408 IOUserServer::serviceMatchesCheckInToken(IOUserServerCheckInToken *token)
2409 {
2410 if (token != NULL) {
2411 bool result = token == fCheckInToken;
2412 if (result) {
2413 fCheckInToken->complete();
2414 }
2415 return result;
2416 } else {
2417 printf("%s: null check in token\n", __FUNCTION__);
2418 return false;
2419 }
2420 }
2421
2422 // entitlements - dict of entitlements to check
2423 // prop - string - if present return true
2424 // - array of strings - if any present return true
2425 // - array of arrays of strings - in each leaf array all must be present
2426 // - if any top level array succeeds return true
2427 // consumes one reference of prop
2428 bool
checkEntitlements(OSDictionary * entitlements,OSObject * prop,IOService * provider,IOService * dext)2429 IOUserServer::checkEntitlements(
2430 OSDictionary * entitlements, OSObject * prop,
2431 IOService * provider, IOService * dext)
2432 {
2433 OSDictionary * matching;
2434
2435 if (!prop) {
2436 return true;
2437 }
2438 if (!entitlements) {
2439 OSSafeReleaseNULL(prop);
2440 return false;
2441 }
2442
2443 matching = NULL;
2444 if (dext) {
2445 matching = dext->dictionaryWithProperties();
2446 if (!matching) {
2447 OSSafeReleaseNULL(prop);
2448 return false;
2449 }
2450 }
2451
2452 bool allPresent __block;
2453 prop->iterateObjects(^bool (OSObject * object) {
2454 allPresent = false;
2455 object->iterateObjects(^bool (OSObject * object) {
2456 OSString * string;
2457 OSObject * value;
2458 string = OSDynamicCast(OSString, object);
2459 value = entitlements->getObject(string);
2460 if (matching && value) {
2461 matching->setObject(string, value);
2462 }
2463 allPresent = (NULL != value);
2464 // early terminate if not found
2465 return !allPresent;
2466 });
2467 // early terminate if found
2468 return allPresent;
2469 });
2470
2471 if (allPresent && matching && provider) {
2472 allPresent = provider->matchPropertyTable(matching);
2473 }
2474
2475 OSSafeReleaseNULL(matching);
2476 OSSafeReleaseNULL(prop);
2477
2478 return allPresent;
2479 }
2480
2481 bool
checkEntitlements(IOService * provider,IOService * dext)2482 IOUserServer::checkEntitlements(IOService * provider, IOService * dext)
2483 {
2484 OSObject * prop;
2485 bool ok;
2486
2487 if (!fOwningTask) {
2488 return false;
2489 }
2490
2491 prop = provider->copyProperty(gIOServiceDEXTEntitlementsKey);
2492 ok = checkEntitlements(fEntitlements, prop, provider, dext);
2493 if (!ok) {
2494 DKLOG(DKS ": provider entitlements check failed\n", DKN(dext));
2495 }
2496 if (ok) {
2497 prop = dext->copyProperty(gIOServiceDEXTEntitlementsKey);
2498 ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
2499 if (!ok) {
2500 DKLOG(DKS ": family entitlements check failed\n", DKN(dext));
2501 }
2502 }
2503
2504 return ok;
2505 }
2506
2507 IOReturn
exit(const char * reason)2508 IOUserServer::exit(const char * reason)
2509 {
2510 DKLOG("%s::exit(%s)\n", getName(), reason);
2511 Exit(reason);
2512 return kIOReturnSuccess;
2513 }
2514
2515 OSObjectUserVars *
varsForObject(OSObject * obj)2516 IOUserServer::varsForObject(OSObject * obj)
2517 {
2518 IOService * service;
2519
2520 if ((service = OSDynamicCast(IOService, obj))) {
2521 return service->reserved->uvars;
2522 }
2523
2524 return NULL;
2525 }
2526
2527 IOPStrings *
copyInStringArray(const char * string,uint32_t userSize)2528 IOUserServer::copyInStringArray(const char * string, uint32_t userSize)
2529 {
2530 IOPStrings * array;
2531 vm_size_t alloc;
2532 size_t len;
2533 const char * cstr;
2534 const char * end;
2535
2536 if (userSize <= 1) {
2537 return NULL;
2538 }
2539
2540 if (os_add_overflow(sizeof(IOPStrings), userSize, &alloc)) {
2541 assert(false);
2542 return NULL;
2543 }
2544 if (alloc > 16384) {
2545 assert(false);
2546 return NULL;
2547 }
2548 array = (typeof(array))IOMallocData(alloc);
2549 if (!array) {
2550 return NULL;
2551 }
2552 array->dataSize = userSize;
2553 bcopy(string, (void *) &array->strings[0], userSize);
2554
2555 array->count = 0;
2556 cstr = &array->strings[0];
2557 end = &array->strings[array->dataSize];
2558 while ((len = (unsigned char)cstr[0])) {
2559 cstr++;
2560 if ((cstr + len) >= end) {
2561 break;
2562 }
2563 cstr += len;
2564 array->count++;
2565 }
2566 if (len) {
2567 IOFreeData(array, alloc);
2568 array = NULL;
2569 }
2570
2571 return array;
2572 }
2573
2574 uint32_t
stringArrayIndex(IOPStrings * array,const char * look)2575 IOUserServer::stringArrayIndex(IOPStrings * array, const char * look)
2576 {
2577 uint32_t idx;
2578 size_t len, llen;
2579 const char * cstr;
2580 const char * end;
2581
2582 idx = 0;
2583 cstr = &array->strings[0];
2584 end = &array->strings[array->dataSize];
2585 llen = strlen(look);
2586 while ((len = (unsigned char)cstr[0])) {
2587 cstr++;
2588 if ((cstr + len) >= end) {
2589 break;
2590 }
2591 if ((len == llen) && !strncmp(cstr, look, len)) {
2592 return idx;
2593 }
2594 cstr += len;
2595 idx++;
2596 }
2597
2598 return -1U;
2599 }
2600 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
2601
2602 IODispatchQueue *
queueForObject(OSObject * obj,uint64_t msgid)2603 IOUserServer::queueForObject(OSObject * obj, uint64_t msgid)
2604 {
2605 IODispatchQueue * queue;
2606 OSObjectUserVars * uvars;
2607 uint64_t option;
2608
2609 uvars = varsForObject(obj);
2610 if (!uvars) {
2611 return NULL;
2612 }
2613 if (!uvars->queueArray) {
2614 if (uvars->stopped) {
2615 return kIODispatchQueueStopped;
2616 }
2617 return NULL;
2618 }
2619 queue = uvars->queueArray[0];
2620
2621 if (uvars->userMeta
2622 && uvars->userMeta->methods) {
2623 uint32_t idx, baseIdx;
2624 uint32_t lim;
2625 // bsearch
2626 for (baseIdx = 0, lim = uvars->userMeta->methodCount; lim; lim >>= 1) {
2627 idx = baseIdx + (lim >> 1);
2628 if (msgid == uvars->userMeta->methods[idx]) {
2629 option = uvars->userMeta->methods[uvars->userMeta->methodCount + idx];
2630 option &= 0xFF;
2631 if (option < uvars->userMeta->queueNames->count) {
2632 queue = uvars->queueArray[option + 1];
2633 }
2634 break;
2635 } else if (msgid > uvars->userMeta->methods[idx]) {
2636 // move right
2637 baseIdx += (lim >> 1) + 1;
2638 lim--;
2639 }
2640 // else move left
2641 }
2642 }
2643 return queue;
2644 }
2645
2646 IOReturn
objectInstantiate(OSObject * obj,IORPC rpc,IORPCMessage * message)2647 IOUserServer::objectInstantiate(OSObject * obj, IORPC rpc, IORPCMessage * message)
2648 {
2649 IOReturn ret;
2650 OSString * str;
2651 OSObject * prop;
2652 IOService * service;
2653
2654 OSAction * action;
2655 OSObject * target;
2656 uint32_t queueCount, queueAlloc;
2657 const char * resultClassName;
2658 uint64_t resultFlags;
2659
2660 mach_msg_size_t replySize;
2661 uint32_t methodCount;
2662 const uint64_t * methods;
2663 IODispatchQueue * queue;
2664 OSUserMetaClass * userMeta;
2665 OSObjectUserVars * uvars;
2666 uint32_t idx;
2667 ipc_port_t sendPort;
2668
2669 OSObject_Instantiate_Rpl_Content * reply;
2670
2671 queueCount = 0;
2672 methodCount = 0;
2673 methods = NULL;
2674 str = NULL;
2675 prop = NULL;
2676 userMeta = NULL;
2677 resultClassName = NULL;
2678 resultFlags = 0;
2679 ret = kIOReturnUnsupportedMode;
2680
2681 service = OSDynamicCast(IOService, obj);
2682 action = OSDynamicCast(OSAction, obj);
2683 if (!service) {
2684 // xxx other classes hosted
2685 resultFlags |= kOSObjectRPCKernel;
2686 resultFlags |= kOSObjectRPCRemote;
2687 } else {
2688 if (service->isInactive()) {
2689 DKLOG(DKS "::instantiate inactive\n", DKN(service));
2690 return kIOReturnOffline;
2691 }
2692 prop = service->copyProperty(gIOUserClassKey);
2693 str = OSDynamicCast(OSString, prop);
2694 if (!service->reserved->uvars) {
2695 resultFlags |= kOSObjectRPCRemote;
2696 resultFlags |= kOSObjectRPCKernel;
2697 } else if (this != service->reserved->uvars->userServer) {
2698 // remote, use base class
2699 resultFlags |= kOSObjectRPCRemote;
2700 }
2701 if (service->reserved->uvars && service->reserved->uvars->userServer) {
2702 if (!str) {
2703 DKLOG("no IOUserClass defined for " DKS "\n", DKN(service));
2704 OSSafeReleaseNULL(prop);
2705 return kIOReturnError;
2706 }
2707 IOLockLock(service->reserved->uvars->userServer->fLock);
2708 userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str);
2709 IOLockUnlock(service->reserved->uvars->userServer->fLock);
2710 }
2711 }
2712 if (!str && !userMeta) {
2713 const OSMetaClass * meta;
2714 meta = obj->getMetaClass();
2715 IOLockLock(fLock);
2716 if (action) {
2717 str = action->ivars->typeName;
2718 if (str) {
2719 userMeta = (typeof(userMeta))fClasses->getObject(str);
2720 }
2721 }
2722 while (meta && !userMeta) {
2723 str = (OSString *) meta->getClassNameSymbol();
2724 userMeta = (typeof(userMeta))fClasses->getObject(str);
2725 if (!userMeta) {
2726 meta = meta->getSuperClass();
2727 }
2728 }
2729 IOLockUnlock(fLock);
2730 }
2731 if (str) {
2732 if (!userMeta) {
2733 IOLockLock(fLock);
2734 userMeta = (typeof(userMeta))fClasses->getObject(str);
2735 IOLockUnlock(fLock);
2736 }
2737 if (kIODKLogSetup & gIODKDebug) {
2738 DKLOG("userMeta %s %p\n", str->getCStringNoCopy(), userMeta);
2739 }
2740 if (userMeta) {
2741 if (kOSObjectRPCRemote & resultFlags) {
2742 if (!action) {
2743 /* Special case: For OSAction subclasses, do not use the superclass */
2744 while (userMeta && !(kOSClassCanRemote & userMeta->description->flags)) {
2745 userMeta = userMeta->superMeta;
2746 }
2747 }
2748 if (userMeta) {
2749 resultClassName = userMeta->description->name;
2750 ret = kIOReturnSuccess;
2751 }
2752 } else {
2753 service->reserved->uvars->userMeta = userMeta;
2754 queueAlloc = 1;
2755 if (userMeta->queueNames) {
2756 queueAlloc += userMeta->queueNames->count;
2757 }
2758 service->reserved->uvars->queueArray =
2759 IONewZero(IODispatchQueue *, queueAlloc);
2760 resultClassName = str->getCStringNoCopy();
2761 ret = kIOReturnSuccess;
2762 }
2763 } else if (kIODKLogSetup & gIODKDebug) {
2764 DKLOG("userMeta %s was not found in fClasses\n", str->getCStringNoCopy());
2765 IOLockLock(fLock);
2766 fClasses->iterateObjects(^bool (const OSSymbol * key, OSObject * val) {
2767 DKLOG(" fClasses[\"%s\"] => %p\n", key->getCStringNoCopy(), val);
2768 return false;
2769 });
2770 IOLockUnlock(fLock);
2771 }
2772 }
2773 OSSafeReleaseNULL(prop);
2774
2775 IORPCMessageMach * machReply = rpc.reply;
2776 replySize = sizeof(OSObject_Instantiate_Rpl);
2777
2778 if ((kIOReturnSuccess == ret) && (kOSObjectRPCRemote & resultFlags)) {
2779 target = obj;
2780 if (action) {
2781 if (action->ivars->referenceSize) {
2782 resultFlags |= kOSObjectRPCKernel;
2783 } else {
2784 resultFlags &= ~kOSObjectRPCKernel;
2785 if (action->ivars->target) {
2786 target = action->ivars->target;
2787 queueCount = 1;
2788 queue = queueForObject(target, action->ivars->targetmsgid);
2789 if (!queue && action->ivars->userServer) {
2790 queue = action->ivars->userServer->fRootQueue;
2791 }
2792 idx = 0;
2793 sendPort = NULL;
2794 if (queue && (kIODispatchQueueStopped != queue)) {
2795 sendPort = ipc_port_copy_send(queue->ivars->serverPort);
2796 }
2797 replySize = sizeof(OSObject_Instantiate_Rpl)
2798 + queueCount * sizeof(machReply->objects[0])
2799 + 2 * methodCount * sizeof(reply->methods[0]);
2800 if (replySize > rpc.replySize) {
2801 assert(false);
2802 return kIOReturnIPCError;
2803 }
2804 machReply->objects[idx].type = MACH_MSG_PORT_DESCRIPTOR;
2805 machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
2806 machReply->objects[idx].name = sendPort;
2807 machReply->objects[idx].pad2 = 0;
2808 machReply->objects[idx].pad_end = 0;
2809 }
2810 }
2811 } else {
2812 uvars = varsForObject(target);
2813 if (uvars && uvars->userMeta) {
2814 queueCount = 1;
2815 if (uvars->userMeta->queueNames) {
2816 queueCount += uvars->userMeta->queueNames->count;
2817 }
2818 methods = &uvars->userMeta->methods[0];
2819 methodCount = uvars->userMeta->methodCount;
2820 replySize = sizeof(OSObject_Instantiate_Rpl)
2821 + queueCount * sizeof(machReply->objects[0])
2822 + 2 * methodCount * sizeof(reply->methods[0]);
2823 if (replySize > rpc.replySize) {
2824 assert(false);
2825 return kIOReturnIPCError;
2826 }
2827 for (idx = 0; idx < queueCount; idx++) {
2828 queue = uvars->queueArray[idx];
2829 sendPort = NULL;
2830 if (queue) {
2831 sendPort = ipc_port_copy_send(queue->ivars->serverPort);
2832 }
2833 machReply->objects[idx].type = MACH_MSG_PORT_DESCRIPTOR;
2834 machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
2835 machReply->objects[idx].name = sendPort;
2836 machReply->objects[idx].pad2 = 0;
2837 machReply->objects[idx].pad_end = 0;
2838 }
2839 }
2840 }
2841 }
2842
2843 if (kIODKLogIPC & gIODKDebug) {
2844 DKLOG("instantiate object %s with user class %s\n", obj->getMetaClass()->getClassName(), str ? str->getCStringNoCopy() : "(null)");
2845 }
2846
2847 if (kIOReturnSuccess != ret) {
2848 DKLOG("%s: no user class found\n", str ? str->getCStringNoCopy() : obj->getMetaClass()->getClassName());
2849 resultClassName = "unknown";
2850 }
2851
2852 machReply->msgh.msgh_id = kIORPCVersionCurrentReply;
2853 machReply->msgh.msgh_size = replySize;
2854 machReply->msgh_body.msgh_descriptor_count = queueCount;
2855
2856 reply = (typeof(reply))IORPCMessageFromMach(machReply, true);
2857 if (!reply) {
2858 return kIOReturnIPCError;
2859 }
2860 if (methodCount) {
2861 bcopy(methods, &reply->methods[0], methodCount * 2 * sizeof(reply->methods[0]));
2862 }
2863 reply->__hdr.msgid = OSObject_Instantiate_ID;
2864 reply->__hdr.flags = kIORPCMessageOneway;
2865 reply->__hdr.objectRefs = 0;
2866 reply->__pad = 0;
2867 reply->flags = resultFlags;
2868 strlcpy(reply->classname, resultClassName, sizeof(reply->classname));
2869 reply->__result = ret;
2870
2871 ret = kIOReturnSuccess;
2872
2873 return ret;
2874 }
2875
2876 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2877
2878 IOReturn
kernelDispatch(OSObject * obj,IORPC rpc)2879 IOUserServer::kernelDispatch(OSObject * obj, IORPC rpc)
2880 {
2881 IOReturn ret;
2882 IORPCMessage * message;
2883
2884 message = IORPCMessageFromMach(rpc.message, false);
2885 if (!message) {
2886 return kIOReturnIPCError;
2887 }
2888
2889 if (OSObject_Instantiate_ID == message->msgid) {
2890 ret = objectInstantiate(obj, rpc, message);
2891 if (kIOReturnSuccess != ret) {
2892 DKLOG("%s: instantiate failed 0x%x\n", obj->getMetaClass()->getClassName(), ret);
2893 }
2894 } else {
2895 if (kIODKLogIPC & gIODKDebug) {
2896 DKLOG("%s::Dispatch kernel 0x%qx\n", obj->getMetaClass()->getClassName(), message->msgid);
2897 }
2898 ret = obj->Dispatch(rpc);
2899 if (kIODKLogIPC & gIODKDebug) {
2900 DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj->getMetaClass()->getClassName(), message->msgid, ret);
2901 }
2902 }
2903
2904 return ret;
2905 }
2906
2907
2908 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2909
2910 OSObject *
target(OSAction * action,IORPCMessage * message)2911 IOUserServer::target(OSAction * action, IORPCMessage * message)
2912 {
2913 OSObject * object;
2914
2915 if (message->msgid != action->ivars->msgid) {
2916 return action;
2917 }
2918 object = action->ivars->target;
2919 if (!object) {
2920 return action;
2921 }
2922 message->msgid = action->ivars->targetmsgid;
2923 message->objects[0] = (OSObjectRef) object;
2924 if (kIORPCMessageRemote & message->flags) {
2925 object->retain();
2926 #ifndef __clang_analyzer__
2927 // Hide the release of 'action' from the clang static analyzer to suppress
2928 // an overrelease diagnostic. The analyzer doesn't have a way to express the
2929 // non-standard contract of this method, which is that it releases 'action' when
2930 // the message flags have kIORPCMessageRemote set.
2931 action->release();
2932 #endif
2933 }
2934 if (kIODKLogIPC & gIODKDebug) {
2935 DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid, action->ivars->msgid);
2936 }
2937
2938 return object;
2939 }
2940
2941 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2942
2943 kern_return_t
uext_server(ipc_port_t receiver,ipc_kmsg_t requestkmsg,ipc_kmsg_t * pReply)2944 uext_server(ipc_port_t receiver, ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
2945 {
2946 kern_return_t ret;
2947 IORPCMessageMach * msgin;
2948 OSObject * object;
2949 IOUserServer * server;
2950
2951 msgin = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
2952
2953 object = IOUserServer::copyObjectForSendRight(receiver, IKOT_UEXT_OBJECT);
2954 server = OSDynamicCast(IOUserServer, object);
2955 if (!server) {
2956 OSSafeReleaseNULL(object);
2957 return KERN_INVALID_NAME;
2958 }
2959 ret = server->server(requestkmsg, pReply);
2960 object->release();
2961
2962 return ret;
2963 }
2964
2965 /*
2966 * Chosen to hit kalloc zones (as opposed to the VM).
2967 * doesn't include the trailer size which ipc_kmsg_alloc() will add
2968 */
2969 #define MAX_UEXT_REPLY_SIZE 0x17c0
2970 static_assert(MAX_UEXT_REPLY_SIZE + MAX_TRAILER_SIZE <= KALLOC_SAFE_ALLOC_SIZE);
2971
2972 kern_return_t
server(ipc_kmsg_t requestkmsg,ipc_kmsg_t * pReply)2973 IOUserServer::server(ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
2974 {
2975 kern_return_t ret;
2976 mach_msg_size_t replyAlloc;
2977 ipc_kmsg_t replykmsg;
2978 IORPCMessageMach * msgin;
2979 IORPCMessage * message;
2980 IORPCMessageMach * msgout;
2981 IORPCMessage * reply;
2982 uint32_t replySize;
2983 OSObject * object;
2984 OSAction * action;
2985 bool oneway;
2986 uint64_t msgid;
2987
2988 msgin = (typeof(msgin))ipc_kmsg_msg_header(requestkmsg);
2989 replyAlloc = 0;
2990 msgout = NULL;
2991 replykmsg = NULL;
2992
2993 if (msgin->msgh.msgh_size < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
2994 if (kIODKLogIPC & gIODKDebug) {
2995 DKLOG("UEXT notify %o\n", msgin->msgh.msgh_id);
2996 }
2997 return KERN_NOT_SUPPORTED;
2998 }
2999
3000 if (!(MACH_MSGH_BITS_COMPLEX & msgin->msgh.msgh_bits)) {
3001 msgin->msgh_body.msgh_descriptor_count = 0;
3002 }
3003 message = IORPCMessageFromMach(msgin, false);
3004 if (!message) {
3005 return kIOReturnIPCError;
3006 }
3007 if (message->objectRefs == 0) {
3008 return kIOReturnIPCError;
3009 }
3010 ret = copyInObjects(msgin, message, msgin->msgh.msgh_size, true, false);
3011 if (kIOReturnSuccess != ret) {
3012 if (kIODKLogIPC & gIODKDebug) {
3013 DKLOG("UEXT copyin(0x%x) %x\n", ret, msgin->msgh.msgh_id);
3014 }
3015 return KERN_NOT_SUPPORTED;
3016 }
3017
3018 if (msgin->msgh_body.msgh_descriptor_count < 1) {
3019 return KERN_NOT_SUPPORTED;
3020 }
3021 object = (OSObject *) message->objects[0];
3022 msgid = message->msgid;
3023 message->flags &= ~kIORPCMessageKernel;
3024 message->flags |= kIORPCMessageRemote;
3025
3026 if ((action = OSDynamicCast(OSAction, object))) {
3027 object = target(action, message);
3028 msgid = message->msgid;
3029 }
3030
3031 oneway = (0 != (kIORPCMessageOneway & message->flags));
3032 assert(oneway || (MACH_PORT_NULL != msgin->msgh.msgh_local_port));
3033
3034 replyAlloc = oneway ? 0 : MAX_UEXT_REPLY_SIZE;
3035 if (replyAlloc) {
3036 /*
3037 * Same as:
3038 * ipc_kmsg_alloc(replyAlloc, 0,
3039 * IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO |
3040 * IPC_KMSG_ALLOC_NOFAIL);
3041 */
3042 replykmsg = ipc_kmsg_alloc_uext_reply(replyAlloc);
3043 msgout = (typeof(msgout))ipc_kmsg_msg_header(replykmsg);
3044 }
3045
3046 IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc };
3047
3048 if (object) {
3049 kern_allocation_name_t prior;
3050 bool setAllocationName;
3051
3052 setAllocationName = (NULL != fAllocationName);
3053 if (setAllocationName) {
3054 prior = thread_set_allocation_name(fAllocationName);
3055 }
3056 thread_iokit_tls_set(0, this);
3057 ret = kernelDispatch(object, rpc);
3058 thread_iokit_tls_set(0, NULL);
3059 if (setAllocationName) {
3060 thread_set_allocation_name(prior);
3061 }
3062 } else {
3063 ret = kIOReturnBadArgument;
3064 }
3065
3066 // release objects
3067 consumeObjects(message, msgin->msgh.msgh_size);
3068
3069 // release ports
3070 copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
3071
3072 if (!oneway) {
3073 if (kIOReturnSuccess == ret) {
3074 replySize = msgout->msgh.msgh_size;
3075 reply = IORPCMessageFromMach(msgout, true);
3076 if (!reply) {
3077 ret = kIOReturnIPCError;
3078 } else {
3079 ret = copyOutObjects(msgout, reply, replySize, (kIORPCVersionCurrentReply == msgout->msgh.msgh_id) /* =>!InvokeReply */);
3080 }
3081 }
3082 if (kIOReturnSuccess != ret) {
3083 IORPCMessageErrorReturnContent * errorMsg;
3084
3085 msgout->msgh_body.msgh_descriptor_count = 0;
3086 msgout->msgh.msgh_id = kIORPCVersionCurrentReply;
3087 errorMsg = (typeof(errorMsg))IORPCMessageFromMach(msgout, true);
3088 errorMsg->hdr.msgid = message->msgid;
3089 errorMsg->hdr.flags = kIORPCMessageOneway | kIORPCMessageError;
3090 errorMsg->hdr.objectRefs = 0;
3091 errorMsg->result = ret;
3092 errorMsg->pad = 0;
3093 replySize = sizeof(IORPCMessageErrorReturn);
3094 }
3095
3096 msgout->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
3097 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin->msgh.msgh_bits) /*remote*/, 0 /*local*/, 0, 0);
3098
3099 msgout->msgh.msgh_remote_port = msgin->msgh.msgh_local_port;
3100 msgout->msgh.msgh_local_port = MACH_PORT_NULL;
3101 msgout->msgh.msgh_voucher_port = (mach_port_name_t) 0;
3102 msgout->msgh.msgh_reserved = 0;
3103 msgout->msgh.msgh_size = replySize;
3104 }
3105
3106 *pReply = replykmsg;
3107 return KERN_SUCCESS;
3108 }
3109
3110 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3111
3112 #define MAX_OBJECT_COUNT(mach, size, message) \
3113 ((uint32_t)(((((size) + ((uintptr_t) (mach))) - ((uintptr_t) (&message->objects[0]))) / sizeof(OSObjectRef))))
3114
3115 kern_return_t
IOUserServerUEXTTrap(OSObject * object,void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)3116 IOUserServerUEXTTrap(OSObject * object, void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
3117 {
3118 const user_addr_t msg = (uintptr_t) p1;
3119 size_t inSize = (uintptr_t) p2;
3120 user_addr_t out = (uintptr_t) p3;
3121 size_t outSize = (uintptr_t) p4;
3122 mach_port_name_t objectName1 = (mach_port_name_t)(uintptr_t) p5;
3123 size_t totalSize;
3124 OSObject * objectArg1;
3125
3126 IORPCMessageMach * mach;
3127 mach_msg_port_descriptor_t * descs;
3128
3129 #pragma pack(4)
3130 struct {
3131 uint32_t pad;
3132 IORPCMessageMach mach;
3133 mach_msg_port_descriptor_t objects[2];
3134 IOTrapMessageBuffer buffer;
3135 } buffer;
3136 #pragma pack()
3137
3138 IOReturn ret;
3139 OSAction * action;
3140 int copyerr;
3141 IORPCMessage * message;
3142 IORPCMessage * reply;
3143 IORPC rpc;
3144 uint64_t refs;
3145 uint32_t maxObjectCount;
3146 size_t copySize;
3147 uint64_t * replyHdr;
3148 uintptr_t p;
3149
3150 bzero(&buffer, sizeof(buffer));
3151
3152 p = (typeof(p)) & buffer.buffer[0];
3153 if (os_add_overflow(inSize, outSize, &totalSize)) {
3154 return kIOReturnMessageTooLarge;
3155 }
3156 if (totalSize > sizeof(buffer.buffer)) {
3157 return kIOReturnMessageTooLarge;
3158 }
3159 if (inSize < sizeof(IORPCMessage)) {
3160 return kIOReturnIPCError;
3161 }
3162 copyerr = copyin(msg, &buffer.buffer[0], inSize);
3163 if (copyerr) {
3164 return kIOReturnVMError;
3165 }
3166
3167 message = (typeof(message))p;
3168 refs = message->objectRefs;
3169 if ((refs > 2) || !refs) {
3170 return kIOReturnUnsupported;
3171 }
3172 if (!(kIORPCMessageSimpleReply & message->flags)) {
3173 return kIOReturnUnsupported;
3174 }
3175
3176 descs = (typeof(descs))(p - refs * sizeof(*descs));
3177 mach = (typeof(mach))(p - refs * sizeof(*descs) - sizeof(*mach));
3178
3179 mach->msgh.msgh_id = kIORPCVersionCurrent;
3180 mach->msgh.msgh_size = (mach_msg_size_t) (sizeof(IORPCMessageMach) + refs * sizeof(*descs) + inSize); // totalSize was checked
3181 mach->msgh_body.msgh_descriptor_count = ((mach_msg_size_t) refs);
3182
3183 rpc.message = mach;
3184 rpc.sendSize = mach->msgh.msgh_size;
3185 rpc.reply = (IORPCMessageMach *) (p + inSize);
3186 rpc.replySize = ((uint32_t) (sizeof(buffer.buffer) - inSize)); // inSize was checked
3187
3188 message->objects[0] = 0;
3189 if ((action = OSDynamicCast(OSAction, object))) {
3190 maxObjectCount = MAX_OBJECT_COUNT(rpc.message, rpc.sendSize, message);
3191 if (refs > maxObjectCount) {
3192 return kIOReturnBadArgument;
3193 }
3194 object = IOUserServer::target(action, message);
3195 message->objects[1] = (OSObjectRef) action;
3196 if (kIODKLogIPC & gIODKDebug) {
3197 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
3198 }
3199 ret = object->Dispatch(rpc);
3200 } else {
3201 objectArg1 = NULL;
3202 if (refs > 1) {
3203 if (objectName1) {
3204 objectArg1 = iokit_lookup_uext_ref_current_task(objectName1);
3205 if (!objectArg1) {
3206 return kIOReturnIPCError;
3207 }
3208 }
3209 message->objects[1] = (OSObjectRef) objectArg1;
3210 }
3211 if (kIODKLogIPC & gIODKDebug) {
3212 DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
3213 }
3214 ret = object->Dispatch(rpc);
3215 if (kIODKLogIPC & gIODKDebug) {
3216 DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object->getMetaClass()->getClassName(), message->msgid, ret);
3217 }
3218 OSSafeReleaseNULL(objectArg1);
3219
3220 if (kIOReturnSuccess == ret) {
3221 if (rpc.reply->msgh_body.msgh_descriptor_count) {
3222 return kIOReturnIPCError;
3223 }
3224 reply = IORPCMessageFromMach(rpc.reply, rpc.reply->msgh.msgh_size);
3225 if (!reply) {
3226 return kIOReturnIPCError;
3227 }
3228 copySize = rpc.reply->msgh.msgh_size - (((uintptr_t) reply) - ((uintptr_t) rpc.reply)) + sizeof(uint64_t);
3229 if (copySize > outSize) {
3230 return kIOReturnIPCError;
3231 }
3232 replyHdr = (uint64_t *) reply;
3233 replyHdr--;
3234 replyHdr[0] = copySize;
3235 copyerr = copyout(replyHdr, out, copySize);
3236 if (copyerr) {
3237 return kIOReturnVMError;
3238 }
3239 }
3240 }
3241
3242 return ret;
3243 }
3244
3245 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3246
3247 IOReturn
rpc(IORPC rpc)3248 IOUserServer::rpc(IORPC rpc)
3249 {
3250 if (isInactive() && !fRootQueue) {
3251 return kIOReturnOffline;
3252 }
3253
3254 IOReturn ret;
3255 IORPCMessage * message;
3256 IORPCMessageMach * mach;
3257 mach_msg_id_t machid;
3258 uint32_t sendSize, replySize;
3259 bool oneway;
3260 uint64_t msgid;
3261 IODispatchQueue * queue;
3262 IOService * service;
3263 ipc_port_t port;
3264 ipc_port_t sendPort;
3265
3266 queue = NULL;
3267 port = NULL;
3268 sendPort = NULL;
3269
3270 mach = rpc.message;
3271 sendSize = rpc.sendSize;
3272 replySize = rpc.replySize;
3273
3274 assert(sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
3275
3276 message = IORPCMessageFromMach(mach, false);
3277 if (!message) {
3278 return kIOReturnIPCError;
3279 }
3280 msgid = message->msgid;
3281 machid = (msgid >> 32);
3282
3283 if (mach->msgh_body.msgh_descriptor_count < 1) {
3284 return kIOReturnNoMedia;
3285 }
3286
3287 IOLockLock(gIOUserServerLock);
3288 if ((service = OSDynamicCast(IOService, (OSObject *) message->objects[0]))) {
3289 queue = queueForObject(service, msgid);
3290 }
3291 if (!queue) {
3292 queue = fRootQueue;
3293 }
3294 if (queue && (kIODispatchQueueStopped != queue)) {
3295 port = queue->ivars->serverPort;
3296 }
3297 if (port) {
3298 sendPort = ipc_port_copy_send(port);
3299 }
3300 IOLockUnlock(gIOUserServerLock);
3301 if (!sendPort) {
3302 return kIOReturnNotReady;
3303 }
3304
3305 oneway = (0 != (kIORPCMessageOneway & message->flags));
3306
3307 ret = copyOutObjects(mach, message, sendSize, false);
3308
3309 mach->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
3310 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (oneway ? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE));
3311 mach->msgh.msgh_remote_port = sendPort;
3312 mach->msgh.msgh_local_port = (oneway ? MACH_PORT_NULL : mig_get_reply_port());
3313 mach->msgh.msgh_id = kIORPCVersionCurrent;
3314 mach->msgh.msgh_reserved = 0;
3315
3316 boolean_t message_moved;
3317
3318 if (oneway) {
3319 ret = kernel_mach_msg_send(&mach->msgh, sendSize,
3320 MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_NOIMPORTANCE,
3321 0, &message_moved);
3322 } else {
3323 assert(replySize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
3324 ret = kernel_mach_msg_rpc(&mach->msgh, sendSize, replySize, FALSE, &message_moved);
3325 }
3326
3327 ipc_port_release_send(sendPort);
3328
3329 if (MACH_MSG_SUCCESS != ret) {
3330 if (kIODKLogIPC & gIODKDebug) {
3331 DKLOG("mach_msg() failed 0x%x\n", ret);
3332 }
3333 if (!message_moved) {
3334 // release ports
3335 copyInObjects(mach, message, sendSize, false, true);
3336 }
3337 }
3338
3339 if ((KERN_SUCCESS == ret) && !oneway) {
3340 if (kIORPCVersionCurrentReply != mach->msgh.msgh_id) {
3341 ret = (MACH_NOTIFY_SEND_ONCE == mach->msgh.msgh_id) ? MIG_SERVER_DIED : MIG_REPLY_MISMATCH;
3342 } else if ((replySize = mach->msgh.msgh_size) < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
3343 // printf("BAD REPLY SIZE\n");
3344 ret = MIG_BAD_ARGUMENTS;
3345 } else {
3346 if (!(MACH_MSGH_BITS_COMPLEX & mach->msgh.msgh_bits)) {
3347 mach->msgh_body.msgh_descriptor_count = 0;
3348 }
3349 message = IORPCMessageFromMach(mach, true);
3350 if (!message) {
3351 ret = kIOReturnIPCError;
3352 } else if (message->msgid != msgid) {
3353 // printf("BAD REPLY ID\n");
3354 ret = MIG_BAD_ARGUMENTS;
3355 } else {
3356 bool isError = (0 != (kIORPCMessageError & message->flags));
3357 ret = copyInObjects(mach, message, replySize, !isError, true);
3358 if (kIOReturnSuccess != ret) {
3359 if (kIODKLogIPC & gIODKDebug) {
3360 DKLOG("rpc copyin(0x%x) %x\n", ret, mach->msgh.msgh_id);
3361 }
3362 return KERN_NOT_SUPPORTED;
3363 }
3364 if (isError) {
3365 IORPCMessageErrorReturnContent * errorMsg = (typeof(errorMsg))message;
3366 ret = errorMsg->result;
3367 }
3368 }
3369 }
3370 }
3371
3372 return ret;
3373 }
3374
3375 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3376
3377 IORPCMessage *
IORPCMessageFromMach(IORPCMessageMach * msg,bool reply)3378 IORPCMessageFromMach(IORPCMessageMach * msg, bool reply)
3379 {
3380 mach_msg_size_t idx, count;
3381 mach_msg_port_descriptor_t * desc;
3382 mach_msg_port_descriptor_t * maxDesc;
3383 size_t size, msgsize;
3384 bool upgrade;
3385
3386 msgsize = msg->msgh.msgh_size;
3387 count = msg->msgh_body.msgh_descriptor_count;
3388 desc = &msg->objects[0];
3389 maxDesc = (typeof(maxDesc))(((uintptr_t) msg) + msgsize);
3390 upgrade = (msg->msgh.msgh_id != (reply ? kIORPCVersionCurrentReply : kIORPCVersionCurrent));
3391
3392 if (upgrade) {
3393 OSReportWithBacktrace("obsolete message");
3394 return NULL;
3395 }
3396
3397 for (idx = 0; idx < count; idx++) {
3398 if (desc >= maxDesc) {
3399 return NULL;
3400 }
3401 switch (desc->type) {
3402 case MACH_MSG_PORT_DESCRIPTOR:
3403 size = sizeof(mach_msg_port_descriptor_t);
3404 break;
3405 case MACH_MSG_OOL_DESCRIPTOR:
3406 size = sizeof(mach_msg_ool_descriptor_t);
3407 break;
3408 default:
3409 return NULL;
3410 }
3411 desc = (typeof(desc))(((uintptr_t) desc) + size);
3412 }
3413 return (IORPCMessage *)(uintptr_t) desc;
3414 }
3415
3416 ipc_port_t
copySendRightForObject(OSObject * object,ipc_kobject_type_t type)3417 IOUserServer::copySendRightForObject(OSObject * object, ipc_kobject_type_t type)
3418 {
3419 ipc_port_t port;
3420 ipc_port_t sendPort = NULL;
3421
3422 port = iokit_port_for_object(object, type);
3423 if (port) {
3424 sendPort = ipc_port_make_send(port);
3425 iokit_release_port(port);
3426 }
3427
3428 return sendPort;
3429 }
3430
3431 OSObject *
copyObjectForSendRight(ipc_port_t port,ipc_kobject_type_t type)3432 IOUserServer::copyObjectForSendRight(ipc_port_t port, ipc_kobject_type_t type)
3433 {
3434 OSObject * object;
3435 object = iokit_lookup_io_object(port, type);
3436 return object;
3437 }
3438
3439 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3440
3441 // Create a vm_map_copy_t or kalloc'ed data for memory
3442 // to be copied out. ipc will free after the copyout.
3443
3444 static kern_return_t
copyoutkdata(const void * data,vm_size_t len,void ** buf)3445 copyoutkdata(const void * data, vm_size_t len, void ** buf)
3446 {
3447 kern_return_t err;
3448 vm_map_copy_t copy;
3449
3450 err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
3451 false /* src_destroy */, ©);
3452
3453 assert( err == KERN_SUCCESS );
3454 if (err == KERN_SUCCESS) {
3455 *buf = (char *) copy;
3456 }
3457
3458 return err;
3459 }
3460
3461 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3462
3463 IOReturn
copyOutObjects(IORPCMessageMach * mach,IORPCMessage * message,size_t size,bool consume)3464 IOUserServer::copyOutObjects(IORPCMessageMach * mach, IORPCMessage * message,
3465 size_t size, bool consume)
3466 {
3467 uint64_t refs;
3468 uint32_t idx, maxObjectCount;
3469 ipc_port_t port;
3470 OSObject * object;
3471 size_t descsize;
3472 mach_msg_port_descriptor_t * desc;
3473 mach_msg_ool_descriptor_t * ool;
3474 vm_map_copy_t copy;
3475 void * address;
3476 mach_msg_size_t length;
3477 kern_return_t kr;
3478 OSSerialize * s;
3479
3480 refs = message->objectRefs;
3481 maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3482 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
3483 // assert(refs <= maxObjectCount);
3484 if (refs > mach->msgh_body.msgh_descriptor_count) {
3485 return kIOReturnBadArgument;
3486 }
3487 if (refs > maxObjectCount) {
3488 return kIOReturnBadArgument;
3489 }
3490
3491 desc = &mach->objects[0];
3492 for (idx = 0; idx < refs; idx++) {
3493 object = (OSObject *) message->objects[idx];
3494
3495 switch (desc->type) {
3496 case MACH_MSG_PORT_DESCRIPTOR:
3497 descsize = sizeof(mach_msg_port_descriptor_t);
3498 port = NULL;
3499 if (object) {
3500 port = copySendRightForObject(object, IKOT_UEXT_OBJECT);
3501 if (!port) {
3502 break;
3503 }
3504 if (consume) {
3505 object->release();
3506 }
3507 message->objects[idx] = 0;
3508 }
3509 // desc->type = MACH_MSG_PORT_DESCRIPTOR;
3510 desc->disposition = MACH_MSG_TYPE_MOVE_SEND;
3511 desc->name = port;
3512 desc->pad2 = 0;
3513 desc->pad_end = 0;
3514 break;
3515
3516 case MACH_MSG_OOL_DESCRIPTOR:
3517 descsize = sizeof(mach_msg_ool_descriptor_t);
3518
3519 length = 0;
3520 address = NULL;
3521 if (object) {
3522 s = OSSerialize::binaryWithCapacity(4096);
3523 assert(s);
3524 if (!s) {
3525 break;
3526 }
3527 s->setIndexed(true);
3528 if (!object->serialize(s)) {
3529 assert(false);
3530 descsize = -1UL;
3531 s->release();
3532 break;
3533 }
3534 length = s->getLength();
3535 kr = copyoutkdata(s->text(), length, &address);
3536 s->release();
3537 if (KERN_SUCCESS != kr) {
3538 descsize = -1UL;
3539 address = NULL;
3540 length = 0;
3541 }
3542 if (consume) {
3543 object->release();
3544 }
3545 message->objects[idx] = 0;
3546 }
3547 ool = (typeof(ool))desc;
3548 // ool->type = MACH_MSG_OOL_DESCRIPTOR;
3549 ool->deallocate = false;
3550 ool->copy = MACH_MSG_PHYSICAL_COPY;
3551 ool->size = length;
3552 ool->address = address;
3553 break;
3554
3555 default:
3556 descsize = -1UL;
3557 break;
3558 }
3559 if (-1UL == descsize) {
3560 break;
3561 }
3562 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3563 }
3564
3565 if (idx >= refs) {
3566 return kIOReturnSuccess;
3567 }
3568
3569 desc = &mach->objects[0];
3570 while (idx--) {
3571 switch (desc->type) {
3572 case MACH_MSG_PORT_DESCRIPTOR:
3573 descsize = sizeof(mach_msg_port_descriptor_t);
3574 port = desc->name;
3575 if (port) {
3576 ipc_port_release_send(port);
3577 }
3578 break;
3579
3580 case MACH_MSG_OOL_DESCRIPTOR:
3581 descsize = sizeof(mach_msg_ool_descriptor_t);
3582 ool = (typeof(ool))desc;
3583 copy = (vm_map_copy_t) ool->address;
3584 if (copy) {
3585 vm_map_copy_discard(copy);
3586 }
3587 break;
3588
3589 default:
3590 descsize = -1UL;
3591 break;
3592 }
3593 if (-1UL == descsize) {
3594 break;
3595 }
3596 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3597 }
3598
3599 return kIOReturnBadArgument;
3600 }
3601
3602 IOReturn
copyInObjects(IORPCMessageMach * mach,IORPCMessage * message,size_t size,bool copyObjects,bool consumePorts)3603 IOUserServer::copyInObjects(IORPCMessageMach * mach, IORPCMessage * message,
3604 size_t size, bool copyObjects, bool consumePorts)
3605 {
3606 uint64_t refs;
3607 uint32_t idx, maxObjectCount;
3608 ipc_port_t port;
3609 OSObject * object;
3610 size_t descsize;
3611 mach_msg_port_descriptor_t * desc;
3612 mach_msg_ool_descriptor_t * ool;
3613 vm_map_address_t copyoutdata;
3614 kern_return_t kr;
3615
3616 refs = message->objectRefs;
3617 maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3618 // assert(refs <= mach->msgh_body.msgh_descriptor_count);
3619 // assert(refs <= maxObjectCount);
3620 if (refs > mach->msgh_body.msgh_descriptor_count) {
3621 return kIOReturnBadArgument;
3622 }
3623 if (refs > maxObjectCount) {
3624 return kIOReturnBadArgument;
3625 }
3626
3627 desc = &mach->objects[0];
3628 for (idx = 0; idx < refs; idx++) {
3629 switch (desc->type) {
3630 case MACH_MSG_PORT_DESCRIPTOR:
3631 descsize = sizeof(mach_msg_port_descriptor_t);
3632
3633 object = NULL;
3634 port = desc->name;
3635 if (port) {
3636 if (copyObjects) {
3637 object = copyObjectForSendRight(port, IKOT_UEXT_OBJECT);
3638 if (!object) {
3639 descsize = -1UL;
3640 break;
3641 }
3642 }
3643 if (consumePorts) {
3644 ipc_port_release_send(port);
3645 }
3646 }
3647 break;
3648
3649 case MACH_MSG_OOL_DESCRIPTOR:
3650 descsize = sizeof(mach_msg_ool_descriptor_t);
3651 ool = (typeof(ool))desc;
3652
3653 object = NULL;
3654 if (copyObjects && ool->size && ool->address) {
3655 kr = vm_map_copyout(kernel_map, ©outdata, (vm_map_copy_t) ool->address);
3656 if (KERN_SUCCESS == kr) {
3657 object = OSUnserializeXML((const char *) copyoutdata, ool->size);
3658 kr = vm_deallocate(kernel_map, copyoutdata, ool->size);
3659 assert(KERN_SUCCESS == kr);
3660 // vm_map_copyout() has consumed the vm_map_copy_t in the message
3661 ool->size = 0;
3662 ool->address = NULL;
3663 }
3664 if (!object) {
3665 descsize = -1UL;
3666 break;
3667 }
3668 }
3669 break;
3670
3671 default:
3672 descsize = -1UL;
3673 break;
3674 }
3675 if (-1UL == descsize) {
3676 break;
3677 }
3678 if (copyObjects) {
3679 message->objects[idx] = (OSObjectRef) object;
3680 }
3681 desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3682 }
3683
3684 if (idx >= refs) {
3685 return kIOReturnSuccess;
3686 }
3687
3688 while (idx--) {
3689 object = (OSObject *) message->objects[idx];
3690 object->release();
3691 message->objects[idx] = 0;
3692 }
3693
3694 return kIOReturnBadArgument;
3695 }
3696
3697 IOReturn
consumeObjects(IORPCMessage * message,size_t messageSize)3698 IOUserServer::consumeObjects(IORPCMessage * message, size_t messageSize)
3699 {
3700 uint64_t refs, idx;
3701 OSObject * object;
3702
3703 refs = message->objectRefs;
3704 for (idx = 0; idx < refs; idx++) {
3705 object = (OSObject *) message->objects[idx];
3706 if (object) {
3707 object->release();
3708 message->objects[idx] = 0;
3709 }
3710 }
3711
3712 return kIOReturnSuccess;
3713 }
3714
3715 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3716
3717 bool
finalize(IOOptionBits options)3718 IOUserServer::finalize(IOOptionBits options)
3719 {
3720 OSArray * services;
3721
3722 if (kIODKLogSetup & gIODKDebug) {
3723 DKLOG("%s::finalize(%p)\n", getName(), this);
3724 }
3725
3726 IOLockLock(gIOUserServerLock);
3727 OSSafeReleaseNULL(fRootQueue);
3728 IOLockUnlock(gIOUserServerLock);
3729
3730 services = NULL;
3731 IOLockLock(fLock);
3732 if (fServices) {
3733 services = OSArray::withArray(fServices);
3734 }
3735 IOLockUnlock(fLock);
3736
3737 if (services) {
3738 services->iterateObjects(^bool (OSObject * obj) {
3739 int service __unused; // hide outer defn
3740 IOService * nextService;
3741 IOService * provider;
3742 bool started = false;
3743
3744 nextService = (IOService *) obj;
3745 if (kIODKLogSetup & gIODKDebug) {
3746 DKLOG("%s::terminate(" DKS ")\n", getName(), DKN(nextService));
3747 }
3748 if (nextService->reserved->uvars) {
3749 started = nextService->reserved->uvars->started;
3750 nextService->reserved->uvars->serverDied = true;
3751 if (started) {
3752 provider = nextService->getProvider();
3753 serviceDidStop(nextService, provider);
3754 nextService->terminate(kIOServiceTerminateNeedWillTerminate
3755 | kIOServiceTerminateWithRematch
3756 | kIOServiceTerminateWithRematchCurrentDext);
3757 }
3758 }
3759 if (!started) {
3760 DKLOG("%s::terminate(" DKS ") server exit before start()\n", getName(), DKN(nextService));
3761 serviceStop(nextService, NULL);
3762 }
3763 return false;
3764 });
3765 services->release();
3766 }
3767
3768 return IOUserClient::finalize(options);
3769 }
3770
3771 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3772
3773 #undef super
3774 #define super IOUserClient
3775
OSDefineMetaClassAndStructors(IOUserServer,IOUserClient)3776 OSDefineMetaClassAndStructors(IOUserServer, IOUserClient)
3777
3778 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3779
3780 IOUserClient * IOUserServer::withTask(task_t owningTask)
3781 {
3782 IOUserServer * inst;
3783
3784 assert(owningTask == current_task());
3785 if (!task_is_driver(owningTask)) {
3786 DKLOG("IOUserServer may only be created with driver tasks\n");
3787 return NULL;
3788 }
3789
3790 inst = new IOUserServer;
3791 if (inst && !inst->init()) {
3792 inst->release();
3793 inst = NULL;
3794 return inst;
3795 }
3796 inst->PMinit();
3797
3798 inst->fOwningTask = current_task();
3799 inst->fEntitlements = IOUserClient::copyClientEntitlements(inst->fOwningTask);
3800
3801 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
3802 if (!IOCurrentTaskHasEntitlement(gIODriverKitEntitlementKey->getCStringNoCopy())) {
3803 proc_t p;
3804 pid_t pid;
3805
3806 p = (proc_t)get_bsdtask_info(inst->fOwningTask);
3807 if (p) {
3808 pid = proc_pid(p);
3809 IOLog(kIODriverKitEntitlementKey " entitlement check failed for %s[%d]\n", proc_best_name(p), pid);
3810 }
3811 inst->release();
3812 inst = NULL;
3813 return inst;
3814 }
3815 }
3816
3817 /* Mark the current task's space as eligible for uext object ports */
3818 iokit_label_dext_task(inst->fOwningTask);
3819
3820 inst->fLock = IOLockAlloc();
3821 inst->fServices = OSArray::withCapacity(4);
3822 inst->fClasses = OSDictionary::withCapacity(16);
3823 inst->fClasses->setOptions(OSCollection::kSort, OSCollection::kSort);
3824
3825 return inst;
3826 }
3827
3828 IOReturn
clientClose(void)3829 IOUserServer::clientClose(void)
3830 {
3831 OSArray * services;
3832
3833 if (kIODKLogSetup & gIODKDebug) {
3834 DKLOG("%s::clientClose(%p)\n", getName(), this);
3835 }
3836
3837 services = NULL;
3838 IOLockLock(fLock);
3839 if (fServices) {
3840 services = OSArray::withArray(fServices);
3841 }
3842 IOLockUnlock(fLock);
3843
3844 // if this was a an expected exit, termination and stop should have detached at this
3845 // point, so send any provider still attached and not owned by this user server
3846 // the ClientCrashed() notification
3847 if (services) {
3848 services->iterateObjects(^bool (OSObject * obj) {
3849 int service __unused; // hide outer defn
3850 IOService * nextService;
3851 IOService * provider;
3852
3853 nextService = (IOService *) obj;
3854 if (nextService->isInactive()) {
3855 return false;
3856 }
3857 provider = nextService->getProvider();
3858 if (provider
3859 && (!provider->reserved->uvars || (provider->reserved->uvars->userServer != this))) {
3860 if (kIODKLogSetup & gIODKDebug) {
3861 DKLOG(DKS "::ClientCrashed(" DKS ")\n", DKN(provider), DKN(nextService));
3862 }
3863 provider->ClientCrashed(nextService, 0);
3864 }
3865 return false;
3866 });
3867 services->release();
3868 }
3869
3870 terminate();
3871 return kIOReturnSuccess;
3872 }
3873
3874 IOReturn
setProperties(OSObject * properties)3875 IOUserServer::setProperties(OSObject * properties)
3876 {
3877 IOReturn kr = kIOReturnUnsupported;
3878 return kr;
3879 }
3880
3881 void
stop(IOService * provider)3882 IOUserServer::stop(IOService * provider)
3883 {
3884 fOwningTask = TASK_NULL;
3885
3886 PMstop();
3887
3888 IOServicePH::serverRemove(this);
3889
3890 OSSafeReleaseNULL(fRootQueue);
3891
3892 if (fInterruptLock) {
3893 IOSimpleLockFree(fInterruptLock);
3894 }
3895 }
3896
3897 void
free()3898 IOUserServer::free()
3899 {
3900 OSSafeReleaseNULL(fEntitlements);
3901 OSSafeReleaseNULL(fClasses);
3902 if (fLock) {
3903 IOLockFree(fLock);
3904 }
3905 OSSafeReleaseNULL(fServices);
3906 OSSafeReleaseNULL(fCheckInToken);
3907 if (fAllocationName) {
3908 kern_allocation_name_release(fAllocationName);
3909 fAllocationName = NULL;
3910 }
3911 IOUserClient::free();
3912 }
3913
3914 IOReturn
registerClass(OSClassDescription * desc,uint32_t size,OSUserMetaClass ** pCls)3915 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSUserMetaClass ** pCls)
3916 {
3917 OSUserMetaClass * cls;
3918 const OSSymbol * sym;
3919 uint64_t * methodOptions;
3920 const char * queueNames;
3921 uint32_t methodOptionsEnd, queueNamesEnd;
3922 IOReturn ret = kIOReturnSuccess;
3923
3924 if (size < sizeof(OSClassDescription)) {
3925 assert(false);
3926 return kIOReturnBadArgument;
3927 }
3928
3929 if (kIODKLogSetup & gIODKDebug) {
3930 DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc->name, desc->queueNamesSize, desc->methodNamesSize);
3931 }
3932
3933 if (desc->descriptionSize != size) {
3934 assert(false);
3935 return kIOReturnBadArgument;
3936 }
3937 if (os_add_overflow(desc->queueNamesOffset, desc->queueNamesSize, &queueNamesEnd)) {
3938 assert(false);
3939 return kIOReturnBadArgument;
3940 }
3941 if (queueNamesEnd > size) {
3942 assert(false);
3943 return kIOReturnBadArgument;
3944 }
3945 if (os_add_overflow(desc->methodOptionsOffset, desc->methodOptionsSize, &methodOptionsEnd)) {
3946 assert(false);
3947 return kIOReturnBadArgument;
3948 }
3949 if (methodOptionsEnd > size) {
3950 assert(false);
3951 return kIOReturnBadArgument;
3952 }
3953 // overlaps?
3954 if ((desc->queueNamesOffset >= desc->methodOptionsOffset) && (desc->queueNamesOffset < methodOptionsEnd)) {
3955 assert(false);
3956 return kIOReturnBadArgument;
3957 }
3958 if ((queueNamesEnd >= desc->methodOptionsOffset) && (queueNamesEnd < methodOptionsEnd)) {
3959 assert(false);
3960 return kIOReturnBadArgument;
3961 }
3962
3963 if (desc->methodOptionsSize & ((2 * sizeof(uint64_t)) - 1)) {
3964 assert(false);
3965 return kIOReturnBadArgument;
3966 }
3967 if (sizeof(desc->name) == strnlen(desc->name, sizeof(desc->name))) {
3968 assert(false);
3969 return kIOReturnBadArgument;
3970 }
3971 if (sizeof(desc->superName) == strnlen(desc->superName, sizeof(desc->superName))) {
3972 assert(false);
3973 return kIOReturnBadArgument;
3974 }
3975
3976 cls = OSTypeAlloc(OSUserMetaClass);
3977 assert(cls);
3978 if (!cls) {
3979 return kIOReturnNoMemory;
3980 }
3981
3982 cls->description = (typeof(cls->description))IOMallocData(size);
3983 assert(cls->description);
3984 if (!cls->description) {
3985 assert(false);
3986 cls->release();
3987 return kIOReturnNoMemory;
3988 }
3989 bcopy(desc, cls->description, size);
3990
3991 cls->methodCount = desc->methodOptionsSize / (2 * sizeof(uint64_t));
3992 cls->methods = IONewData(uint64_t, 2 * cls->methodCount);
3993 if (!cls->methods) {
3994 assert(false);
3995 cls->release();
3996 return kIOReturnNoMemory;
3997 }
3998
3999 methodOptions = (typeof(methodOptions))(((uintptr_t) desc) + desc->methodOptionsOffset);
4000 bcopy(methodOptions, cls->methods, 2 * cls->methodCount * sizeof(uint64_t));
4001
4002 queueNames = (typeof(queueNames))(((uintptr_t) desc) + desc->queueNamesOffset);
4003 cls->queueNames = copyInStringArray(queueNames, desc->queueNamesSize);
4004
4005 sym = OSSymbol::withCString(desc->name);
4006 assert(sym);
4007 if (!sym) {
4008 assert(false);
4009 cls->release();
4010 return kIOReturnNoMemory;
4011 }
4012
4013 cls->name = sym;
4014 cls->meta = OSMetaClass::copyMetaClassWithName(sym);
4015 IOLockLock(fLock);
4016 cls->superMeta = OSDynamicCast(OSUserMetaClass, fClasses->getObject(desc->superName));
4017 if (fClasses->getObject(sym) != NULL) {
4018 /* class with this name exists */
4019 ret = kIOReturnBadArgument;
4020 } else {
4021 if (fClasses->setObject(sym, cls)) {
4022 *pCls = cls;
4023 } else {
4024 /* could not add class to fClasses */
4025 ret = kIOReturnNoMemory;
4026 }
4027 }
4028 IOLockUnlock(fLock);
4029 cls->release();
4030 return ret;
4031 }
4032
4033 IOReturn
registerClass(OSClassDescription * desc,uint32_t size,OSSharedPtr<OSUserMetaClass> & pCls)4034 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSSharedPtr<OSUserMetaClass>& pCls)
4035 {
4036 OSUserMetaClass* pClsRaw = NULL;
4037 IOReturn result = registerClass(desc, size, &pClsRaw);
4038 if (result == kIOReturnSuccess) {
4039 pCls.reset(pClsRaw, OSRetain);
4040 }
4041 return result;
4042 }
4043
4044 IOReturn
setRootQueue(IODispatchQueue * queue)4045 IOUserServer::setRootQueue(IODispatchQueue * queue)
4046 {
4047 assert(!fRootQueue);
4048 if (fRootQueue) {
4049 return kIOReturnStillOpen;
4050 }
4051 queue->retain();
4052 fRootQueue = queue;
4053
4054 return kIOReturnSuccess;
4055 }
4056
4057 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)4058 IOUserServer::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
4059 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
4060 {
4061 IOReturn ret = kIOReturnBadArgument;
4062 mach_port_name_t portname;
4063
4064 switch (selector) {
4065 case kIOUserServerMethodRegisterClass:
4066 {
4067 OSUserMetaClass * cls;
4068 if (!args->structureInputSize) {
4069 return kIOReturnBadArgument;
4070 }
4071 if (args->scalarOutputCount != 2) {
4072 return kIOReturnBadArgument;
4073 }
4074 ret = registerClass((OSClassDescription *) args->structureInput, args->structureInputSize, &cls);
4075 if (kIOReturnSuccess == ret) {
4076 portname = iokit_make_send_right(fOwningTask, cls, IKOT_UEXT_OBJECT);
4077 assert(portname);
4078 args->scalarOutput[0] = portname;
4079 args->scalarOutput[1] = kOSObjectRPCRemote;
4080 }
4081 break;
4082 }
4083 case kIOUserServerMethodStart:
4084 {
4085 if (args->scalarOutputCount != 1) {
4086 return kIOReturnBadArgument;
4087 }
4088 if (!(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
4089 if (args->scalarInputCount != 1) {
4090 return kIOReturnBadArgument;
4091 }
4092 mach_port_name_t checkInPortName = ((typeof(checkInPortName))args->scalarInput[0]);
4093 OSObject * obj = iokit_lookup_object_with_port_name(checkInPortName, IKOT_IOKIT_IDENT, fOwningTask);
4094 IOUserServerCheckInToken * retrievedToken = OSDynamicCast(IOUserServerCheckInToken, obj);
4095 if (retrievedToken != NULL) {
4096 setCheckInToken(retrievedToken);
4097 } else {
4098 OSSafeReleaseNULL(obj);
4099 return kIOReturnBadArgument;
4100 }
4101 OSSafeReleaseNULL(obj);
4102 }
4103 portname = iokit_make_send_right(fOwningTask, this, IKOT_UEXT_OBJECT);
4104 assert(portname);
4105 args->scalarOutput[0] = portname;
4106 ret = kIOReturnSuccess;
4107 break;
4108 }
4109 default:
4110 break;
4111 }
4112
4113 return ret;
4114 }
4115
4116 IOExternalTrap *
getTargetAndTrapForIndex(IOService ** targetP,UInt32 index)4117 IOUserServer::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
4118 {
4119 static const IOExternalTrap trapTemplate[] = {
4120 { NULL, (IOTrap) & IOUserServer::waitInterruptTrap},
4121 };
4122 if (index >= (sizeof(trapTemplate) / sizeof(IOExternalTrap))) {
4123 return NULL;
4124 }
4125 *targetP = this;
4126 return (IOExternalTrap *)&trapTemplate[index];
4127 }
4128
4129 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4130
4131 IOReturn
serviceAttach(IOService * service,IOService * provider)4132 IOUserServer::serviceAttach(IOService * service, IOService * provider)
4133 {
4134 IOReturn ret;
4135 OSObjectUserVars * vars;
4136 OSObject * prop;
4137 OSString * str;
4138 OSSymbol const* bundleID;
4139 char execPath[1024];
4140
4141 vars = IOMallocType(OSObjectUserVars);
4142 service->reserved->uvars = vars;
4143
4144 vars->userServer = this;
4145 vars->userServer->retain();
4146 vars->uvarsLock = IOLockAlloc();
4147 IOLockLock(fLock);
4148 if (-1U == fServices->getNextIndexOfObject(service, 0)) {
4149 fServices->setObject(service);
4150
4151 // Add to IOAssociatedServices
4152 OSObject * serviceArrayObj = copyProperty(gIOAssociatedServicesKey);
4153 OSArray * serviceArray = OSDynamicCast(OSArray, serviceArrayObj);
4154 if (!serviceArray) {
4155 serviceArray = OSArray::withCapacity(0);
4156 } else {
4157 serviceArray = OSDynamicCast(OSArray, serviceArray->copyCollection());
4158 assert(serviceArray != NULL);
4159 }
4160
4161 OSNumber * registryEntryNumber = OSNumber::withNumber(service->getRegistryEntryID(), 64);
4162 serviceArray->setObject(registryEntryNumber);
4163 setProperty(gIOAssociatedServicesKey, serviceArray);
4164 OSSafeReleaseNULL(registryEntryNumber);
4165 OSSafeReleaseNULL(serviceArray);
4166 OSSafeReleaseNULL(serviceArrayObj);
4167 }
4168 IOLockUnlock(fLock);
4169
4170 prop = service->copyProperty(gIOUserClassKey);
4171 str = OSDynamicCast(OSString, prop);
4172 if (str) {
4173 service->setName(str);
4174 }
4175 OSSafeReleaseNULL(prop);
4176
4177 prop = service->copyProperty(gIOModuleIdentifierKey);
4178 bundleID = OSDynamicCast(OSSymbol, prop);
4179 if (bundleID) {
4180 execPath[0] = 0;
4181 bool ok = OSKext::copyUserExecutablePath(bundleID, execPath, sizeof(execPath));
4182 if (ok) {
4183 ret = LoadModule(execPath);
4184 if (kIODKLogSetup & gIODKDebug) {
4185 DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret, execPath);
4186 }
4187 }
4188 }
4189 OSSafeReleaseNULL(prop);
4190
4191 ret = kIOReturnSuccess;
4192
4193 return ret;
4194 }
4195
4196 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4197
4198 #define kDriverKitUCPrefix "com.apple.developer.driverkit.userclient-access."
4199
4200 IOReturn
serviceNewUserClient(IOService * service,task_t owningTask,void * securityID,uint32_t type,OSDictionary * properties,IOUserClient ** handler)4201 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
4202 uint32_t type, OSDictionary * properties, IOUserClient ** handler)
4203 {
4204 IOReturn ret;
4205 IOUserClient * uc;
4206 IOUserUserClient * userUC;
4207 OSDictionary * entitlements;
4208 OSObject * prop;
4209 OSObject * bundleID;
4210 bool ok;
4211
4212 entitlements = IOUserClient::copyClientEntitlements(owningTask);
4213 if (!entitlements) {
4214 entitlements = OSDictionary::withCapacity(8);
4215 }
4216 if (entitlements && (kIOReturnSuccess == clientHasPrivilege((void *) owningTask, kIOClientPrivilegeAdministrator))) {
4217 entitlements->setObject(kIODriverKitUserClientEntitlementAdministratorKey, kOSBooleanTrue);
4218 }
4219
4220 *handler = NULL;
4221 ret = service->_NewUserClient(type, entitlements, &uc);
4222 if (kIOReturnSuccess != ret) {
4223 OSSafeReleaseNULL(entitlements);
4224 return ret;
4225 }
4226 userUC = OSDynamicCast(IOUserUserClient, uc);
4227 if (!userUC) {
4228 uc->terminate();
4229 OSSafeReleaseNULL(uc);
4230 OSSafeReleaseNULL(entitlements);
4231 return kIOReturnUnsupported;
4232 }
4233 userUC->setTask(owningTask);
4234
4235 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
4236 if (entitlements && (prop = entitlements->getObject(gIODriverKitRequiredEntitlementsKey))) {
4237 prop->retain();
4238 ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
4239 if (!ok && fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowAnyKey)) {
4240 ok = true;
4241 }
4242 } else {
4243 bundleID = NULL;
4244 if (fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowAnyKey)) {
4245 ok = true;
4246 } else {
4247 bundleID = service->copyProperty(gIOModuleIdentifierKey);
4248 ok = (entitlements
4249 && bundleID
4250 && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey)));
4251 if (ok) {
4252 bool found __block = false;
4253 ok = prop->iterateObjects(^bool (OSObject * object) {
4254 found = object->isEqualTo(bundleID);
4255 return found;
4256 });
4257 ok = found;
4258 }
4259 OSSafeReleaseNULL(bundleID);
4260 }
4261 if (ok) {
4262 prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
4263 ok = checkEntitlements(entitlements, prop, NULL, NULL);
4264 }
4265 }
4266
4267 if (!ok) {
4268 DKLOG(DKS ":UC entitlements check failed\n", DKN(userUC));
4269 uc->terminate();
4270 OSSafeReleaseNULL(uc);
4271 OSSafeReleaseNULL(entitlements);
4272 return kIOReturnNotPermitted;
4273 }
4274 }
4275
4276 OSSafeReleaseNULL(entitlements);
4277 *handler = userUC;
4278
4279 return ret;
4280 }
4281
4282 IOReturn
serviceNewUserClient(IOService * service,task_t owningTask,void * securityID,uint32_t type,OSDictionary * properties,OSSharedPtr<IOUserClient> & handler)4283 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
4284 uint32_t type, OSDictionary * properties, OSSharedPtr<IOUserClient>& handler)
4285 {
4286 IOUserClient* handlerRaw = NULL;
4287 IOReturn result = serviceNewUserClient(service, owningTask, securityID, type, properties, &handlerRaw);
4288 handler.reset(handlerRaw, OSNoRetain);
4289 return result;
4290 }
4291
4292 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4293
4294 static IOPMPowerState
4295 sPowerStates[] = {
4296 { .version = kIOPMPowerStateVersion1,
4297 .capabilityFlags = 0,
4298 .outputPowerCharacter = 0,
4299 .inputPowerRequirement = 0},
4300 { .version = kIOPMPowerStateVersion1,
4301 .capabilityFlags = kIOPMLowPower,
4302 .outputPowerCharacter = kIOPMLowPower,
4303 .inputPowerRequirement = kIOPMLowPower},
4304 { .version = kIOPMPowerStateVersion1,
4305 .capabilityFlags = kIOPMPowerOn,
4306 .outputPowerCharacter = kIOPMPowerOn,
4307 .inputPowerRequirement = kIOPMPowerOn},
4308 };
4309
4310 IOReturn
setPowerState(unsigned long state,IOService * service)4311 IOUserServer::setPowerState(unsigned long state, IOService * service)
4312 {
4313 if (kIODKLogPM & gIODKDebug) {
4314 DKLOG(DKS "::setPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
4315 }
4316 return kIOPMAckImplied;
4317 }
4318
4319 IOReturn
serviceSetPowerState(IOService * controllingDriver,IOService * service,IOPMPowerFlags flags,unsigned long state)4320 IOUserServer::serviceSetPowerState(IOService * controllingDriver, IOService * service, IOPMPowerFlags flags, unsigned long state)
4321 {
4322 IOReturn ret;
4323 bool sendIt = false;
4324
4325 IOLockLock(fLock);
4326 if (service->reserved->uvars) {
4327 if (!fSystemOff && !(kIODKDisablePM & gIODKDebug)) {
4328 service->reserved->uvars->willPower = true;
4329 service->reserved->uvars->willPowerState = state;
4330 service->reserved->uvars->controllingDriver = controllingDriver;
4331 sendIt = true;
4332 } else {
4333 service->reserved->uvars->willPower = false;
4334 }
4335 }
4336 IOLockUnlock(fLock);
4337
4338 if (sendIt) {
4339 if (kIODKLogPM & gIODKDebug) {
4340 DKLOG(DKS "::serviceSetPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
4341 }
4342 ret = service->SetPowerState((uint32_t) flags);
4343 if (kIOReturnSuccess == ret) {
4344 return 20 * 1000 * 1000;
4345 } else {
4346 IOLockLock(fLock);
4347 service->reserved->uvars->willPower = false;
4348 IOLockUnlock(fLock);
4349 }
4350 }
4351
4352 return kIOPMAckImplied;
4353 }
4354
4355 IOReturn
powerStateWillChangeTo(IOPMPowerFlags flags,unsigned long state,IOService * service)4356 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
4357 {
4358 return kIOPMAckImplied;
4359 }
4360
4361 IOReturn
powerStateDidChangeTo(IOPMPowerFlags flags,unsigned long state,IOService * service)4362 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
4363 {
4364 unsigned int idx;
4365 bool pmAck;
4366
4367 pmAck = false;
4368 IOLockLock(fLock);
4369 idx = fServices->getNextIndexOfObject(service, 0);
4370 if (-1U == idx) {
4371 IOLockUnlock(fLock);
4372 return kIOPMAckImplied;
4373 }
4374
4375 service->reserved->uvars->powerState = (0 != state);
4376 bool allPowerStates __block = 0;
4377 if (!state) {
4378 // any service on?
4379 fServices->iterateObjects(^bool (OSObject * obj) {
4380 int service __unused; // hide outer defn
4381 IOService * nextService;
4382 nextService = (IOService *) obj;
4383 allPowerStates = nextService->reserved->uvars->powerState;
4384 // early terminate if true
4385 return allPowerStates;
4386 });
4387 }
4388 if (kIODKLogPM & gIODKDebug) {
4389 DKLOG(DKS "::powerStateDidChangeTo(%ld) %d, %d\n", DKN(service), state, allPowerStates, fSystemPowerAck);
4390 }
4391 if (!allPowerStates && (pmAck = fSystemPowerAck)) {
4392 fSystemPowerAck = false;
4393 fSystemOff = true;
4394 }
4395 IOLockUnlock(fLock);
4396
4397 if (pmAck) {
4398 IOServicePH::serverAck(this);
4399 }
4400
4401 return kIOPMAckImplied;
4402 }
4403
4404 kern_return_t
SetPowerState_Impl(uint32_t powerFlags)4405 IOService::SetPowerState_Impl(
4406 uint32_t powerFlags)
4407 {
4408 if (kIODKLogPM & gIODKDebug) {
4409 DKLOG(DKS "::SetPowerState(%d), %d\n", DKN(this), powerFlags, reserved->uvars->willPower);
4410 }
4411 if (reserved->uvars
4412 && reserved->uvars->userServer
4413 && reserved->uvars->willPower) {
4414 IOReturn ret;
4415 reserved->uvars->willPower = false;
4416 ret = reserved->uvars->controllingDriver->setPowerState(reserved->uvars->willPowerState, this);
4417 if (kIOPMAckImplied == ret) {
4418 acknowledgeSetPowerState();
4419 }
4420 return kIOReturnSuccess;
4421 }
4422 return kIOReturnNotReady;
4423 }
4424
4425 kern_return_t
ChangePowerState_Impl(uint32_t powerFlags)4426 IOService::ChangePowerState_Impl(
4427 uint32_t powerFlags)
4428 {
4429 switch (powerFlags) {
4430 case kIOServicePowerCapabilityOff:
4431 changePowerStateToPriv(0);
4432 break;
4433 case kIOServicePowerCapabilityLow:
4434 changePowerStateToPriv(1);
4435 break;
4436 case kIOServicePowerCapabilityOn:
4437 changePowerStateToPriv(2);
4438 break;
4439 default:
4440 return kIOReturnBadArgument;
4441 }
4442
4443 return kIOReturnSuccess;
4444 }
4445
4446 kern_return_t
_ClaimSystemWakeEvent_Impl(IOService * device,uint64_t flags,const char * reason,OSContainer * details)4447 IOService::_ClaimSystemWakeEvent_Impl(
4448 IOService * device,
4449 uint64_t flags,
4450 const char * reason,
4451 OSContainer * details)
4452 {
4453 IOPMrootDomain * rootDomain;
4454 IOOptionBits pmFlags;
4455
4456 rootDomain = getPMRootDomain();
4457 if (!rootDomain) {
4458 return kIOReturnNotReady;
4459 }
4460 if (os_convert_overflow(flags, &pmFlags)) {
4461 return kIOReturnBadArgument;
4462 }
4463 rootDomain->claimSystemWakeEvent(device, pmFlags, reason, details);
4464
4465 return kIOReturnSuccess;
4466 }
4467
4468 kern_return_t
Create_Impl(IOService * provider,const char * propertiesKey,IOService ** result)4469 IOService::Create_Impl(
4470 IOService * provider,
4471 const char * propertiesKey,
4472 IOService ** result)
4473 {
4474 OSObject * inst;
4475 IOService * service;
4476 OSString * str;
4477 const OSSymbol * sym;
4478 OSObject * prop;
4479 OSDictionary * properties;
4480 kern_return_t ret;
4481
4482 if (provider != this) {
4483 return kIOReturnUnsupported;
4484 }
4485
4486 ret = kIOReturnUnsupported;
4487 inst = NULL;
4488 service = NULL;
4489
4490 prop = copyProperty(propertiesKey);
4491 properties = OSDynamicCast(OSDictionary, prop);
4492 assert(properties);
4493 if (properties) {
4494 str = OSDynamicCast(OSString, properties->getObject(gIOClassKey));
4495 assert(str);
4496 sym = OSSymbol::withString(str);
4497 if (sym) {
4498 inst = OSMetaClass::allocClassWithName(sym);
4499 service = OSDynamicCast(IOService, inst);
4500 if (service && service->init(properties) && service->attach(this)) {
4501 reserved->uvars->userServer->serviceAttach(service, this);
4502 service->reserved->uvars->started = true;
4503 ret = kIOReturnSuccess;
4504 *result = service;
4505 }
4506 OSSafeReleaseNULL(sym);
4507 }
4508 }
4509
4510 OSSafeReleaseNULL(prop);
4511 if (kIOReturnSuccess != ret) {
4512 OSSafeReleaseNULL(inst);
4513 }
4514
4515 return ret;
4516 }
4517
4518 kern_return_t
Terminate_Impl(uint64_t options)4519 IOService::Terminate_Impl(
4520 uint64_t options)
4521 {
4522 IOUserServer * us;
4523
4524 if (options) {
4525 return kIOReturnUnsupported;
4526 }
4527
4528 us = (typeof(us))thread_iokit_tls_get(0);
4529 if (!reserved->uvars
4530 || (reserved->uvars->userServer != us)) {
4531 return kIOReturnNotPermitted;
4532 }
4533 terminate(kIOServiceTerminateNeedWillTerminate);
4534
4535 return kIOReturnSuccess;
4536 }
4537
4538 kern_return_t
NewUserClient_Impl(uint32_t type,IOUserClient ** userClient)4539 IOService::NewUserClient_Impl(
4540 uint32_t type,
4541 IOUserClient ** userClient)
4542 {
4543 return kIOReturnError;
4544 }
4545
4546 kern_return_t
_NewUserClient_Impl(uint32_t type,OSDictionary * entitlements,IOUserClient ** userClient)4547 IOService::_NewUserClient_Impl(
4548 uint32_t type,
4549 OSDictionary * entitlements,
4550 IOUserClient ** userClient)
4551 {
4552 return kIOReturnError;
4553 }
4554
4555 kern_return_t
SearchProperty_Impl(const char * name,const char * plane,uint64_t options,OSContainer ** property)4556 IOService::SearchProperty_Impl(
4557 const char * name,
4558 const char * plane,
4559 uint64_t options,
4560 OSContainer ** property)
4561 {
4562 OSObject * object __block;
4563 IOService * provider;
4564 IOOptionBits regOptions;
4565
4566 if (kIOServiceSearchPropertyParents & options) {
4567 regOptions = kIORegistryIterateParents | kIORegistryIterateRecursively;
4568 } else {
4569 regOptions = 0;
4570 }
4571
4572 object = copyProperty(name, IORegistryEntry::getPlane(plane), regOptions);
4573
4574 if (NULL == object) {
4575 for (provider = this; provider; provider = provider->getProvider()) {
4576 provider->runPropertyActionBlock(^IOReturn (void) {
4577 OSDictionary * userProps;
4578 object = provider->getProperty(name);
4579 if (!object
4580 && (userProps = OSDynamicCast(OSDictionary, provider->getProperty(gIOUserServicePropertiesKey)))) {
4581 object = userProps->getObject(name);
4582 }
4583 if (object) {
4584 object->retain();
4585 }
4586 return kIOReturnSuccess;
4587 });
4588 if (object || !(kIORegistryIterateParents & options)) {
4589 break;
4590 }
4591 }
4592 }
4593
4594 *property = object;
4595
4596 return object ? kIOReturnSuccess : kIOReturnNotFound;
4597 }
4598
4599 kern_return_t
StringFromReturn_Impl(IOReturn retval,OSString ** str)4600 IOService::StringFromReturn_Impl(
4601 IOReturn retval,
4602 OSString ** str)
4603 {
4604 OSString *obj = OSString::withCString(stringFromReturn(retval));
4605 *str = obj;
4606 return obj ? kIOReturnSuccess : kIOReturnError;
4607 }
4608
4609 kern_return_t
CopyProviderProperties_Impl(OSArray * propertyKeys,OSArray ** properties)4610 IOService::CopyProviderProperties_Impl(
4611 OSArray * propertyKeys,
4612 OSArray ** properties)
4613 {
4614 IOReturn ret;
4615 OSArray * result;
4616 IOService * provider;
4617
4618 result = OSArray::withCapacity(8);
4619 if (!result) {
4620 return kIOReturnNoMemory;
4621 }
4622
4623 ret = kIOReturnSuccess;
4624 for (provider = this; provider; provider = provider->getProvider()) {
4625 OSObject * obj;
4626 OSDictionary * props;
4627
4628 obj = provider->copyProperty(gIOSupportedPropertiesKey);
4629 props = OSDynamicCast(OSDictionary, obj);
4630 if (!props) {
4631 OSSafeReleaseNULL(obj);
4632 props = provider->dictionaryWithProperties();
4633 }
4634 if (!props) {
4635 ret = kIOReturnNoMemory;
4636 break;
4637 }
4638
4639 bool __block addClass = true;
4640 if (propertyKeys) {
4641 OSDictionary * retProps;
4642 retProps = OSDictionary::withCapacity(4);
4643 addClass = false;
4644 if (!retProps) {
4645 ret = kIOReturnNoMemory;
4646 OSSafeReleaseNULL(props);
4647 break;
4648 }
4649 propertyKeys->iterateObjects(^bool (OSObject * _key) {
4650 OSString * key = OSDynamicCast(OSString, _key);
4651 if (gIOClassKey->isEqualTo(key)) {
4652 addClass = true;
4653 return false;
4654 }
4655 retProps->setObject(key, props->getObject(key));
4656 return false;
4657 });
4658 OSSafeReleaseNULL(props);
4659 props = retProps;
4660 }
4661 if (addClass) {
4662 OSArray * classes = OSArray::withCapacity(8);
4663 if (!classes) {
4664 OSSafeReleaseNULL(props);
4665 ret = kIOReturnNoMemory;
4666 break;
4667 }
4668 for (const OSMetaClass * meta = provider->getMetaClass(); meta; meta = meta->getSuperClass()) {
4669 classes->setObject(meta->getClassNameSymbol());
4670 }
4671 props->setObject(gIOClassKey, classes);
4672 OSSafeReleaseNULL(classes);
4673 }
4674 bool ok = result->setObject(props);
4675 props->release();
4676 if (!ok) {
4677 ret = kIOReturnNoMemory;
4678 break;
4679 }
4680 }
4681 if (kIOReturnSuccess != ret) {
4682 OSSafeReleaseNULL(result);
4683 }
4684 *properties = result;
4685 return ret;
4686 }
4687
4688 IOReturn
AdjustBusy_Impl(int32_t delta)4689 IOService::AdjustBusy_Impl(int32_t delta)
4690 {
4691 adjustBusy(delta);
4692 return kIOReturnSuccess;
4693 }
4694
4695 IOReturn
GetBusyState_Impl(uint32_t * busyState)4696 IOService::GetBusyState_Impl(uint32_t *busyState)
4697 {
4698 *busyState = getBusyState();
4699 return kIOReturnSuccess;
4700 }
4701
4702 void
systemPower(bool powerOff)4703 IOUserServer::systemPower(bool powerOff)
4704 {
4705 OSArray * services;
4706 {
4707 OSDictionary * sleepDescription;
4708 OSObject * prop;
4709
4710 sleepDescription = OSDictionary::withCapacity(4);
4711 if (sleepDescription) {
4712 prop = getPMRootDomain()->copyProperty(kRootDomainSleepReasonKey);
4713 if (prop) {
4714 sleepDescription->setObject(gIOSystemStateSleepDescriptionReasonKey, prop);
4715 OSSafeReleaseNULL(prop);
4716 }
4717 prop = getPMRootDomain()->copyProperty(kIOHibernateStateKey);
4718 if (prop) {
4719 sleepDescription->setObject(gIOSystemStateSleepDescriptionHibernateStateKey, prop);
4720 OSSafeReleaseNULL(prop);
4721 }
4722 getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateSleepDescriptionKey, sleepDescription);
4723 OSSafeReleaseNULL(sleepDescription);
4724 }
4725 }
4726
4727 IOLockLock(fLock);
4728 services = OSArray::withArray(fServices);
4729
4730 bool allPowerStates __block = 0;
4731 // any service on?
4732 fServices->iterateObjects(^bool (OSObject * obj) {
4733 int service __unused; // hide outer defn
4734 IOService * nextService;
4735 nextService = (IOService *) obj;
4736 allPowerStates = nextService->reserved->uvars->powerState;
4737 // early terminate if true
4738 return allPowerStates;
4739 });
4740
4741 if (kIODKLogPM & gIODKDebug) {
4742 DKLOG("%s::powerOff(%d) %d\n", getName(), powerOff, allPowerStates);
4743 }
4744
4745 if (powerOff) {
4746 fSystemPowerAck = allPowerStates;
4747 if (!fSystemPowerAck) {
4748 fSystemOff = true;
4749 }
4750 IOLockUnlock(fLock);
4751
4752 if (!fSystemPowerAck) {
4753 IOServicePH::serverAck(this);
4754 } else {
4755 if (services) {
4756 services->iterateObjects(^bool (OSObject * obj) {
4757 int service __unused; // hide outer defn
4758 IOService * nextService;
4759 nextService = (IOService *) obj;
4760 if (kIODKLogPM & gIODKDebug) {
4761 DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(nextService), 0);
4762 }
4763 nextService->reserved->uvars->powerOverride = nextService->getPowerState();
4764 nextService->changePowerStateWithOverrideTo(0, 0);
4765 return false;
4766 });
4767 }
4768 }
4769 } else {
4770 fSystemOff = false;
4771 IOLockUnlock(fLock);
4772 if (services) {
4773 services->iterateObjects(^bool (OSObject * obj) {
4774 int service __unused; // hide outer defn
4775 IOService * nextService;
4776 nextService = (IOService *) obj;
4777 if (-1U != nextService->reserved->uvars->powerOverride) {
4778 if (kIODKLogPM & gIODKDebug) {
4779 DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(nextService), nextService->reserved->uvars->powerOverride);
4780 }
4781 nextService->changePowerStateWithOverrideTo(nextService->reserved->uvars->powerOverride, 0);
4782 nextService->reserved->uvars->powerOverride = -1U;
4783 }
4784 return false;
4785 });
4786 }
4787 }
4788 OSSafeReleaseNULL(services);
4789 }
4790
4791
4792 void
systemHalt(int howto)4793 IOUserServer::systemHalt(int howto)
4794 {
4795 OSArray * services;
4796
4797 if (true || (kIODKLogPM & gIODKDebug)) {
4798 DKLOG("%s::systemHalt()\n", getName());
4799 }
4800
4801 {
4802 OSDictionary * haltDescription;
4803 OSNumber * state;
4804 uint64_t haltStateFlags;
4805
4806 haltDescription = OSDictionary::withCapacity(4);
4807 if (haltDescription) {
4808 haltStateFlags = 0;
4809 if (RB_HALT & howto) {
4810 haltStateFlags |= kIOServiceHaltStatePowerOff;
4811 } else {
4812 haltStateFlags |= kIOServiceHaltStateRestart;
4813 }
4814 state = OSNumber::withNumber(haltStateFlags, 64);
4815 haltDescription->setObject(gIOSystemStateHaltDescriptionHaltStateKey, state);
4816 getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateHaltDescriptionKey, haltDescription);
4817
4818 OSSafeReleaseNULL(state);
4819 OSSafeReleaseNULL(haltDescription);
4820 }
4821 }
4822
4823 IOLockLock(fLock);
4824 services = OSArray::withArray(fServices);
4825 IOLockUnlock(fLock);
4826
4827 if (services) {
4828 services->iterateObjects(^bool (OSObject * obj) {
4829 int service __unused; // hide outer defn
4830 IOService * nextService;
4831 IOService * provider;
4832 IOOptionBits terminateOptions;
4833 bool root;
4834
4835 nextService = (IOService *) obj;
4836 provider = nextService->getProvider();
4837 if (!provider) {
4838 DKLOG("stale service " DKS " found, skipping termination\n", DKN(nextService));
4839 return false;
4840 }
4841 root = (NULL == provider->getProperty(gIOUserServerNameKey, gIOServicePlane));
4842 if (true || (kIODKLogPM & gIODKDebug)) {
4843 DKLOG("%d: terminate(" DKS ")\n", root, DKN(nextService));
4844 }
4845 if (!root) {
4846 return false;
4847 }
4848 terminateOptions = kIOServiceRequired | kIOServiceTerminateNeedWillTerminate;
4849 if (!nextService->terminate(terminateOptions)) {
4850 IOLog("failed to terminate service %s-0x%llx\n", nextService->getName(), nextService->getRegistryEntryID());
4851 }
4852 return false;
4853 });
4854 }
4855 OSSafeReleaseNULL(services);
4856 }
4857
4858 void
powerSourceChanged(bool acAttached)4859 IOUserServer::powerSourceChanged(bool acAttached)
4860 {
4861 OSDictionary * powerSourceDescription;
4862
4863 powerSourceDescription = OSDictionary::withCapacity(4);
4864 if (!powerSourceDescription) {
4865 return;
4866 }
4867 powerSourceDescription->setObject(gIOSystemStatePowerSourceDescriptionACAttachedKey, acAttached ? kOSBooleanTrue : kOSBooleanFalse);
4868 getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStatePowerSourceDescriptionKey, powerSourceDescription);
4869
4870 OSSafeReleaseNULL(powerSourceDescription);
4871 }
4872
4873 IOReturn
serviceStarted(IOService * service,IOService * provider,bool result)4874 IOUserServer::serviceStarted(IOService * service, IOService * provider, bool result)
4875 {
4876 IOReturn ret;
4877 IOService * pmProvider;
4878 bool joinTree;
4879
4880 DKLOG(DKS "::start(" DKS ") %s\n", DKN(service), DKN(provider), result ? "ok" : "fail");
4881
4882 if (!result) {
4883 ret = kIOReturnSuccess;
4884 return ret;
4885 }
4886
4887 if (!fRootNotifier) {
4888 ret = registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4889 assert(kIOReturnSuccess == ret);
4890 IOServicePH::serverAdd(this);
4891 fRootNotifier = true;
4892 }
4893
4894 joinTree = false;
4895 if (!(kIODKDisablePM & gIODKDebug) && !service->pm_vars) {
4896 service->PMinit();
4897 ret = service->registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4898 assert(kIOReturnSuccess == ret);
4899 joinTree = true;
4900 }
4901
4902 pmProvider = service;
4903 while (pmProvider && !pmProvider->inPlane(gIOPowerPlane)) {
4904 pmProvider = pmProvider->getProvider();
4905 }
4906 if (pmProvider) {
4907 IOService * entry;
4908 OSObject * prop;
4909 OSObject * nextProp;
4910 OSString * str;
4911
4912 entry = pmProvider;
4913 prop = NULL;
4914 do {
4915 nextProp = entry->copyProperty("non-removable");
4916 if (nextProp) {
4917 OSSafeReleaseNULL(prop);
4918 prop = nextProp;
4919 }
4920 entry = entry->getProvider();
4921 } while (entry);
4922 if (prop) {
4923 str = OSDynamicCast(OSString, prop);
4924 if (str && str->isEqualTo("yes")) {
4925 pmProvider = NULL;
4926 }
4927 prop->release();
4928 }
4929 }
4930
4931 if (!(kIODKDisablePM & gIODKDebug) && pmProvider) {
4932 IOLockLock(fLock);
4933 service->reserved->uvars->powerState = true;
4934 IOLockUnlock(fLock);
4935
4936 if (joinTree) {
4937 pmProvider->joinPMtree(service);
4938 service->reserved->uvars->userServerPM = true;
4939 }
4940 }
4941
4942 service->registerInterestedDriver(this);
4943 service->reserved->uvars->started = true;
4944
4945 return kIOReturnSuccess;
4946 }
4947
4948
4949 IOReturn
serviceOpen(IOService * provider,IOService * client)4950 IOUserServer::serviceOpen(IOService * provider, IOService * client)
4951 {
4952 OSObjectUserVars * uvars;
4953
4954 IOLockLock(client->reserved->uvars->uvarsLock);
4955 uvars = client->reserved->uvars;
4956 if (!uvars->openProviders) {
4957 uvars->openProviders = OSArray::withObjects((const OSObject **) &provider, 1);
4958 } else if (-1U == uvars->openProviders->getNextIndexOfObject(provider, 0)) {
4959 uvars->openProviders->setObject(provider);
4960 }
4961 IOLockUnlock(client->reserved->uvars->uvarsLock);
4962
4963 return kIOReturnSuccess;
4964 }
4965
4966 IOReturn
serviceClose(IOService * provider,IOService * client)4967 IOUserServer::serviceClose(IOService * provider, IOService * client)
4968 {
4969 OSObjectUserVars * uvars;
4970 unsigned int idx;
4971 IOReturn ret;
4972
4973 IOLockLock(client->reserved->uvars->uvarsLock);
4974 uvars = client->reserved->uvars;
4975 if (!uvars->openProviders) {
4976 ret = kIOReturnNotOpen;
4977 goto finish;
4978 }
4979 idx = uvars->openProviders->getNextIndexOfObject(provider, 0);
4980 if (-1U == idx) {
4981 ret = kIOReturnNotOpen;
4982 goto finish;
4983 }
4984 uvars->openProviders->removeObject(idx);
4985 if (!uvars->openProviders->getCount()) {
4986 OSSafeReleaseNULL(uvars->openProviders);
4987 }
4988
4989 ret = kIOReturnSuccess;
4990
4991 finish:
4992 IOLockUnlock(client->reserved->uvars->uvarsLock);
4993
4994 return ret;
4995 }
4996
4997
4998 IOReturn
serviceStop(IOService * service,IOService *)4999 IOUserServer::serviceStop(IOService * service, IOService *)
5000 {
5001 IOReturn ret;
5002 uint32_t idx, queueAlloc;
5003 bool pmAck;
5004 OSObjectUserVars * uvars;
5005
5006 pmAck = false;
5007 IOLockLock(fLock);
5008 idx = fServices->getNextIndexOfObject(service, 0);
5009 if (-1U != idx) {
5010 fServices->removeObject(idx);
5011
5012 // Remove the service from IOAssociatedServices
5013 OSObject * serviceArrayObj = copyProperty(gIOAssociatedServicesKey);
5014 OSArray * serviceArray = OSDynamicCast(OSArray, serviceArrayObj);
5015 assert(serviceArray != NULL);
5016
5017 serviceArray = OSDynamicCast(OSArray, serviceArray->copyCollection());
5018 assert(serviceArray != NULL);
5019
5020 // Index should be the same as it was in fServices
5021 OSNumber * __assert_only registryEntryID = OSDynamicCast(OSNumber, serviceArray->getObject(idx));
5022 assert(registryEntryID);
5023
5024 // ensure it is the right service
5025 assert(registryEntryID->unsigned64BitValue() == service->getRegistryEntryID());
5026 serviceArray->removeObject(idx);
5027
5028 setProperty(gIOAssociatedServicesKey, serviceArray);
5029 OSSafeReleaseNULL(serviceArray);
5030 OSSafeReleaseNULL(serviceArrayObj);
5031
5032 uvars = service->reserved->uvars;
5033 uvars->stopped = true;
5034 uvars->powerState = 0;
5035
5036 bool allPowerStates __block = 0;
5037 // any service on?
5038 fServices->iterateObjects(^bool (OSObject * obj) {
5039 int service __unused; // hide outer defn
5040 IOService * nextService;
5041 nextService = (IOService *) obj;
5042 allPowerStates = nextService->reserved->uvars->powerState;
5043 // early terminate if true
5044 return allPowerStates;
5045 });
5046
5047 if (!allPowerStates && (pmAck = fSystemPowerAck)) {
5048 fSystemPowerAck = false;
5049 fSystemOff = true;
5050 }
5051 }
5052 IOLockUnlock(fLock);
5053 if (pmAck) {
5054 IOServicePH::serverAck(this);
5055 }
5056
5057 if (-1U == idx) {
5058 return kIOReturnSuccess;
5059 }
5060
5061 if (uvars->queueArray && uvars->userMeta) {
5062 queueAlloc = 1;
5063 if (uvars->userMeta->queueNames) {
5064 queueAlloc += uvars->userMeta->queueNames->count;
5065 }
5066 for (idx = 0; idx < queueAlloc; idx++) {
5067 OSSafeReleaseNULL(uvars->queueArray[idx]);
5068 }
5069 IOSafeDeleteNULL(uvars->queueArray, IODispatchQueue *, queueAlloc);
5070 }
5071
5072 (void) service->deRegisterInterestedDriver(this);
5073 if (uvars->userServerPM) {
5074 service->PMstop();
5075 }
5076
5077 ret = kIOReturnSuccess;
5078 return ret;
5079 }
5080
5081 void
serviceFree(IOService * service)5082 IOUserServer::serviceFree(IOService * service)
5083 {
5084 OSObjectUserVars * uvars;
5085
5086 uvars = service->reserved->uvars;
5087 if (!uvars) {
5088 return;
5089 }
5090 OSSafeReleaseNULL(uvars->userServer);
5091 IOLockFree(uvars->uvarsLock);
5092 IOFreeType(service->reserved->uvars, OSObjectUserVars);
5093 }
5094
5095 void
serviceWillTerminate(IOService * client,IOService * provider,IOOptionBits options)5096 IOUserServer::serviceWillTerminate(IOService * client, IOService * provider, IOOptionBits options)
5097 {
5098 IOReturn ret;
5099 bool willTerminate;
5100
5101 willTerminate = false;
5102 IOLockLock(client->reserved->uvars->uvarsLock);
5103 if (!client->reserved->uvars->serverDied
5104 && !client->reserved->uvars->willTerminate) {
5105 client->reserved->uvars->willTerminate = true;
5106 willTerminate = true;
5107 }
5108 IOLockUnlock(client->reserved->uvars->uvarsLock);
5109
5110 if (willTerminate) {
5111 if (provider->isInactive() || IOServicePH::serverSlept()) {
5112 client->Stop_async(provider);
5113 ret = kIOReturnOffline;
5114 } else {
5115 ret = client->Stop(provider);
5116 }
5117 if (kIOReturnSuccess != ret) {
5118 IOUserServer::serviceDidStop(client, provider);
5119 ret = kIOReturnSuccess;
5120 }
5121 }
5122 }
5123
5124 void
serviceDidTerminate(IOService * client,IOService * provider,IOOptionBits options,bool * defer)5125 IOUserServer::serviceDidTerminate(IOService * client, IOService * provider, IOOptionBits options, bool * defer)
5126 {
5127 IOLockLock(client->reserved->uvars->uvarsLock);
5128 client->reserved->uvars->didTerminate = true;
5129 if (!client->reserved->uvars->serverDied
5130 && !client->reserved->uvars->stopped) {
5131 *defer = true;
5132 }
5133 IOLockUnlock(client->reserved->uvars->uvarsLock);
5134 }
5135
5136 void
serviceDidStop(IOService * client,IOService * provider)5137 IOUserServer::serviceDidStop(IOService * client, IOService * provider)
5138 {
5139 bool complete;
5140 OSArray * closeArray;
5141
5142 complete = false;
5143 closeArray = NULL;
5144
5145 IOLockLock(client->reserved->uvars->uvarsLock);
5146 if (client->reserved->uvars
5147 && client->reserved->uvars->willTerminate
5148 && !client->reserved->uvars->stopped) {
5149 client->reserved->uvars->stopped = true;
5150 complete = client->reserved->uvars->didTerminate;
5151 }
5152
5153 if (client->reserved->uvars) {
5154 closeArray = client->reserved->uvars->openProviders;
5155 client->reserved->uvars->openProviders = NULL;
5156 }
5157 IOLockUnlock(client->reserved->uvars->uvarsLock);
5158
5159 if (closeArray) {
5160 closeArray->iterateObjects(^bool (OSObject * obj) {
5161 IOService * toClose;
5162 toClose = OSDynamicCast(IOService, obj);
5163 if (toClose) {
5164 DKLOG(DKS ":force close (" DKS ")\n", DKN(client), DKN(toClose));
5165 toClose->close(client);
5166 }
5167 return false;
5168 });
5169 closeArray->release();
5170 }
5171
5172 if (complete) {
5173 bool defer = false;
5174 client->didTerminate(provider, 0, &defer);
5175 }
5176 }
5177
5178 kern_return_t
ClientCrashed_Impl(IOService * client,uint64_t options)5179 IOService::ClientCrashed_Impl(
5180 IOService * client,
5181 uint64_t options)
5182 {
5183 return kIOReturnUnsupported;
5184 }
5185
5186 kern_return_t
Stop_Impl(IOService * provider)5187 IOService::Stop_Impl(
5188 IOService * provider)
5189 {
5190 IOUserServer::serviceDidStop(this, provider);
5191
5192 return kIOReturnSuccess;
5193 }
5194
5195 void
Stop_async_Impl(IOService * provider)5196 IOService::Stop_async_Impl(
5197 IOService * provider)
5198 {
5199 }
5200
5201 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5202
5203 #undef super
5204 #define super IOUserClient
5205
OSDefineMetaClassAndStructors(IOUserUserClient,IOUserClient)5206 OSDefineMetaClassAndStructors(IOUserUserClient, IOUserClient)
5207
5208 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5209
5210 bool
5211 IOUserUserClient::init(OSDictionary * properties)
5212 {
5213 if (!super::init(properties)) {
5214 return false;
5215 }
5216
5217 fWorkGroups = OSDictionary::withCapacity(0);
5218 if (fWorkGroups == NULL) {
5219 return false;
5220 }
5221
5222 fEventLinks = OSDictionary::withCapacity(0);
5223 if (fEventLinks == NULL) {
5224 return false;
5225 }
5226
5227 fLock = IOLockAlloc();
5228
5229 return true;
5230 }
5231
5232 void
free()5233 IOUserUserClient::free()
5234 {
5235 OSSafeReleaseNULL(fWorkGroups);
5236 OSSafeReleaseNULL(fEventLinks);
5237 if (fLock) {
5238 IOLockFree(fLock);
5239 }
5240
5241 super::free();
5242 }
5243
5244 IOReturn
setTask(task_t task)5245 IOUserUserClient::setTask(task_t task)
5246 {
5247 task_reference(task);
5248 fTask = task;
5249
5250 return kIOReturnSuccess;
5251 }
5252
5253 void
stop(IOService * provider)5254 IOUserUserClient::stop(IOService * provider)
5255 {
5256 if (fTask) {
5257 task_deallocate(fTask);
5258 fTask = NULL;
5259 }
5260 super::stop(provider);
5261 }
5262
5263 IOReturn
clientClose(void)5264 IOUserUserClient::clientClose(void)
5265 {
5266 terminate(kIOServiceTerminateNeedWillTerminate);
5267 return kIOReturnSuccess;
5268 }
5269
5270 IOReturn
setProperties(OSObject * properties)5271 IOUserUserClient::setProperties(OSObject * properties)
5272 {
5273 IOReturn ret = kIOReturnUnsupported;
5274 return ret;
5275 }
5276
5277 // p1 - name of object
5278 // p2 - length of object name
5279 // p3 - mach port name
5280
5281 kern_return_t
eventlinkConfigurationTrap(void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)5282 IOUserUserClient::eventlinkConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
5283 {
5284 user_addr_t userObjectName = (user_addr_t)p1;
5285 mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
5286 mach_port_t port = MACH_PORT_NULL;
5287 ipc_kobject_type_t portType;
5288 char eventlinkName[kIOEventLinkMaxNameLength + 1] = {0};
5289 size_t eventLinkNameLen;
5290 OSString * eventlinkNameStr = NULL; // must release
5291 IOEventLink * eventLink = NULL; // do not release
5292 kern_return_t ret;
5293
5294 ret = copyinstr(userObjectName, &eventlinkName[0], sizeof(eventlinkName), &eventLinkNameLen);
5295 if (ret != kIOReturnSuccess) {
5296 goto finish;
5297 }
5298
5299 // ensure string length matches trap argument
5300 if (eventLinkNameLen != (size_t)p2 + 1) {
5301 ret = kIOReturnBadArgument;
5302 goto finish;
5303 }
5304
5305 eventlinkNameStr = OSString::withCStringNoCopy(eventlinkName);
5306 if (eventlinkNameStr == NULL) {
5307 ret = kIOReturnNoMemory;
5308 goto finish;
5309 }
5310
5311 IOLockLock(fLock);
5312 eventLink = OSDynamicCast(IOEventLink, fEventLinks->getObject(eventlinkNameStr));
5313 IOLockUnlock(fLock);
5314
5315 if (eventLink == NULL) {
5316 ret = kIOReturnNotFound;
5317 goto finish;
5318 }
5319
5320 port = iokit_lookup_raw_current_task(portName, &portType);
5321
5322 if (port == NULL) {
5323 ret = kIOReturnNotFound;
5324 goto finish;
5325 }
5326
5327 if (portType != IKOT_EVENTLINK) {
5328 ret = kIOReturnBadArgument;
5329 goto finish;
5330 }
5331
5332 ret = eventLink->SetEventlinkPort(port);
5333 if (ret != kIOReturnSuccess) {
5334 if (kIODKLogSetup & gIODKDebug) {
5335 DKLOG(DKS " %s SetEventlinkPort() returned %x\n", DKN(this), eventlinkNameStr->getCStringNoCopy(), ret);
5336 }
5337 goto finish;
5338 }
5339
5340 finish:
5341 if (port != NULL) {
5342 iokit_release_port_send(port);
5343 }
5344
5345 OSSafeReleaseNULL(eventlinkNameStr);
5346
5347 return ret;
5348 }
5349
5350 kern_return_t
workgroupConfigurationTrap(void * p1,void * p2,void * p3,void * p4,void * p5,void * p6)5351 IOUserUserClient::workgroupConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
5352 {
5353 user_addr_t userObjectName = (user_addr_t)p1;
5354 mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
5355 mach_port_t port = MACH_PORT_NULL;
5356 ipc_kobject_type_t portType;
5357 char workgroupName[kIOWorkGroupMaxNameLength + 1] = {0};
5358 size_t workgroupNameLen;
5359 OSString * workgroupNameStr = NULL; // must release
5360 IOWorkGroup * workgroup = NULL; // do not release
5361 kern_return_t ret;
5362
5363 ret = copyinstr(userObjectName, &workgroupName[0], sizeof(workgroupName), &workgroupNameLen);
5364 if (ret != kIOReturnSuccess) {
5365 goto finish;
5366 }
5367
5368 // ensure string length matches trap argument
5369 if (workgroupNameLen != (size_t)p2 + 1) {
5370 ret = kIOReturnBadArgument;
5371 goto finish;
5372 }
5373
5374 workgroupNameStr = OSString::withCStringNoCopy(workgroupName);
5375 if (workgroupNameStr == NULL) {
5376 ret = kIOReturnNoMemory;
5377 goto finish;
5378 }
5379
5380 IOLockLock(fLock);
5381 workgroup = OSDynamicCast(IOWorkGroup, fWorkGroups->getObject(workgroupNameStr));
5382 IOLockUnlock(fLock);
5383
5384 if (workgroup == NULL) {
5385 ret = kIOReturnNotFound;
5386 goto finish;
5387 }
5388
5389 port = iokit_lookup_raw_current_task(portName, &portType);
5390
5391 if (port == NULL) {
5392 ret = kIOReturnNotFound;
5393 goto finish;
5394 }
5395
5396 if (portType != IKOT_WORK_INTERVAL) {
5397 ret = kIOReturnBadArgument;
5398 goto finish;
5399 }
5400
5401 ret = workgroup->SetWorkGroupPort(port);
5402 if (ret != kIOReturnSuccess) {
5403 if (kIODKLogSetup & gIODKDebug) {
5404 DKLOG(DKS " %s SetWorkGroupPort() returned %x\n", DKN(this), workgroupNameStr->getCStringNoCopy(), ret);
5405 }
5406 goto finish;
5407 }
5408
5409 finish:
5410
5411 if (port != NULL) {
5412 iokit_release_port_send(port);
5413 }
5414
5415 OSSafeReleaseNULL(workgroupNameStr);
5416
5417 return ret;
5418 }
5419
5420 IOExternalTrap *
getTargetAndTrapForIndex(IOService ** targetP,UInt32 index)5421 IOUserUserClient::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
5422 {
5423 static const IOExternalTrap trapTemplate[] = {
5424 { NULL, (IOTrap) & IOUserUserClient::eventlinkConfigurationTrap},
5425 { NULL, (IOTrap) & IOUserUserClient::workgroupConfigurationTrap},
5426 };
5427 if (index >= (sizeof(trapTemplate) / sizeof(IOExternalTrap))) {
5428 return NULL;
5429 }
5430 *targetP = this;
5431 return (IOExternalTrap *)&trapTemplate[index];
5432 }
5433
5434 kern_return_t
CopyClientEntitlements_Impl(OSDictionary ** entitlements)5435 IOUserClient::CopyClientEntitlements_Impl(OSDictionary ** entitlements)
5436 {
5437 return kIOReturnUnsupported;
5438 };
5439
5440 struct IOUserUserClientActionRef {
5441 OSAsyncReference64 asyncRef;
5442 };
5443
5444 void
KernelCompletion_Impl(OSAction * action,IOReturn status,const unsigned long long * asyncData,uint32_t asyncDataCount)5445 IOUserClient::KernelCompletion_Impl(
5446 OSAction * action,
5447 IOReturn status,
5448 const unsigned long long * asyncData,
5449 uint32_t asyncDataCount)
5450 {
5451 IOUserUserClientActionRef * ref;
5452
5453 ref = (typeof(ref))action->GetReference();
5454
5455 IOUserClient::sendAsyncResult64(ref->asyncRef, status, (io_user_reference_t *) asyncData, asyncDataCount);
5456 }
5457
5458 kern_return_t
_ExternalMethod_Impl(uint64_t selector,const unsigned long long * scalarInput,uint32_t scalarInputCount,OSData * structureInput,IOMemoryDescriptor * structureInputDescriptor,unsigned long long * scalarOutput,uint32_t * scalarOutputCount,uint64_t structureOutputMaximumSize,OSData ** structureOutput,IOMemoryDescriptor * structureOutputDescriptor,OSAction * completion)5459 IOUserClient::_ExternalMethod_Impl(
5460 uint64_t selector,
5461 const unsigned long long * scalarInput,
5462 uint32_t scalarInputCount,
5463 OSData * structureInput,
5464 IOMemoryDescriptor * structureInputDescriptor,
5465 unsigned long long * scalarOutput,
5466 uint32_t * scalarOutputCount,
5467 uint64_t structureOutputMaximumSize,
5468 OSData ** structureOutput,
5469 IOMemoryDescriptor * structureOutputDescriptor,
5470 OSAction * completion)
5471 {
5472 return kIOReturnUnsupported;
5473 }
5474
5475 IOReturn
clientMemoryForType(UInt32 type,IOOptionBits * koptions,IOMemoryDescriptor ** kmemory)5476 IOUserUserClient::clientMemoryForType(UInt32 type,
5477 IOOptionBits * koptions,
5478 IOMemoryDescriptor ** kmemory)
5479 {
5480 IOReturn kr;
5481 uint64_t options;
5482 IOMemoryDescriptor * memory;
5483
5484 kr = CopyClientMemoryForType(type, &options, &memory);
5485
5486 *koptions = 0;
5487 *kmemory = NULL;
5488 if (kIOReturnSuccess != kr) {
5489 return kr;
5490 }
5491
5492 if (kIOUserClientMemoryReadOnly & options) {
5493 *koptions |= kIOMapReadOnly;
5494 }
5495 *kmemory = memory;
5496
5497 return kr;
5498 }
5499
5500 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)5501 IOUserUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
5502 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
5503 {
5504 IOReturn kr;
5505 OSData * structureInput;
5506 OSData * structureOutput;
5507 size_t copylen;
5508 uint64_t structureOutputSize;
5509 OSAction * action;
5510 IOUserUserClientActionRef * ref;
5511 mach_port_t wake_port = MACH_PORT_NULL;
5512
5513 kr = kIOReturnUnsupported;
5514 structureInput = NULL;
5515 action = NULL;
5516 ref = NULL;
5517
5518 if (args->structureInputSize) {
5519 structureInput = OSData::withBytesNoCopy((void *) args->structureInput, args->structureInputSize);
5520 }
5521
5522 if (MACH_PORT_NULL != args->asyncWakePort) {
5523 // this retain is for the OSAction to release
5524 wake_port = ipc_port_make_send(args->asyncWakePort);
5525 kr = CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef), &action);
5526 assert(KERN_SUCCESS == kr);
5527 ref = (typeof(ref))action->GetReference();
5528 bcopy(args->asyncReference, &ref->asyncRef[0], args->asyncReferenceCount * sizeof(ref->asyncRef[0]));
5529 kr = action->SetAbortedHandler(^(void) {
5530 IOUserUserClientActionRef * ref;
5531 IOReturn ret;
5532
5533 ref = (typeof(ref))action->GetReference();
5534 ret = releaseAsyncReference64(ref->asyncRef);
5535 assert(kIOReturnSuccess == ret);
5536 bzero(&ref->asyncRef[0], sizeof(ref->asyncRef));
5537 });
5538 assert(KERN_SUCCESS == kr);
5539 }
5540
5541 if (args->structureVariableOutputData) {
5542 structureOutputSize = kIOUserClientVariableStructureSize;
5543 } else if (args->structureOutputDescriptor) {
5544 structureOutputSize = args->structureOutputDescriptor->getLength();
5545 } else {
5546 structureOutputSize = args->structureOutputSize;
5547 }
5548
5549 kr = _ExternalMethod(selector, &args->scalarInput[0], args->scalarInputCount,
5550 structureInput, args->structureInputDescriptor,
5551 args->scalarOutput, &args->scalarOutputCount,
5552 structureOutputSize, &structureOutput, args->structureOutputDescriptor,
5553 action);
5554
5555 OSSafeReleaseNULL(structureInput);
5556 OSSafeReleaseNULL(action);
5557
5558 if (kIOReturnSuccess != kr) {
5559 // mig will destroy any async port
5560 return kr;
5561 }
5562 if (MACH_PORT_NULL != wake_port) {
5563 // this release is for the mig created send right
5564 iokit_release_port_send(wake_port);
5565 }
5566
5567 if (structureOutput) {
5568 if (args->structureVariableOutputData) {
5569 *args->structureVariableOutputData = structureOutput;
5570 } else {
5571 copylen = structureOutput->getLength();
5572 if (copylen > args->structureOutputSize) {
5573 kr = kIOReturnBadArgument;
5574 } else {
5575 bcopy((const void *) structureOutput->getBytesNoCopy(), args->structureOutput, copylen);
5576 args->structureOutputSize = (uint32_t) copylen;
5577 }
5578 OSSafeReleaseNULL(structureOutput);
5579 }
5580 }
5581
5582 return kr;
5583 }
5584
5585 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5586
5587 extern IORecursiveLock * gDriverKitLaunchLock;
5588 extern OSSet * gDriverKitLaunches;
5589
5590 _IOUserServerCheckInCancellationHandler *
setCancellationHandler(IOUserServerCheckInCancellationHandler handler,void * handlerArgs)5591 IOUserServerCheckInToken::setCancellationHandler(IOUserServerCheckInCancellationHandler handler,
5592 void* handlerArgs)
5593 {
5594 _IOUserServerCheckInCancellationHandler * handlerObj = _IOUserServerCheckInCancellationHandler::withHandler(handler, handlerArgs);
5595 if (!handlerObj) {
5596 goto finish;
5597 }
5598
5599 IORecursiveLockLock(gDriverKitLaunchLock);
5600
5601 assert(fState != kIOUserServerCheckInComplete);
5602
5603 if (fState == kIOUserServerCheckInCanceled) {
5604 // Send cancel notification if we set the handler after this was canceled
5605 handlerObj->call(this);
5606 } else if (fState == kIOUserServerCheckInPending) {
5607 fHandlers->setObject(handlerObj);
5608 }
5609
5610 IORecursiveLockUnlock(gDriverKitLaunchLock);
5611
5612 finish:
5613 return handlerObj;
5614 }
5615
5616 void
removeCancellationHandler(_IOUserServerCheckInCancellationHandler * handler)5617 IOUserServerCheckInToken::removeCancellationHandler(_IOUserServerCheckInCancellationHandler * handler)
5618 {
5619 IORecursiveLockLock(gDriverKitLaunchLock);
5620
5621 fHandlers->removeObject(handler);
5622
5623 IORecursiveLockUnlock(gDriverKitLaunchLock);
5624 }
5625
5626 void
cancel()5627 IOUserServerCheckInToken::cancel()
5628 {
5629 IORecursiveLockLock(gDriverKitLaunchLock);
5630
5631 if (fState == kIOUserServerCheckInPending) {
5632 fState = kIOUserServerCheckInCanceled;
5633 if (gDriverKitLaunches != NULL) {
5634 // Remove pending launch from list, if we have not shut down yet.
5635 gDriverKitLaunches->removeObject(this);
5636 }
5637
5638 fHandlers->iterateObjects(^bool (OSObject * obj){
5639 _IOUserServerCheckInCancellationHandler * handlerObj = OSDynamicCast(_IOUserServerCheckInCancellationHandler, obj);
5640 if (handlerObj) {
5641 handlerObj->call(this);
5642 }
5643 return false;
5644 });
5645 fHandlers->flushCollection();
5646 }
5647
5648 IORecursiveLockUnlock(gDriverKitLaunchLock);
5649 }
5650
5651 void
complete()5652 IOUserServerCheckInToken::complete()
5653 {
5654 IORecursiveLockLock(gDriverKitLaunchLock);
5655
5656 if (fState == kIOUserServerCheckInPending && --fPendingCount == 0) {
5657 fState = kIOUserServerCheckInComplete;
5658 if (gDriverKitLaunches != NULL) {
5659 // Remove pending launch from list, if we have not shut down yet.
5660 gDriverKitLaunches->removeObject(this);
5661 }
5662
5663 // No need to hold on to the cancellation handlers
5664 fHandlers->flushCollection();
5665 }
5666
5667 IORecursiveLockUnlock(gDriverKitLaunchLock);
5668 }
5669
5670 bool
init(const OSSymbol * serverName,OSNumber * serverTag)5671 IOUserServerCheckInToken::init(const OSSymbol * serverName, OSNumber * serverTag)
5672 {
5673 if (!OSObject::init()) {
5674 return false;
5675 }
5676
5677 if (!serverName) {
5678 return false;
5679 }
5680 fServerName = serverName;
5681 fServerName->retain();
5682
5683 if (!serverTag) {
5684 return false;
5685 }
5686 fServerTag = serverTag;
5687 fServerTag->retain();
5688
5689 fHandlers = OSSet::withCapacity(0);
5690 if (!fHandlers) {
5691 return false;
5692 }
5693
5694 fState = kIOUserServerCheckInPending;
5695 fPendingCount = 1;
5696
5697 return true;
5698 }
5699
5700 void
free()5701 IOUserServerCheckInToken::free()
5702 {
5703 OSSafeReleaseNULL(fServerName);
5704 OSSafeReleaseNULL(fServerTag);
5705 OSSafeReleaseNULL(fHandlers);
5706
5707 OSObject::free();
5708 }
5709
5710 const OSSymbol *
copyServerName() const5711 IOUserServerCheckInToken::copyServerName() const
5712 {
5713 fServerName->retain();
5714 return fServerName;
5715 }
5716
5717 OSNumber *
copyServerTag() const5718 IOUserServerCheckInToken::copyServerTag() const
5719 {
5720 fServerTag->retain();
5721 return fServerTag;
5722 }
5723
5724 IOUserServer *
launchUserServer(OSString * bundleID,const OSSymbol * serverName,OSNumber * serverTag,bool reuseIfExists,IOUserServerCheckInToken ** resultToken)5725 IOUserServer::launchUserServer(OSString * bundleID, const OSSymbol * serverName, OSNumber * serverTag, bool reuseIfExists, IOUserServerCheckInToken ** resultToken)
5726 {
5727 IOUserServer *me = NULL;
5728 IOUserServerCheckInToken * token = NULL;
5729 OSDictionary * matching = NULL; // must release
5730
5731 IORecursiveLockLock(gDriverKitLaunchLock);
5732
5733 if (gDriverKitLaunches == NULL) {
5734 // About to shut down, don't launch anything
5735 goto finish;
5736 }
5737
5738 if (reuseIfExists) {
5739 const char * serverNameCStr;
5740 const char * bundleIDCStr;
5741 const char * endOrgCStr;
5742
5743 serverNameCStr = serverName->getCStringNoCopy();
5744 bundleIDCStr = bundleID->getCStringNoCopy();
5745 (endOrgCStr = strchr(bundleIDCStr, '.')) && (endOrgCStr = strchr(endOrgCStr + 1, '.'));
5746 reuseIfExists = endOrgCStr && (0 == strncmp(bundleIDCStr, serverNameCStr, endOrgCStr + 1 - bundleIDCStr));
5747 if (!reuseIfExists) {
5748 IOLog(kIOUserServerNameKey " \"%s\" not correct organization for bundleID \"%s\"\n", serverNameCStr, bundleIDCStr);
5749 }
5750 }
5751
5752 // Find existing server
5753 if (reuseIfExists) {
5754 token = IOUserServerCheckInToken::findExistingToken(serverName);
5755 if (token) {
5756 // Launch in progress, return token
5757 goto finish;
5758 } else {
5759 // Check if launch completed
5760 matching = IOService::serviceMatching(gIOUserServerClassKey);
5761 if (!matching) {
5762 goto finish;
5763 }
5764 IOService::propertyMatching(gIOUserServerNameKey, serverName, matching);
5765 IOService * service = IOService::copyMatchingService(matching);
5766 IOUserServer * userServer = OSDynamicCast(IOUserServer, service);
5767 if (userServer) {
5768 // found existing user server
5769 me = userServer;
5770 goto finish;
5771 } else {
5772 OSSafeReleaseNULL(service);
5773 }
5774 }
5775 }
5776
5777 // No existing server, request launch
5778 token = new IOUserServerCheckInToken;
5779 if (!token) {
5780 goto finish;
5781 }
5782 if (token && !token->init(serverName, serverTag)) {
5783 OSSafeReleaseNULL(token);
5784 goto finish;
5785 }
5786
5787 gDriverKitLaunches->setObject(token);
5788 OSKext::requestDaemonLaunch(bundleID, (OSString *)serverName, serverTag, token);
5789
5790 finish:
5791 IORecursiveLockUnlock(gDriverKitLaunchLock);
5792 OSSafeReleaseNULL(matching);
5793
5794 if (resultToken) {
5795 *resultToken = token;
5796 } else {
5797 OSSafeReleaseNULL(token);
5798 }
5799
5800 return me;
5801 }
5802
5803 /*
5804 * IOUserServerCheckInTokens are used to track dext launches. They have three possible states:
5805 *
5806 * - Pending: A dext launch is pending
5807 * - Canceled: Dext launch failed
5808 * - Complete: Dext launch is complete
5809 *
5810 * A token can be shared among multiple IOServices that are waiting for dexts if the IOUserServerName
5811 * is the same. This allows dexts to be reused and host multiple services. All pending tokens are stored
5812 * in gDriverKitLaunches and we check here before creating a new token when launching a dext.
5813 *
5814 * A token starts in the pending state with a pending count of 1. When we reuse a token, we increase the
5815 * pending count of the token.
5816 *
5817 * The token is sent to userspace as a mach port through kernelmanagerd/driverkitd to the dext. The dext then
5818 * uses that token to check in to the kernel. If any part of the dext launch failed (dext crashed, kmd crashed, etc.)
5819 * we get a no-senders notification for the token in the kernel and the token goes into the Canceled state.
5820 *
5821 * Once the dext checks in to the kernel, we decrement the pending count for the token. When the pending count reaches
5822 * 0, the token goes into the Complete state. So if the token is in the Complete state, there are no kernel matching threads
5823 * waiting on the dext to check in.
5824 */
5825
5826 IOUserServerCheckInToken *
findExistingToken(const OSSymbol * serverName)5827 IOUserServerCheckInToken::findExistingToken(const OSSymbol * serverName)
5828 {
5829 IOUserServerCheckInToken * __block result = NULL;
5830
5831 IORecursiveLockLock(gDriverKitLaunchLock);
5832 if (gDriverKitLaunches == NULL) {
5833 goto finish;
5834 }
5835
5836 gDriverKitLaunches->iterateObjects(^(OSObject * obj) {
5837 IOUserServerCheckInToken * token = OSDynamicCast(IOUserServerCheckInToken, obj);
5838 if (token) {
5839 // Check if server name matches
5840 const OSSymbol * tokenServerName = token->fServerName;
5841 if (tokenServerName->isEqualTo(serverName)) {
5842 assert(token->fState == kIOUserServerCheckInPending);
5843 token->fPendingCount++;
5844 result = token;
5845 result->retain();
5846 }
5847 }
5848 return result != NULL;
5849 });
5850
5851 finish:
5852 IORecursiveLockUnlock(gDriverKitLaunchLock);
5853 return result;
5854 }
5855
5856 void
cancelAll()5857 IOUserServerCheckInToken::cancelAll()
5858 {
5859 OSSet * tokensToCancel;
5860
5861 IORecursiveLockLock(gDriverKitLaunchLock);
5862 tokensToCancel = gDriverKitLaunches;
5863 gDriverKitLaunches = NULL;
5864
5865
5866 tokensToCancel->iterateObjects(^(OSObject *obj) {
5867 IOUserServerCheckInToken * token = OSDynamicCast(IOUserServerCheckInToken, obj);
5868 if (token) {
5869 token->cancel();
5870 }
5871 return false;
5872 });
5873
5874 IORecursiveLockUnlock(gDriverKitLaunchLock);
5875
5876 OSSafeReleaseNULL(tokensToCancel);
5877 }
5878
5879 void
call(IOUserServerCheckInToken * token)5880 _IOUserServerCheckInCancellationHandler::call(IOUserServerCheckInToken * token)
5881 {
5882 fHandler(token, fHandlerArgs);
5883 }
5884
5885 _IOUserServerCheckInCancellationHandler *
withHandler(IOUserServerCheckInCancellationHandler handler,void * args)5886 _IOUserServerCheckInCancellationHandler::withHandler(IOUserServerCheckInCancellationHandler handler, void * args)
5887 {
5888 _IOUserServerCheckInCancellationHandler * handlerObj = NULL;
5889 if (!handler) {
5890 goto finish;
5891 }
5892
5893 handlerObj = new _IOUserServerCheckInCancellationHandler;
5894 if (!handlerObj) {
5895 goto finish;
5896 }
5897
5898 handlerObj->fHandler = handler;
5899 handlerObj->fHandlerArgs = args;
5900
5901 finish:
5902 return handlerObj;
5903 }
5904
5905 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5906
5907 struct IOServiceStateNotificationDispatchSource_IVars {
5908 IOLock * fLock;
5909 IOService * fStateNotification;
5910 IOStateNotificationListenerRef fListener;
5911 OSAction * fAction;
5912 bool fEnable;
5913 bool fArmed;
5914 };
5915
5916 kern_return_t
Create_Impl(IOService * service,OSArray * items,IODispatchQueue * queue,IOServiceStateNotificationDispatchSource ** outSource)5917 IOServiceStateNotificationDispatchSource::Create_Impl(IOService * service, OSArray * items,
5918 IODispatchQueue * queue, IOServiceStateNotificationDispatchSource ** outSource)
5919 {
5920 kern_return_t kr;
5921 IOServiceStateNotificationDispatchSource * source;
5922
5923 source = OSTypeAlloc(IOServiceStateNotificationDispatchSource);
5924 source->init();
5925
5926 source->ivars->fStateNotification = service;
5927 kr = service->stateNotificationListenerAdd(items, &source->ivars->fListener, ^kern_return_t () {
5928 OSAction * action;
5929
5930 action = NULL;
5931 IOLockLock(source->ivars->fLock);
5932 if (source->ivars->fArmed && source->ivars->fAction) {
5933 source->ivars->fArmed = false;
5934 action = source->ivars->fAction;
5935 action->retain();
5936 }
5937 IOLockUnlock(source->ivars->fLock);
5938 if (action) {
5939 source->StateNotificationReady(action);
5940 OSSafeReleaseNULL(action);
5941 }
5942 return kIOReturnSuccess;
5943 });
5944
5945 if (kIOReturnSuccess != kr) {
5946 OSSafeReleaseNULL(source);
5947 }
5948 *outSource = source;
5949
5950 return kr;
5951 }
5952
5953
5954 bool
init()5955 IOServiceStateNotificationDispatchSource::init()
5956 {
5957 if (!IODispatchSource::init()) {
5958 return false;
5959 }
5960 ivars = IOMallocType(IOServiceStateNotificationDispatchSource_IVars);
5961 if (!ivars) {
5962 return false;
5963 }
5964 ivars->fLock = IOLockAlloc();
5965 if (!ivars->fLock) {
5966 return false;
5967 }
5968 ivars->fArmed = true;
5969
5970 return true;
5971 }
5972
5973 void
free()5974 IOServiceStateNotificationDispatchSource::free()
5975 {
5976 if (ivars) {
5977 if (ivars->fListener) {
5978 ivars->fStateNotification->stateNotificationListenerRemove(ivars->fListener);
5979 }
5980 if (ivars->fLock) {
5981 IOLockFree(ivars->fLock);
5982 }
5983 IOFreeType(ivars, IOServiceStateNotificationDispatchSource_IVars);
5984 }
5985 IODispatchSource::free();
5986 }
5987
5988 kern_return_t
SetHandler_Impl(OSAction * action)5989 IOServiceStateNotificationDispatchSource::SetHandler_Impl(OSAction * action)
5990 {
5991 IOReturn ret;
5992 bool notifyReady;
5993
5994 notifyReady = false;
5995
5996 IOLockLock(ivars->fLock);
5997 action->retain();
5998 OSSafeReleaseNULL(ivars->fAction);
5999 ivars->fAction = action;
6000 if (action) {
6001 notifyReady = true;
6002 }
6003 IOLockUnlock(ivars->fLock);
6004
6005 if (notifyReady) {
6006 StateNotificationReady(action);
6007 }
6008 ret = kIOReturnSuccess;
6009
6010 return ret;
6011 }
6012
6013 kern_return_t
SetEnableWithCompletion_Impl(bool enable,IODispatchSourceCancelHandler handler)6014 IOServiceStateNotificationDispatchSource::SetEnableWithCompletion_Impl(
6015 bool enable,
6016 IODispatchSourceCancelHandler handler)
6017 {
6018 if (enable == ivars->fEnable) {
6019 return kIOReturnSuccess;
6020 }
6021
6022 IOLockLock(ivars->fLock);
6023 ivars->fEnable = enable;
6024 IOLockUnlock(ivars->fLock);
6025
6026 return kIOReturnSuccess;
6027 }
6028
6029 kern_return_t
Cancel_Impl(IODispatchSourceCancelHandler handler)6030 IOServiceStateNotificationDispatchSource::Cancel_Impl(
6031 IODispatchSourceCancelHandler handler)
6032 {
6033 return kIOReturnUnsupported;
6034 }
6035
6036 kern_return_t
StateNotificationBegin_Impl(void)6037 IOServiceStateNotificationDispatchSource::StateNotificationBegin_Impl(void)
6038 {
6039 IOLockLock(ivars->fLock);
6040 ivars->fArmed = true;
6041 IOLockUnlock(ivars->fLock);
6042
6043 return kIOReturnSuccess;
6044 }
6045
6046 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6047
6048 #include <IOKit/IOServiceStateNotificationEventSource.h>
6049
6050 OSDefineMetaClassAndStructors(IOServiceStateNotificationEventSource, IOEventSource)
6051 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 0);
6052 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 1);
6053 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 2);
6054 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 3);
6055 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 4);
6056 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 5);
6057 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 6);
6058 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 7);
6059
6060 OSPtr<IOServiceStateNotificationEventSource>
serviceStateNotificationEventSource(IOService * service,OSArray * items,ActionBlock inAction)6061 IOServiceStateNotificationEventSource::serviceStateNotificationEventSource(IOService *service,
6062 OSArray * items,
6063 ActionBlock inAction)
6064 {
6065 kern_return_t kr;
6066 IOServiceStateNotificationEventSource * source;
6067
6068 source = OSTypeAlloc(IOServiceStateNotificationEventSource);
6069 if (source && !source->init(service, NULL)) {
6070 OSSafeReleaseNULL(source);
6071 }
6072
6073 if (!source) {
6074 return nullptr;
6075 }
6076
6077 source->fStateNotification = service;
6078 kr = service->stateNotificationListenerAdd(items, &source->fListener, ^kern_return_t () {
6079 if (!source->workLoop) {
6080 return kIOReturnSuccess;
6081 }
6082 source->workLoop->runActionBlock(^IOReturn (void) {
6083 source->fArmed = true;
6084 return kIOReturnSuccess;
6085 });
6086 source->signalWorkAvailable();
6087 return kIOReturnSuccess;
6088 });
6089
6090 if (kIOReturnSuccess != kr) {
6091 OSSafeReleaseNULL(source);
6092 }
6093
6094 if (source) {
6095 source->setActionBlock((IOEventSource::ActionBlock) inAction);
6096 }
6097
6098 return source;
6099 }
6100
6101 void
free()6102 IOServiceStateNotificationEventSource::free()
6103 {
6104 if (fListener) {
6105 fStateNotification->stateNotificationListenerRemove(fListener);
6106 }
6107 IOEventSource::free();
6108 }
6109
6110 void
enable()6111 IOServiceStateNotificationEventSource::enable()
6112 {
6113 fEnable = true;
6114 }
6115
6116 void
disable()6117 IOServiceStateNotificationEventSource::disable()
6118 {
6119 fEnable = false;
6120 }
6121
6122 void
setWorkLoop(IOWorkLoop * inWorkLoop)6123 IOServiceStateNotificationEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
6124 {
6125 IOEventSource::setWorkLoop(inWorkLoop);
6126 }
6127
6128 bool
checkForWork()6129 IOServiceStateNotificationEventSource::checkForWork()
6130 {
6131 ActionBlock intActionBlock = (ActionBlock) actionBlock;
6132
6133 if (fArmed) {
6134 fArmed = false;
6135 (intActionBlock)();
6136 }
6137
6138 return false;
6139 }
6140
6141 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6142
6143 OSDefineMetaClassAndStructors(IOSystemStateNotification, IOService);
6144
6145 class IOStateNotificationItem : public OSObject
6146 {
6147 OSDeclareDefaultStructors(IOStateNotificationItem);
6148
6149 public:
6150 virtual bool init() override;
6151
6152 OSDictionary * fSchema;
6153 OSDictionary * fValue;
6154 OSSet * fListeners;
6155 };
6156 OSDefineMetaClassAndStructors(IOStateNotificationItem, OSObject);
6157
6158
6159 class IOStateNotificationListener : public OSObject
6160 {
6161 OSDeclareDefaultStructors(IOStateNotificationListener);
6162
6163 public:
6164 virtual bool init() override;
6165 virtual void free() override;
6166
6167 IOStateNotificationHandler fHandler;
6168 };
6169 OSDefineMetaClassAndStructors(IOStateNotificationListener, OSObject);
6170
6171
6172 bool
init()6173 IOStateNotificationItem::init()
6174 {
6175 return OSObject::init();
6176 }
6177
6178 bool
init()6179 IOStateNotificationListener::init()
6180 {
6181 return OSObject::init();
6182 }
6183
6184 void
free()6185 IOStateNotificationListener::free()
6186 {
6187 if (fHandler) {
6188 Block_release(fHandler);
6189 }
6190 OSObject::free();
6191 }
6192
6193
6194 struct IOServiceStateChangeVars {
6195 IOLock * fLock;
6196 OSDictionary * fItems;
6197 };
6198
6199 IOService *
initialize(void)6200 IOSystemStateNotification::initialize(void)
6201 {
6202 IOSystemStateNotification * me;
6203 IOServiceStateChangeVars * vars;
6204
6205 me = OSTypeAlloc(IOSystemStateNotification);
6206 me->init();
6207 vars = IOMallocType(IOServiceStateChangeVars);
6208 me->reserved->svars = vars;
6209 vars->fLock = IOLockAlloc();
6210 vars->fItems = OSDictionary::withCapacity(16);
6211 {
6212 kern_return_t ret;
6213
6214 gIOSystemStateSleepDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionKey);
6215 gIOSystemStateSleepDescriptionHibernateStateKey = OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionHibernateStateKey);
6216 gIOSystemStateSleepDescriptionReasonKey = OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionReasonKey);
6217
6218 ret = me->StateNotificationItemCreate(gIOSystemStateSleepDescriptionKey, NULL);
6219 assert(kIOReturnSuccess == ret);
6220
6221 gIOSystemStateHaltDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionKey);
6222 gIOSystemStateHaltDescriptionHaltStateKey = OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionHaltStateKey);
6223
6224 ret = me->StateNotificationItemCreate(gIOSystemStateHaltDescriptionKey, NULL);
6225 assert(kIOReturnSuccess == ret);
6226
6227 gIOSystemStatePowerSourceDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStatePowerSourceDescriptionKey);
6228 gIOSystemStatePowerSourceDescriptionACAttachedKey = OSSymbol::withCStringNoCopy(kIOSystemStatePowerSourceDescriptionACAttachedKey);
6229
6230 ret = me->StateNotificationItemCreate(gIOSystemStatePowerSourceDescriptionKey, NULL);
6231 assert(kIOReturnSuccess == ret);
6232 }
6233
6234 return me;
6235 }
6236
6237 bool
serializeProperties(OSSerialize * s) const6238 IOSystemStateNotification::serializeProperties(OSSerialize * s) const
6239 {
6240 IOServiceStateChangeVars * ivars = reserved->svars;
6241
6242 bool ok;
6243 OSDictionary * result;
6244
6245 result = OSDictionary::withCapacity(16);
6246
6247 IOLockLock(ivars->fLock);
6248 ivars->fItems->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
6249 IOStateNotificationItem * item;
6250
6251 item = (typeof(item))object;
6252 if (!item->fValue) {
6253 return false;
6254 }
6255 result->setObject(key, item->fValue);
6256 return false;
6257 });
6258 IOLockUnlock(ivars->fLock);
6259
6260 ok = result->serialize(s);
6261 OSSafeReleaseNULL(result);
6262
6263 return ok;
6264 }
6265
6266 kern_return_t
setProperties(OSObject * properties)6267 IOSystemStateNotification::setProperties(OSObject * properties)
6268 {
6269 kern_return_t kr;
6270 OSDictionary * dict;
6271 OSDictionary * schema;
6272 OSDictionary * value;
6273 OSString * itemName;
6274
6275 dict = OSDynamicCast(OSDictionary, properties);
6276 if (!dict) {
6277 return kIOReturnBadArgument;
6278 }
6279
6280 if ((schema = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemCreateKey)))) {
6281 itemName = OSDynamicCast(OSString, schema->getObject(kIOStateNotificationNameKey));
6282 kr = StateNotificationItemCreate(itemName, schema);
6283 } else if ((value = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemSetKey)))) {
6284 itemName = OSDynamicCast(OSString, value->getObject(kIOStateNotificationNameKey));
6285 itemName->retain();
6286 value->removeObject(kIOStateNotificationNameKey);
6287 kr = StateNotificationItemSet(itemName, value);
6288 itemName->release();
6289 } else {
6290 kr = kIOReturnError;
6291 }
6292
6293 return kr;
6294 }
6295
6296 kern_return_t
CopySystemStateNotificationService_Impl(IOService ** outService)6297 IOService::CopySystemStateNotificationService_Impl(IOService ** outService)
6298 {
6299 IOService * service;
6300
6301 service = getSystemStateNotificationService();
6302 service->retain();
6303 *outService = service;
6304
6305 return kIOReturnSuccess;
6306 }
6307
6308 IOStateNotificationItem *
stateNotificationItemCopy(OSString * itemName,OSDictionary * schema)6309 IOService::stateNotificationItemCopy(OSString * itemName, OSDictionary * schema)
6310 {
6311 IOServiceStateChangeVars * ivars = reserved->svars;
6312
6313 const OSSymbol * name;
6314 IOStateNotificationItem * item;
6315
6316 name = OSSymbol::withString(itemName);
6317
6318 IOLockLock(ivars->fLock);
6319 if ((item = (typeof(item))ivars->fItems->getObject(name))) {
6320 item->retain();
6321 } else {
6322 item = OSTypeAlloc(IOStateNotificationItem);
6323 item->init();
6324 item->fListeners = OSSet::withCapacity(16);
6325
6326 if (schema) {
6327 schema->retain();
6328 } else {
6329 schema = OSDictionary::withCapacity(8);
6330 }
6331 schema->setObject(kIOStateNotificationNameKey, name);
6332 item->fSchema = schema;
6333 ivars->fItems->setObject(name, item);
6334 }
6335 IOLockUnlock(ivars->fLock);
6336
6337 OSSafeReleaseNULL(name);
6338
6339 return item;
6340 }
6341
6342 kern_return_t
StateNotificationItemCreate_Impl(OSString * itemName,OSDictionary * schema)6343 IOService::StateNotificationItemCreate_Impl(OSString * itemName, OSDictionary * schema)
6344 {
6345 IOStateNotificationItem * item;
6346
6347 item = stateNotificationItemCopy(itemName, schema);
6348 if (!item) {
6349 return kIOReturnNoMemory;
6350 }
6351 item->release();
6352
6353 return kIOReturnSuccess;
6354 }
6355
6356 kern_return_t
StateNotificationItemSet_Impl(OSString * itemName,OSDictionary * value)6357 IOService::StateNotificationItemSet_Impl(OSString * itemName, OSDictionary * value)
6358 {
6359 IOServiceStateChangeVars * ivars = reserved->svars;
6360
6361 OSSet * listeners;
6362 IOStateNotificationItem * item;
6363
6364 value->retain();
6365 IOLockLock(ivars->fLock);
6366 item = (typeof(item))ivars->fItems->getObject(itemName);
6367 OSSafeReleaseNULL(item->fValue);
6368 item->fValue = value;
6369 listeners = NULL;
6370 if (item->fListeners->getCount()) {
6371 listeners = OSSet::withSet(item->fListeners);
6372 }
6373 IOLockUnlock(ivars->fLock);
6374
6375 if (listeners) {
6376 listeners->iterateObjects(^bool (OSObject * object) {
6377 IOStateNotificationListener * listener;
6378
6379 listener = (typeof(listener))object;
6380 listener->fHandler();
6381 return false;
6382 });
6383 OSSafeReleaseNULL(listeners);
6384 }
6385
6386 return kIOReturnSuccess;
6387 }
6388
6389 kern_return_t
StateNotificationItemCopy_Impl(OSString * itemName,OSDictionary ** outValue)6390 IOService::StateNotificationItemCopy_Impl(OSString * itemName, OSDictionary ** outValue)
6391 {
6392 IOServiceStateChangeVars * ivars = reserved->svars;
6393
6394 kern_return_t ret;
6395 IOStateNotificationItem * item;
6396 OSDictionary * value;
6397
6398 IOLockLock(ivars->fLock);
6399 item = (typeof(item))ivars->fItems->getObject(itemName);
6400 if (item) {
6401 value = item->fValue;
6402 } else {
6403 value = NULL;
6404 }
6405 if (!value) {
6406 ret = kIOReturnNotFound;
6407 } else {
6408 value->retain();
6409 ret = kIOReturnSuccess;
6410 }
6411 IOLockUnlock(ivars->fLock);
6412
6413 *outValue = value;
6414
6415 return ret;
6416 }
6417
6418 kern_return_t
stateNotificationListenerAdd(OSArray * items,IOStateNotificationListenerRef * outRef,IOStateNotificationHandler handler)6419 IOService::stateNotificationListenerAdd(OSArray * items,
6420 IOStateNotificationListenerRef * outRef,
6421 IOStateNotificationHandler handler)
6422 {
6423 IOServiceStateChangeVars * ivars = reserved->svars;
6424
6425 kern_return_t kr __block;
6426 IOStateNotificationListener * listener;
6427
6428 listener = OSTypeAlloc(IOStateNotificationListener);
6429 listener->init();
6430 listener->fHandler = Block_copy(handler);
6431
6432 kr = kIOReturnSuccess;
6433 items->iterateObjects(^bool (OSObject * object) {
6434 OSString * itemName;
6435 IOStateNotificationItem * item;
6436
6437 itemName = OSDynamicCast(OSString, object);
6438 if (!itemName) {
6439 kr = kIOReturnBadArgument;
6440 return true;
6441 }
6442 item = stateNotificationItemCopy(itemName, NULL);
6443 if (!item) {
6444 kr = kIOReturnNoMemory;
6445 return true;
6446 }
6447 IOLockLock(ivars->fLock);
6448 item->fListeners->setObject(listener);
6449 IOLockUnlock(ivars->fLock);
6450 item->release();
6451 return false;
6452 });
6453
6454 if (kIOReturnSuccess != kr) {
6455 stateNotificationListenerRemove(listener);
6456 OSSafeReleaseNULL(listener);
6457 }
6458 *outRef = listener;
6459
6460 return kr;
6461 }
6462
6463
6464 kern_return_t
stateNotificationListenerRemove(IOStateNotificationListenerRef ref)6465 IOService::stateNotificationListenerRemove(IOStateNotificationListenerRef ref)
6466 {
6467 IOServiceStateChangeVars * ivars = reserved->svars;
6468
6469 IOStateNotificationListener * listener;
6470 kern_return_t kr;
6471
6472 kr = kIOReturnSuccess;
6473 listener = (typeof(listener))ref;
6474
6475 IOLockLock(ivars->fLock);
6476 ivars->fItems->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
6477 IOStateNotificationItem * item;
6478
6479 item = (typeof(item))object;
6480 item->fListeners->removeObject(listener);
6481 return false;
6482 });
6483 IOLockUnlock(ivars->fLock);
6484
6485 return kr;
6486 }
6487
6488
6489
6490 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6491
6492 kern_return_t
Create_Impl(OSString * name,IOUserClient * userClient,IOWorkGroup ** workgroup)6493 IOWorkGroup::Create_Impl(OSString * name, IOUserClient * userClient, IOWorkGroup ** workgroup)
6494 {
6495 IOWorkGroup * inst = NULL;
6496 IOUserUserClient * uc = NULL;
6497 kern_return_t ret = kIOReturnError;
6498 IOUserServer * us;
6499
6500 if (name == NULL) {
6501 ret = kIOReturnBadArgument;
6502 goto finish;
6503 }
6504
6505 if (name->getLength() > kIOWorkGroupMaxNameLength) {
6506 ret = kIOReturnBadArgument;
6507 goto finish;
6508 }
6509
6510 uc = OSDynamicCast(IOUserUserClient, userClient);
6511 if (uc == NULL) {
6512 ret = kIOReturnBadArgument;
6513 goto finish;
6514 }
6515
6516 inst = OSTypeAlloc(IOWorkGroup);
6517 if (!inst->init()) {
6518 inst->free();
6519 inst = NULL;
6520 ret = kIOReturnNoMemory;
6521 goto finish;
6522 }
6523
6524 us = (typeof(us))thread_iokit_tls_get(0);
6525 inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
6526
6527 if (inst->ivars->userServer == NULL) {
6528 ret = kIOReturnBadArgument;
6529 goto finish;
6530 }
6531 inst->ivars->userServer->retain();
6532
6533 inst->ivars->name = name;
6534 inst->ivars->name->retain();
6535
6536 inst->ivars->userClient = uc; // no retain
6537
6538 IOLockLock(uc->fLock);
6539 uc->fWorkGroups->setObject(name, inst);
6540 IOLockUnlock(uc->fLock);
6541 ret = kIOReturnSuccess;
6542
6543 finish:
6544 if (ret != kIOReturnSuccess) {
6545 OSSafeReleaseNULL(inst);
6546 } else {
6547 *workgroup = inst;
6548 }
6549
6550 return ret;
6551 }
6552
6553 kern_return_t
InvalidateKernel_Impl(IOUserClient * client)6554 IOWorkGroup::InvalidateKernel_Impl(IOUserClient * client)
6555 {
6556 IOUserUserClient * uc = OSDynamicCast(IOUserUserClient, client);
6557
6558 if (uc == NULL) {
6559 return kIOReturnBadArgument;
6560 }
6561
6562 if (uc != ivars->userClient) {
6563 return kIOReturnBadArgument;
6564 }
6565
6566 IOLockLock(uc->fLock);
6567 uc->fWorkGroups->removeObject(ivars->name);
6568 IOLockUnlock(uc->fLock);
6569
6570 return kIOReturnSuccess;
6571 }
6572
6573 kern_return_t
SetWorkGroupPort_Impl(mach_port_t port)6574 IOWorkGroup::SetWorkGroupPort_Impl(mach_port_t port)
6575 {
6576 return kIOReturnUnsupported;
6577 }
6578
6579 bool
init()6580 IOWorkGroup::init()
6581 {
6582 if (!OSObject::init()) {
6583 return false;
6584 }
6585 ivars = IOMallocType(IOWorkGroup_IVars);
6586
6587 return true;
6588 }
6589
6590 void
free()6591 IOWorkGroup::free()
6592 {
6593 if (ivars) {
6594 OSSafeReleaseNULL(ivars->userServer);
6595 OSSafeReleaseNULL(ivars->name);
6596 IOFreeType(ivars, IOWorkGroup_IVars);
6597 }
6598
6599 OSObject::free();
6600 }
6601
6602 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6603
6604 kern_return_t
Create_Impl(OSString * name,IOUserClient * userClient,IOEventLink ** eventlink)6605 IOEventLink::Create_Impl(OSString * name, IOUserClient * userClient, IOEventLink ** eventlink)
6606 {
6607 IOEventLink * inst = NULL;
6608 IOUserUserClient * uc = NULL;
6609 IOUserServer * us;
6610 kern_return_t ret = kIOReturnError;
6611
6612 if (name == NULL) {
6613 ret = kIOReturnBadArgument;
6614 goto finish;
6615 }
6616
6617 if (name->getLength() > kIOEventLinkMaxNameLength) {
6618 ret = kIOReturnBadArgument;
6619 goto finish;
6620 }
6621
6622 uc = OSDynamicCast(IOUserUserClient, userClient);
6623 if (uc == NULL) {
6624 ret = kIOReturnBadArgument;
6625 goto finish;
6626 }
6627
6628 inst = OSTypeAlloc(IOEventLink);
6629 if (!inst->init()) {
6630 inst->free();
6631 inst = NULL;
6632 ret = kIOReturnNoMemory;
6633 goto finish;
6634 }
6635
6636 us = (typeof(us))thread_iokit_tls_get(0);
6637 inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
6638
6639 if (inst->ivars->userServer == NULL) {
6640 ret = kIOReturnBadArgument;
6641 goto finish;
6642 }
6643 inst->ivars->userServer->retain();
6644
6645 inst->ivars->name = name;
6646 inst->ivars->name->retain();
6647
6648 inst->ivars->userClient = uc; // no retain
6649
6650 IOLockLock(uc->fLock);
6651 uc->fEventLinks->setObject(name, inst);
6652 IOLockUnlock(uc->fLock);
6653
6654 ret = kIOReturnSuccess;
6655
6656 finish:
6657 if (ret != kIOReturnSuccess) {
6658 OSSafeReleaseNULL(inst);
6659 } else {
6660 *eventlink = inst;
6661 }
6662
6663 return ret;
6664 }
6665
6666 kern_return_t
InvalidateKernel_Impl(IOUserClient * client)6667 IOEventLink::InvalidateKernel_Impl(IOUserClient * client)
6668 {
6669 IOUserUserClient * uc = OSDynamicCast(IOUserUserClient, client);
6670
6671 if (uc == NULL) {
6672 return kIOReturnBadArgument;
6673 }
6674
6675 if (uc != ivars->userClient) {
6676 return kIOReturnBadArgument;
6677 }
6678
6679 IOLockLock(uc->fLock);
6680 uc->fEventLinks->removeObject(ivars->name);
6681 IOLockUnlock(uc->fLock);
6682
6683 return kIOReturnSuccess;
6684 }
6685
6686 bool
init()6687 IOEventLink::init()
6688 {
6689 if (!OSObject::init()) {
6690 return false;
6691 }
6692 ivars = IOMallocType(IOEventLink_IVars);
6693
6694 return true;
6695 }
6696
6697 void
free()6698 IOEventLink::free()
6699 {
6700 if (ivars) {
6701 OSSafeReleaseNULL(ivars->userServer);
6702 OSSafeReleaseNULL(ivars->name);
6703 IOFreeType(ivars, IOEventLink_IVars);
6704 }
6705
6706 OSObject::free();
6707 }
6708
6709 kern_return_t
SetEventlinkPort_Impl(mach_port_t port __unused)6710 IOEventLink::SetEventlinkPort_Impl(mach_port_t port __unused)
6711 {
6712 return kIOReturnUnsupported;
6713 }
6714