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