xref: /xnu-8020.101.4/iokit/Tests/Tests.cpp (revision e7776783b89a353188416a9a346c6cdb4928faad)
1 /*
2  * Copyright (c) 1998-2021 Apple Computer, 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  *
30  */
31 
32 #define TEST_HEADERS    0
33 #define IOKIT_ENABLE_SHARED_PTR
34 
35 #if TEST_HEADERS
36 
37 #include <libkern/OSByteOrder.h>
38 #include <libkern/c++/OSArray.h>
39 #include <libkern/c++/OSAllocation.h>
40 #include <libkern/c++/OSBoolean.h>
41 #include <libkern/c++/OSBoundedArray.h>
42 #include <libkern/c++/OSBoundedArrayRef.h>
43 #include <libkern/c++/OSBoundedPtr.h>
44 #include <libkern/c++/OSCollection.h>
45 #include <libkern/c++/OSCollectionIterator.h>
46 #include <libkern/c++/OSContainers.h>
47 #include <libkern/c++/OSCPPDebug.h>
48 #include <libkern/c++/OSData.h>
49 #include <libkern/c++/OSDictionary.h>
50 #include <libkern/c++/OSEndianTypes.h>
51 #include <libkern/c++/OSIterator.h>
52 #include <libkern/c++/OSKext.h>
53 #include <libkern/c++/OSLib.h>
54 #include <libkern/c++/OSMetaClass.h>
55 #include <libkern/c++/OSNumber.h>
56 #include <libkern/c++/OSObject.h>
57 #include <libkern/c++/OSOrderedSet.h>
58 #include <libkern/c++/OSSerialize.h>
59 #include <libkern/c++/OSSet.h>
60 #include <libkern/c++/OSSharedPtr.h>
61 #include <libkern/c++/OSString.h>
62 #include <libkern/c++/OSSymbol.h>
63 #include <libkern/c++/OSUnserialize.h>
64 #include <libkern/c++/OSValueObject.h>
65 #include <libkern/crypto/aes.h>
66 #include <libkern/crypto/aesxts.h>
67 #include <libkern/crypto/crypto_internal.h>
68 #include <libkern/crypto/des.h>
69 #include <libkern/crypto/md5.h>
70 #include <libkern/crypto/register_crypto.h>
71 #include <libkern/crypto/sha1.h>
72 #include <libkern/crypto/sha2.h>
73 #include <libkern/kernel_mach_header.h>
74 #include <libkern/kext_request_keys.h>
75 #include <libkern/kxld.h>
76 #include <libkern/kxld_types.h>
77 #include <libkern/locks.h>
78 #include <libkern/mkext.h>
79 #include <libkern/OSAtomic.h>
80 #include <libkern/OSBase.h>
81 #include <libkern/OSDebug.h>
82 #include <libkern/OSKextLib.h>
83 #include <libkern/OSKextLibPrivate.h>
84 #include <libkern/OSReturn.h>
85 #include <libkern/OSSerializeBinary.h>
86 #include <libkern/OSTypes.h>
87 #include <libkern/prelink.h>
88 #include <libkern/stack_protector.h>
89 #include <libkern/sysctl.h>
90 #include <libkern/tree.h>
91 #include <libkern/zconf.h>
92 #include <libkern/zlib.h>
93 
94 #include <IOKit/AppleKeyStoreInterface.h>
95 #include <IOKit/assert.h>
96 #include <IOKit/IOBSD.h>
97 #include <IOKit/IOBufferMemoryDescriptor.h>
98 #include <IOKit/IOCatalogue.h>
99 #include <IOKit/IOCommand.h>
100 #include <IOKit/IOCommandGate.h>
101 #include <IOKit/IOCommandPool.h>
102 #include <IOKit/IOCommandQueue.h>
103 #include <IOKit/IOConditionLock.h>
104 #include <IOKit/IOCPU.h>
105 //#include <IOKit/IODataQueue.h>
106 #include <IOKit/IODataQueueShared.h>
107 #include <IOKit/IODeviceMemory.h>
108 #include <IOKit/IODeviceTreeSupport.h>
109 #include <IOKit/IODMACommand.h>
110 #include <IOKit/IODMAController.h>
111 #include <IOKit/IODMAEventSource.h>
112 #include <IOKit/IOEventSource.h>
113 #include <IOKit/IOFilterInterruptEventSource.h>
114 #include <IOKit/IOHibernatePrivate.h>
115 #include <IOKit/IOInterleavedMemoryDescriptor.h>
116 #include <IOKit/IOInterruptAccounting.h>
117 #include <IOKit/IOInterruptAccountingPrivate.h>
118 #include <IOKit/IOInterruptController.h>
119 #include <IOKit/IOInterruptEventSource.h>
120 #include <IOKit/IOInterrupts.h>
121 #include <IOKit/IOKernelReporters.h>
122 #include <IOKit/IOKernelReportStructs.h>
123 #include <IOKit/IOKitDebug.h>
124 #include <IOKit/IOKitDiagnosticsUserClient.h>
125 #include <IOKit/IOKitKeys.h>
126 #include <IOKit/IOKitKeysPrivate.h>
127 #include <IOKit/IOKitServer.h>
128 #include <IOKit/IOLib.h>
129 #include <IOKit/IOLocks.h>
130 #include <IOKit/IOLocksPrivate.h>
131 #include <IOKit/IOMapper.h>
132 #include <IOKit/IOMemoryCursor.h>
133 #include <IOKit/IOMemoryDescriptor.h>
134 #include <IOKit/IOMessage.h>
135 #include <IOKit/IOMultiMemoryDescriptor.h>
136 #include <IOKit/IONotifier.h>
137 #include <IOKit/IONVRAM.h>
138 #include <IOKit/IOPlatformExpert.h>
139 #include <IOKit/IOPolledInterface.h>
140 #include <IOKit/IORangeAllocator.h>
141 #include <IOKit/IORegistryEntry.h>
142 #include <IOKit/IOReportMacros.h>
143 #include <IOKit/IOReportTypes.h>
144 #include <IOKit/IOReturn.h>
145 #include <IOKit/IOService.h>
146 #include <IOKit/IOServicePM.h>
147 #include <IOKit/IOSharedDataQueue.h>
148 #include <IOKit/IOSharedLock.h>
149 #include <IOKit/IOStatistics.h>
150 #include <IOKit/IOStatisticsPrivate.h>
151 #include <IOKit/IOSubMemoryDescriptor.h>
152 #include <IOKit/IOSyncer.h>
153 #include <IOKit/IOTimerEventSource.h>
154 #include <IOKit/IOTimeStamp.h>
155 #include <IOKit/IOTypes.h>
156 #include <IOKit/IOUserClient.h>
157 #include <IOKit/IOWorkLoop.h>
158 #include <IOKit/nvram/IONVRAMController.h>
159 #include <IOKit/OSMessageNotification.h>
160 #include <IOKit/platform/AppleMacIO.h>
161 #include <IOKit/platform/AppleMacIODevice.h>
162 #include <IOKit/platform/AppleNMI.h>
163 #include <IOKit/platform/ApplePlatformExpert.h>
164 #include <IOKit/power/IOPwrController.h>
165 #include <IOKit/pwr_mgt/IOPM.h>
166 #include <IOKit/pwr_mgt/IOPMinformee.h>
167 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
168 #include <IOKit/pwr_mgt/IOPMLibDefs.h>
169 #include <IOKit/pwr_mgt/IOPMlog.h>
170 #include <IOKit/pwr_mgt/IOPMPowerSource.h>
171 #include <IOKit/pwr_mgt/IOPMPowerSourceList.h>
172 #include <IOKit/pwr_mgt/IOPMpowerState.h>
173 #include <IOKit/pwr_mgt/IOPMPrivate.h>
174 #include <IOKit/pwr_mgt/IOPowerConnection.h>
175 #include <IOKit/pwr_mgt/RootDomain.h>
176 #include <IOKit/rtc/IORTCController.h>
177 #include <IOKit/system.h>
178 #include <IOKit/system_management/IOWatchDogTimer.h>
179 #include <math.h>
180 
181 #endif /* TEST_HEADERS */
182 
183 #include <sys/sysctl.h>
184 #include <libkern/c++/OSData.h>
185 #include <IOKit/IOService.h>
186 #include <IOKit/IOUserClient.h>
187 #include "Tests.h"
188 
189 
190 #if DEVELOPMENT || DEBUG
191 
192 #include <IOKit/IOWorkLoop.h>
193 #include <IOKit/IOTimerEventSource.h>
194 #include <IOKit/IOInterruptEventSource.h>
195 #include <IOKit/IOCommandGate.h>
196 #include <IOKit/IOPlatformExpert.h>
197 #include <IOKit/IOSharedDataQueue.h>
198 #include <IOKit/IODataQueueShared.h>
199 #include <IOKit/IOServiceStateNotificationEventSource.h>
200 #include <IOKit/IOKitKeysPrivate.h>
201 #include <IOKit/IOKitServer.h>
202 #include <IOKit/IOBSD.h>
203 #include <kern/ipc_kobject.h>
204 #include <libkern/Block.h>
205 #include <libkern/Block_private.h>
206 #include <libkern/c++/OSAllocation.h>
207 #include <libkern/c++/OSBoundedArray.h>
208 #include <libkern/c++/OSBoundedArrayRef.h>
209 #include <libkern/c++/OSBoundedPtr.h>
210 #include <libkern/c++/OSSharedPtr.h>
211 #include <os/cpp_util.h>
212 
213 static uint64_t gIOWorkLoopTestDeadline;
214 
215 static void
TESAction(OSObject * owner,IOTimerEventSource * tes)216 TESAction(OSObject * owner, IOTimerEventSource * tes)
217 {
218 	if (mach_absolute_time() < gIOWorkLoopTestDeadline) {
219 		tes->setTimeout(1, kMicrosecondScale);
220 	}
221 }
222 
223 static int
IOWorkLoopTest(int newValue)224 IOWorkLoopTest(int newValue)
225 {
226 	IOReturn err;
227 	uint32_t idx;
228 	OSSharedPtr<IOWorkLoop> wl;
229 	OSSharedPtr<IOTimerEventSource> tes;
230 	OSSharedPtr<IOInterruptEventSource> ies;
231 
232 	wl = IOWorkLoop::workLoop();
233 	assert(wl);
234 	tes = IOTimerEventSource::timerEventSource(kIOTimerEventSourceOptionsPriorityWorkLoop, wl.get(), &TESAction);
235 	assert(tes);
236 	err = wl->addEventSource(tes.get());
237 	assert(kIOReturnSuccess == err);
238 	clock_interval_to_deadline(100, kMillisecondScale, &gIOWorkLoopTestDeadline);
239 	for (idx = 0; mach_absolute_time() < gIOWorkLoopTestDeadline; idx++) {
240 		tes->setTimeout(idx & 1023, kNanosecondScale);
241 	}
242 	tes->cancelTimeout();
243 	wl->removeEventSource(tes.get());
244 
245 	int value = 3;
246 
247 	tes = IOTimerEventSource::timerEventSource(kIOTimerEventSourceOptionsDefault, wl.get(), ^(IOTimerEventSource * tes){
248 		kprintf("wl %p, value %d\n", wl.get(), value);
249 	});
250 	err = wl->addEventSource(tes.get());
251 	assert(kIOReturnSuccess == err);
252 
253 	value = 2;
254 	tes->setTimeout(1, kNanosecondScale);
255 	IOSleep(1);
256 	wl->removeEventSource(tes.get());
257 
258 	ies = IOInterruptEventSource::interruptEventSource(wl.get(), NULL, 0, ^void (IOInterruptEventSource *sender, int count){
259 		kprintf("ies block %p, %d\n", sender, count);
260 	});
261 
262 	assert(ies);
263 	kprintf("ies %p\n", ies.get());
264 	err = wl->addEventSource(ies.get());
265 	assert(kIOReturnSuccess == err);
266 	ies->interruptOccurred(NULL, NULL, 0);
267 	IOSleep(1);
268 	ies->interruptOccurred(NULL, NULL, 0);
269 	IOSleep(1);
270 	wl->removeEventSource(ies.get());
271 
272 	return 0;
273 }
274 
275 static int
OSCollectionTest(int newValue)276 OSCollectionTest(int newValue)
277 {
278 	OSSharedPtr<OSArray> array = OSArray::withCapacity(8);
279 	array->setObject(kOSBooleanTrue);
280 	array->setObject(kOSBooleanFalse);
281 	array->setObject(kOSBooleanFalse);
282 	array->setObject(kOSBooleanTrue);
283 	array->setObject(kOSBooleanFalse);
284 	array->setObject(kOSBooleanTrue);
285 
286 	__block unsigned int index;
287 	index = 0;
288 	array->iterateObjects(^bool (OSObject * obj) {
289 		kprintf("%d:%d ", index, (obj == kOSBooleanTrue) ? 1 : (obj == kOSBooleanFalse) ? 0 : 2);
290 		index++;
291 		return false;
292 	});
293 	kprintf("\n");
294 
295 	OSSharedPtr<OSDictionary> dict = IOService::resourceMatching("hello");
296 	assert(dict);
297 	index = 0;
298 	dict->iterateObjects(^bool (const OSSymbol * sym, OSObject * obj) {
299 		OSString * str = OSDynamicCast(OSString, obj);
300 		assert(str);
301 		kprintf("%d:%s=%s\n", index, sym->getCStringNoCopy(), str->getCStringNoCopy());
302 		index++;
303 		return false;
304 	});
305 
306 	OSSharedPtr<OSSerializer> serializer = OSSerializer::withBlock(^bool (OSSerialize * s){
307 		return gIOBSDUnitKey->serialize(s);
308 	});
309 	assert(serializer);
310 	IOService::getPlatform()->setProperty("OSSerializer_withBlock", serializer.get());
311 
312 	OSSharedPtr<OSString> ab = OSString::withCString("abcdef", 2);
313 	assert(strcmp(ab->getCStringNoCopy(), "ab") == 0);
314 	OSSharedPtr<OSString> defgh = OSString::withCString("defgh", 10);
315 	assert(strcmp(defgh->getCStringNoCopy(), "defgh") == 0);
316 	OSSharedPtr<OSString> zyxwvut = OSString::withCString("zyxwvut", 7);
317 	assert(strcmp(zyxwvut->getCStringNoCopy(), "zyxwvut") == 0);
318 
319 	return 0;
320 }
321 
322 static int
OSAllocationTests(int)323 OSAllocationTests(int)
324 {
325 	OSAllocation<int> ints(100, OSAllocateMemory);
326 	assert(ints);
327 
328 	{
329 		int counter = 0;
330 		for (int& i : ints) {
331 			i = counter++;
332 		}
333 	}
334 
335 	{
336 		int counter = 0;
337 		for (int& i : ints) {
338 			assert(i == counter);
339 			++counter;
340 		}
341 	}
342 
343 	OSAllocation<int> arrayZero(100, OSAllocateMemoryZero);
344 	assert(arrayZero);
345 	for (const auto& i : arrayZero) {
346 		assert(i == 0);
347 	}
348 
349 	// Make sure we can have two-level OSAllocations
350 	{
351 		OSAllocation<OSAllocation<int> > testArray(10, OSAllocateMemory);
352 		for (int i = 0; i < 10; i++) {
353 			testArray[i] = OSAllocation<int>(10, OSAllocateMemory);
354 			for (int j = 0; j < 10; ++j) {
355 				testArray[i][j] = i + j;
356 			}
357 		}
358 
359 		for (int i = 0; i < 10; i++) {
360 			for (int j = 0; j < 10; ++j) {
361 				assert(testArray[i][j] == i + j);
362 			}
363 		}
364 	}
365 
366 	return 0;
367 }
368 
369 static int
OSDataAllocationTests(int)370 OSDataAllocationTests(int)
371 {
372 	OSDataAllocation<int> ints(100, OSAllocateMemory);
373 	assert(ints);
374 
375 	{
376 		int counter = 0;
377 		for (int& i : ints) {
378 			i = counter++;
379 		}
380 	}
381 
382 	{
383 		int counter = 0;
384 		for (const int& i : ints) {
385 			assert(i == counter);
386 			++counter;
387 		}
388 	}
389 
390 	OSDataAllocation<int> arrayZero(100, OSAllocateMemoryZero);
391 	assert(arrayZero);
392 	for (const auto& i : arrayZero) {
393 		assert(i == 0);
394 	}
395 
396 	return 0;
397 }
398 
399 static int
OSBoundedArrayTests(int)400 OSBoundedArrayTests(int)
401 {
402 	OSBoundedArray<int, 5> ints = {0, 1, 2, 3, 4};
403 	assert(ints.size() == 5);
404 
405 	{
406 		int counter = 0;
407 		for (int& i : ints) {
408 			i = counter++;
409 		}
410 	}
411 
412 	{
413 		int counter = 0;
414 		for (int& i : ints) {
415 			assert(i == counter);
416 			++counter;
417 		}
418 	}
419 
420 	return 0;
421 }
422 
423 static int
OSBoundedArrayRefTests(int)424 OSBoundedArrayRefTests(int)
425 {
426 	OSBoundedArray<int, 5> storage = {0, 1, 2, 3, 4};
427 	OSBoundedArrayRef<int> ints(storage);
428 	assert(ints);
429 
430 	{
431 		int counter = 0;
432 		for (int& i : ints) {
433 			i = counter++;
434 		}
435 	}
436 
437 	{
438 		int counter = 0;
439 		for (int& i : ints) {
440 			assert(i == counter);
441 			++counter;
442 		}
443 	}
444 
445 	return 0;
446 }
447 
448 class OSArraySubclass : public OSArray {
449 	OSDeclareDefaultStructors(OSArraySubclass);
450 public:
451 	static OSSharedPtr<OSArraySubclass> withCapacity(unsigned int inCapacity);
452 	virtual unsigned int iteratorSize() const APPLE_KEXT_OVERRIDE;
453 };
454 
455 OSDefineMetaClassAndStructors(OSArraySubclass, OSArray);
456 
457 OSSharedPtr<OSArraySubclass>
withCapacity(unsigned int inCapacity)458 OSArraySubclass::withCapacity(unsigned int inCapacity)
459 {
460 	OSSharedPtr<OSArraySubclass> me = OSMakeShared<OSArraySubclass>();
461 
462 	if (me && !me->initWithCapacity(inCapacity)) {
463 		return nullptr;
464 	}
465 
466 	return me;
467 }
468 
469 unsigned int
iteratorSize() const470 OSArraySubclass::iteratorSize() const
471 {
472 	unsigned int result = 64;
473 	// Has to be larger than the OSArray iterator size to prevent out-of-bounds writes
474 	assert(result >= OSArray::iteratorSize());
475 	return result;
476 }
477 
478 class OSCISubclass : public OSCollectionIterator {
479 	OSDeclareDefaultStructors(OSCISubclass);
480 public:
481 	static OSSharedPtr<OSCISubclass> withCollection(const OSCollection * inColl);
482 };
483 
484 OSDefineMetaClassAndStructors(OSCISubclass, OSCollectionIterator);
485 
486 OSSharedPtr<OSCISubclass>
withCollection(const OSCollection * inColl)487 OSCISubclass::withCollection(const OSCollection * inColl)
488 {
489 	OSSharedPtr<OSCISubclass> me = OSMakeShared<OSCISubclass>();
490 
491 	if (me && !me->initWithCollection(inColl)) {
492 		return nullptr;
493 	}
494 
495 	return me;
496 }
497 
498 static int
OSCollectionIteratorTests(int)499 OSCollectionIteratorTests(int)
500 {
501 	OSSharedPtr<OSArray> array = OSArray::withCapacity(0);
502 	OSSharedPtr<OSString> firstObj = OSString::withCString("test object");
503 	OSSharedPtr<OSString> secondObj = OSString::withCString("test object 2");
504 	OSObject * current = NULL;
505 	OSSharedPtr<OSCollectionIterator> osci = NULL;
506 	OSSharedPtr<OSCISubclass> osciSubclass = NULL;
507 	size_t index = 0;
508 	array->setObject(firstObj);
509 	array->setObject(secondObj);
510 
511 	// Test iteration over a normal OSArray
512 	osci = OSCollectionIterator::withCollection(array.get());
513 	assert(osci != NULL);
514 
515 	index = 0;
516 	while ((current = osci->getNextObject()) != NULL) {
517 		if (index == 0) {
518 			assert(current == firstObj);
519 		} else if (index == 1) {
520 			assert(current == secondObj);
521 		} else {
522 			panic("index out of range");
523 		}
524 		index++;
525 	}
526 
527 	// Test iteration with a OSCollectionIterator subclass over a normal OSArray
528 	osciSubclass = OSCISubclass::withCollection(array.get());
529 	assert(osciSubclass != NULL);
530 
531 	index = 0;
532 	while ((current = osciSubclass->getNextObject()) != NULL) {
533 		if (index == 0) {
534 			assert(current == firstObj);
535 		} else if (index == 1) {
536 			assert(current == secondObj);
537 		} else {
538 			panic("index out of range");
539 		}
540 		index++;
541 	}
542 
543 	// Create the OSArray subclass
544 	OSSharedPtr<OSArraySubclass> arraySubclass = OSArraySubclass::withCapacity(0);
545 	arraySubclass->setObject(firstObj);
546 	arraySubclass->setObject(secondObj);
547 	// Test iteration over a subclassed OSArray, with a large iterator size
548 	osci = OSCollectionIterator::withCollection(arraySubclass.get());
549 	assert(osci != NULL);
550 
551 	index = 0;
552 	while ((current = osci->getNextObject()) != NULL) {
553 		if (index == 0) {
554 			assert(current == firstObj);
555 		} else if (index == 1) {
556 			assert(current == secondObj);
557 		} else {
558 			panic("index out of range");
559 		}
560 		index++;
561 	}
562 
563 	// Test iteration with a OSCollectionIterator subclass over a subclassed OSArray,
564 	// with a large iterator size.
565 	osciSubclass = OSCISubclass::withCollection(arraySubclass.get());
566 	assert(osciSubclass != NULL);
567 
568 	index = 0;
569 	while ((current = osciSubclass->getNextObject()) != NULL) {
570 		if (index == 0) {
571 			assert(current == firstObj);
572 		} else if (index == 1) {
573 			assert(current == secondObj);
574 		} else {
575 			panic("index out of range");
576 		}
577 		index++;
578 	}
579 
580 	return 0;
581 }
582 
583 static int
OSBoundedPtrTests(int)584 OSBoundedPtrTests(int)
585 {
586 	int array[5] = {55, 66, 77, 88, 99};
587 	OSBoundedPtr<int> begin(&array[0], &array[0], &array[5]);
588 	OSBoundedPtr<int> end(&array[5], &array[0], &array[5]);
589 
590 	{
591 		int counter = 0;
592 		for (OSBoundedPtr<int> b = begin; b != end; ++b) {
593 			*b = counter++;
594 		}
595 	}
596 
597 	{
598 		int counter = 0;
599 		for (OSBoundedPtr<int> b = begin; b != end; ++b) {
600 			assert(*b == counter);
601 			++counter;
602 		}
603 	}
604 
605 	return 0;
606 }
607 
608 static int
OSValueObjectTests(int)609 OSValueObjectTests(int)
610 {
611 	struct TrivialTestType {
612 		int a;
613 		bool b;
614 		float c;
615 	};
616 
617 	class NonTrivialConstructorTestType
618 	{
619 public:
620 		NonTrivialConstructorTestType() = default;
621 		int a = 3;
622 		bool b = true;
623 		float c = 999.f;
624 	};
625 
626 	constexpr auto nearlyEqual = [](float a, float b)
627 	    {
628 		    constexpr float epsilon = 0.000001f;
629 		    const auto diff = a - b;
630 		    return (diff >= -epsilon) && (diff <= epsilon);
631 	    };
632 
633 	// test simple built-in type
634 	{
635 		using T = int;
636 		OSSharedPtr<OSValueObject<T> > test = OSValueObject<T>::create();
637 		assert(test);
638 		if (test) {
639 			assert(test->getRef() == 0);
640 			assert(test->isEqualTo(0));
641 			assert(test->getBytesNoCopy());
642 			assert(test->getBytesNoCopy() == test->getMutableBytesNoCopy());
643 			assert(test->getLength() == sizeof(T));
644 		}
645 	}
646 
647 	// test trivial aggregate type
648 	{
649 		using T = TrivialTestType;
650 		OSSharedPtr<OSValueObject<T> > test = OSValueObject<T>::create();
651 		assert(test);
652 		if (test) {
653 			const auto *const bytes = reinterpret_cast<const uint8_t*>(test->getBytesNoCopy());
654 			bool bytesAreZero = true;
655 			for (size_t byteIndex = 0; byteIndex < test->getLength(); byteIndex++) {
656 				bytesAreZero &= bytes[byteIndex] == 0;
657 			}
658 			assert(bytesAreZero);
659 		}
660 	}
661 
662 	// test aggregate type with non-trivial constructor
663 	{
664 		using T = NonTrivialConstructorTestType;
665 		OSSharedPtr<OSValueObject<T> > test = OSValueObject<T>::create();
666 		assert(test);
667 		if (test) {
668 			const T other;
669 			assert(test->isEqualTo(other));
670 			assert(test->getRef().a == other.a);
671 			assert(test->getRef().b == other.b);
672 			assert(nearlyEqual(test->getRef().c, other.c));
673 		}
674 	}
675 
676 	// test copying of OSValueObject
677 	{
678 		using T = NonTrivialConstructorTestType;
679 		OSSharedPtr<OSValueObject<T> > test1;
680 		T valueCopy;
681 		{
682 			T value; // declared in sub-scope to ensure instance-independence when it falls out of scope
683 			value.a = 1;
684 			value.b = true;
685 			value.c = 3.f;
686 			valueCopy = value;
687 			test1 = OSValueObject<T>::withValue(value);
688 			assert(test1);
689 			if (test1) {
690 				assert(test1->isEqualTo(value));
691 				assert(test1->getRef().a == value.a);
692 				assert(test1->getRef().b == value.b);
693 				assert(nearlyEqual(test1->getRef().c, value.c));
694 			}
695 			valueCopy.a = 100;
696 			test1->getMutableRef().a = valueCopy.a;
697 		}
698 		if (test1) {
699 			OSSharedPtr<OSValueObject<T> > test2 = OSValueObject<T>::withValueObject(test1.get());
700 			if (test2) {
701 				assert(test2->isEqualTo(test1.get()));
702 				assert(test2->getRef().a == valueCopy.a);
703 				assert(test2->getRef().b == valueCopy.b);
704 				assert(nearlyEqual(test2->getRef().c, valueCopy.c));
705 			}
706 		}
707 	}
708 
709 	return KERN_SUCCESS;
710 }
711 
712 
713 static int
IOSharedDataQueue_44636964(__unused int newValue)714 IOSharedDataQueue_44636964(__unused int newValue)
715 {
716 	OSSharedPtr<IOSharedDataQueue> sd = IOSharedDataQueue::withCapacity(DATA_QUEUE_ENTRY_HEADER_SIZE + sizeof(UInt64));
717 	UInt64 data = 0x11223344aa55aa55;
718 	UInt32 data2 = 0x44332211;
719 	UInt32 size = sizeof(UInt32);
720 	/* enqueue moves tail to end */
721 	sd->enqueue(&data, sizeof(UInt64));
722 	/* dequeue moves head to end */
723 	sd->dequeue(&data, &size);
724 	/* Tail wraps around, head is still at end */
725 	sd->enqueue(&data2, sizeof(UInt32));
726 	/* something in the queue so peek() should return non-null */
727 	assert(sd->peek() != NULL);
728 	return KERN_SUCCESS;
729 }
730 
731 #if 0
732 #include <IOKit/IOUserClient.h>
733 class TestUserClient : public IOUserClient
734 {
735 	OSDeclareDefaultStructors(TestUserClient);
736 	virtual void stop( IOService *provider) APPLE_KEXT_OVERRIDE;
737 	virtual bool finalize(IOOptionBits options) APPLE_KEXT_OVERRIDE;
738 	virtual IOReturn externalMethod( uint32_t selector,
739 	    IOExternalMethodArguments * arguments,
740 	    IOExternalMethodDispatch * dispatch,
741 	    OSObject * target,
742 	    void * reference ) APPLE_KEXT_OVERRIDE;
743 };
744 
745 void
746 TestUserClient::stop( IOService *provider)
747 {
748 	kprintf("TestUserClient::stop\n");
749 }
750 bool
751 TestUserClient::finalize(IOOptionBits options)
752 {
753 	kprintf("TestUserClient::finalize\n");
754 	return true;
755 }
756 IOReturn
757 TestUserClient::externalMethod( uint32_t selector,
758     IOExternalMethodArguments * arguments,
759     IOExternalMethodDispatch * dispatch,
760     OSObject * target,
761     void * reference )
762 {
763 	getProvider()->terminate();
764 	IOSleep(500);
765 	return 0;
766 }
767 OSDefineMetaClassAndStructors(TestUserClient, IOUserClient);
768 #endif
769 
770 static int
IOServiceTest(int newValue)771 IOServiceTest(int newValue)
772 {
773 	OSSharedPtr<OSDictionary> matching;
774 	IONotifier        * note;
775 	__block IOService * found;
776 
777 #if 0
778 	found = new IOService;
779 	found->init();
780 	found->setName("IOTestUserClientProvider");
781 	found->attach(IOService::getPlatform());
782 	found->setProperty("IOUserClientClass", "TestUserClient");
783 	found->registerService();
784 #endif
785 
786 	matching = IOService::serviceMatching("IOPlatformExpert");
787 	assert(matching);
788 	found = nullptr;
789 	note = IOService::addMatchingNotification(gIOMatchedNotification, matching.get(), 0,
790 	    ^bool (IOService * newService, IONotifier * notifier) {
791 		kprintf("found %s, %d\n", newService->getName(), newService->getRetainCount());
792 		found = newService;
793 		found->retain();
794 		return true;
795 	}
796 	    );
797 	assert(note);
798 	assert(found);
799 	note->remove();
800 
801 	note = found->registerInterest(gIOBusyInterest,
802 	    ^IOReturn (uint32_t messageType, IOService * provider,
803 	    void   * messageArgument, size_t argSize) {
804 		kprintf("%p messageType 0x%08x %p\n", provider, messageType, messageArgument);
805 		return kIOReturnSuccess;
806 	}).detach();
807 	assert(note);
808 	IOSleep(1 * 1000);
809 	note->remove();
810 	found->release();
811 
812 	return 0;
813 }
814 
815 static void
OSStaticPtrCastTests()816 OSStaticPtrCastTests()
817 {
818 	// const& overload
819 	{
820 		OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
821 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
822 		assert(collection == dict);
823 	}
824 	{
825 		OSSharedPtr<OSDictionary> const dict = nullptr;
826 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
827 		assert(collection == nullptr);
828 	}
829 	// && overload
830 	{
831 		OSSharedPtr<OSDictionary> dict = OSMakeShared<OSDictionary>();
832 		OSDictionary* oldDict = dict.get();
833 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
834 		assert(collection.get() == oldDict);
835 		assert(dict == nullptr);
836 	}
837 	{
838 		OSSharedPtr<OSDictionary> dict = nullptr;
839 		OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
840 		assert(collection == nullptr);
841 		assert(dict == nullptr);
842 	}
843 }
844 
845 static void
OSConstPtrCastTests()846 OSConstPtrCastTests()
847 {
848 	// const& overload
849 	{
850 		OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
851 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
852 		assert(dict2 == dict);
853 	}
854 	{
855 		OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
856 		OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
857 		assert(dict2 == dict);
858 	}
859 	{
860 		OSSharedPtr<OSDictionary const> const dict = nullptr;
861 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
862 		assert(dict2 == nullptr);
863 	}
864 	{
865 		OSSharedPtr<OSDictionary const> const dict = nullptr;
866 		OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
867 		assert(dict2 == nullptr);
868 	}
869 
870 	// && overload
871 	{
872 		OSSharedPtr<OSDictionary const> dict = OSMakeShared<OSDictionary>();
873 		OSDictionary const* oldDict = dict.get();
874 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
875 		assert(dict == nullptr);
876 		assert(dict2 == oldDict);
877 	}
878 	{
879 		OSSharedPtr<OSDictionary const> dict = nullptr;
880 		OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
881 		assert(dict == nullptr);
882 		assert(dict2 == nullptr);
883 	}
884 }
885 
886 static void
OSDynamicPtrCastTests()887 OSDynamicPtrCastTests()
888 {
889 	OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
890 	{
891 		OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
892 		assert(collection != nullptr);
893 	}
894 	{
895 		OSSharedPtr<OSArray> array = OSDynamicPtrCast<OSArray>(dict);
896 		assert(array == nullptr);
897 		assert(dict != nullptr);
898 	}
899 	{
900 		OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
901 		OSTaggedSharedPtr<OSCollection, OSCollection> collection = OSDynamicPtrCast<OSCollection>(taggedDict);
902 		assert(collection != nullptr);
903 	}
904 	{
905 		OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
906 		OSTaggedSharedPtr<OSArray, OSCollection> array = OSDynamicPtrCast<OSArray>(taggedDict);
907 		assert(array == nullptr);
908 		assert(dict != nullptr);
909 	}
910 	{
911 		OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
912 		assert(collection.get() == OSDynamicCast(OSDictionary, dict.get()));
913 		OSSharedPtr<OSDictionary> newDict = OSDynamicPtrCast<OSDictionary>(os::move(collection));
914 		assert(collection == nullptr);
915 		assert(newDict != nullptr);
916 		assert(newDict.get() == dict.get());
917 	}
918 }
919 
920 
921 class IOTestUserNotification : public IOUserNotification
922 {
923 	OSDeclareDefaultStructors(IOTestUserNotification);
924 };
925 
926 OSDefineMetaClassAndStructors(IOTestUserNotification, IOUserNotification)
927 
928 struct IOUserNotificationTestThreadArgs {
929 	IOTestUserNotification * userNotify;
930 	IOLock * lock;
931 	size_t * completed;
932 	size_t iterations;
933 };
934 
935 static bool
IOUserNotificationMatchingHandler(void * target __unused,void * ref __unused,IOService * newService __unused,IONotifier * notifier __unused)936 IOUserNotificationMatchingHandler( void * target __unused,
937     void * ref __unused, IOService * newService __unused, IONotifier * notifier __unused )
938 {
939 	return true;
940 }
941 
942 static void
IOUserNotificationTestThread(void * arg,wait_result_t result __unused)943 IOUserNotificationTestThread(void * arg, wait_result_t result __unused)
944 {
945 	IOUserNotificationTestThreadArgs * threadArgs = (IOUserNotificationTestThreadArgs *)arg;
946 
947 	OSSharedPtr<OSDictionary> dict = OSDictionary::withCapacity(0);
948 	OSSharedPtr<OSString> rootPath = OSString::withCStringNoCopy(":/");
949 	dict->setObject(gIOPathMatchKey, rootPath);
950 
951 	for (size_t i = 0; i < threadArgs->iterations; i++) {
952 		if (i % 2 == 0) {
953 			IONotifier * notify = IOService::addMatchingNotification( gIOWillTerminateNotification, dict.get(),
954 			    &IOUserNotificationMatchingHandler, NULL );
955 			threadArgs->userNotify->setNotification(notify);
956 		} else {
957 			threadArgs->userNotify->setNotification(NULL);
958 		}
959 	}
960 
961 	threadArgs->userNotify->setNotification(NULL);
962 
963 	IOLockLock(threadArgs->lock);
964 	*threadArgs->completed = *threadArgs->completed + 1;
965 	IOLockWakeup(threadArgs->lock, (event_t)threadArgs->completed, true);
966 	IOLockUnlock(threadArgs->lock);
967 }
968 
969 static int
IOUserNotificationTests(__unused int newValue)970 IOUserNotificationTests(__unused int newValue)
971 {
972 	constexpr size_t numThreads = 10;
973 	constexpr size_t numIterations = 500000;
974 	OSSharedPtr<IOTestUserNotification> userNotify = OSMakeShared<IOTestUserNotification>();
975 	IOLock * lock = IOLockAlloc();
976 	size_t threadsCompleted;
977 	size_t i = 0;
978 	thread_t threads[numThreads];
979 	kern_return_t kr;
980 	bool result;
981 
982 	struct IOUserNotificationTestThreadArgs threadArgs = {
983 		.userNotify = userNotify.get(),
984 		.lock = lock,
985 		.completed = &threadsCompleted,
986 		.iterations = numIterations,
987 	};
988 
989 	result = userNotify->init();
990 	assert(result);
991 
992 	for (i = 0; i < numThreads; i++) {
993 		kr = kernel_thread_start(&IOUserNotificationTestThread, (void *)&threadArgs, &threads[i]);
994 		assert(kr == KERN_SUCCESS);
995 	}
996 
997 	IOLockLock(lock);
998 	while (threadsCompleted < numThreads) {
999 		IOLockSleep(lock, &threadsCompleted, THREAD_UNINT);
1000 		IOLog("%s: Threads completed: %zu/%zu\n", __func__, threadsCompleted, numThreads);
1001 	}
1002 	IOLockUnlock(lock);
1003 
1004 	for (i = 0; i < numThreads; i++) {
1005 		thread_deallocate(threads[i]);
1006 	}
1007 
1008 	userNotify->setNotification(NULL);
1009 
1010 	IOLockFree(lock);
1011 
1012 	return KERN_SUCCESS;
1013 }
1014 
1015 static void
IOServiceMatchingSharedPtrTests()1016 IOServiceMatchingSharedPtrTests()
1017 {
1018 	OSSharedPtr<const OSSymbol> name = OSSymbol::withCString("name");
1019 	OSSharedPtr<const OSSymbol> value = OSSymbol::withCString("value");
1020 
1021 	{
1022 		OSSharedPtr<OSDictionary> table;
1023 		OSSharedPtr<OSDictionary> result = IOService::serviceMatching("name", table);
1024 		assert(result);
1025 		assert(result->getRetainCount() == 1);
1026 
1027 		table = result;
1028 		assert(table->getRetainCount() == 2);
1029 		OSSharedPtr<OSDictionary> result2 = IOService::serviceMatching("name", table);
1030 		assert(result2);
1031 		assert(result2 == table);
1032 		assert(result2->getRetainCount() == 3);
1033 	}
1034 
1035 	{
1036 		OSSharedPtr<OSDictionary> table;
1037 		OSSharedPtr<OSDictionary> result = IOService::serviceMatching(name.get(), table);
1038 		assert(result);
1039 		assert(result->getRetainCount() == 1);
1040 
1041 		table = result;
1042 		assert(table->getRetainCount() == 2);
1043 		OSSharedPtr<OSDictionary> result2 = IOService::serviceMatching(name.get(), table);
1044 		assert(result2);
1045 		assert(result2 == table);
1046 		assert(result2->getRetainCount() == 3);
1047 	}
1048 
1049 	{
1050 		OSSharedPtr<OSDictionary> table;
1051 		OSSharedPtr<OSDictionary> result = IOService::nameMatching("name", table);
1052 		assert(result);
1053 		assert(result->getRetainCount() == 1);
1054 
1055 		table = result;
1056 		assert(table->getRetainCount() == 2);
1057 		OSSharedPtr<OSDictionary> result2 = IOService::nameMatching("name", table);
1058 		assert(result2);
1059 		assert(result2 == table);
1060 		assert(result2->getRetainCount() == 3);
1061 	}
1062 
1063 	{
1064 		OSSharedPtr<OSDictionary> table;
1065 		OSSharedPtr<OSDictionary> result = IOService::nameMatching(name.get(), table);
1066 		assert(result);
1067 		assert(result->getRetainCount() == 1);
1068 
1069 		table = result;
1070 		assert(table->getRetainCount() == 2);
1071 		OSSharedPtr<OSDictionary> result2 = IOService::nameMatching(name.get(), table);
1072 		assert(result2);
1073 		assert(result2 == table);
1074 		assert(result2->getRetainCount() == 3);
1075 	}
1076 
1077 	{
1078 		OSSharedPtr<OSDictionary> table;
1079 		OSSharedPtr<OSDictionary> result = IOService::resourceMatching("name", table);
1080 		assert(result);
1081 		assert(result->getRetainCount() == 1);
1082 
1083 		table = result;
1084 		assert(table->getRetainCount() == 2);
1085 		OSSharedPtr<OSDictionary> result2 = IOService::resourceMatching("name", table);
1086 		assert(result2);
1087 		assert(result2 == table);
1088 		assert(result2->getRetainCount() == 3);
1089 	}
1090 
1091 	{
1092 		OSSharedPtr<OSDictionary> table;
1093 		OSSharedPtr<OSDictionary> result = IOService::resourceMatching(name.get(), table);
1094 		assert(result);
1095 		assert(result->getRetainCount() == 1);
1096 
1097 		table = result;
1098 		assert(table->getRetainCount() == 2);
1099 		OSSharedPtr<OSDictionary> result2 = IOService::resourceMatching(name.get(), table);
1100 		assert(result2);
1101 		assert(result2 == table);
1102 		assert(result2->getRetainCount() == 3);
1103 	}
1104 
1105 	{
1106 		OSSharedPtr<OSDictionary> table;
1107 		OSSharedPtr<OSDictionary> result = IOService::propertyMatching(name.get(), value.get(), table);
1108 		assert(result);
1109 		assert(result->getRetainCount() == 1);
1110 
1111 		table = result;
1112 		assert(table->getRetainCount() == 2);
1113 		OSSharedPtr<OSDictionary> result2 = IOService::propertyMatching(name.get(), value.get(), table);
1114 		assert(result2);
1115 		assert(result2 == table);
1116 		assert(result2->getRetainCount() == 3);
1117 	}
1118 
1119 	{
1120 		OSSharedPtr<OSDictionary> table;
1121 		OSSharedPtr<OSDictionary> result = IOService::registryEntryIDMatching(12, table);
1122 		assert(result);
1123 		assert(result->getRetainCount() == 1);
1124 
1125 		table = result;
1126 		assert(table->getRetainCount() == 2);
1127 		OSSharedPtr<OSDictionary> result2 = IOService::registryEntryIDMatching(12, table);
1128 		assert(result2);
1129 		assert(result2 == table);
1130 		assert(result2->getRetainCount() == 3);
1131 	}
1132 }
1133 
1134 static int
OSSharedPtrTests(int)1135 OSSharedPtrTests(int)
1136 {
1137 	OSDynamicPtrCastTests();
1138 	OSConstPtrCastTests();
1139 	OSStaticPtrCastTests();
1140 	IOServiceMatchingSharedPtrTests();
1141 	return 0;
1142 }
1143 
1144 static int
IOServiceStateNotificationTests(int)1145 IOServiceStateNotificationTests(int)
1146 {
1147 	IOService * service = IOService::getSystemStateNotificationService();
1148 	OSSharedPtr<OSString> str = OSString::withCString(kIOSystemStateClamshellKey);
1149 	kern_return_t kr = service->StateNotificationItemCreate(str.get(), NULL);
1150 	assert(kIOReturnSuccess == kr);
1151 
1152 	void (^sendClam)(OSBoolean * state) = ^void (OSBoolean * state) {
1153 		OSSharedPtr<OSDictionary> value;
1154 		kern_return_t kr;
1155 
1156 		value = OSDictionary::withCapacity(4);
1157 		value->setObject("value", state);
1158 		kr = IOService::getSystemStateNotificationService()->StateNotificationItemSet(str.get(), value.get());
1159 		assert(kIOReturnSuccess == kr);
1160 	};
1161 	sendClam(kOSBooleanTrue);
1162 	IOSleep(100);
1163 	sendClam(kOSBooleanFalse);
1164 
1165 	str = OSString::withCString("test");
1166 	OSSharedPtr<OSArray> array = OSArray::withCapacity(4);
1167 	array->setObject(str.get());
1168 	IOStateNotificationListenerRef listenerRef;
1169 	kr = service->stateNotificationListenerAdd(array.get(), &listenerRef, ^kern_return_t () {
1170 		IOLog("test handler\n");
1171 		kern_return_t kr;
1172 		OSDictionary * dict;
1173 		kr = service->StateNotificationItemCopy(str.get(), &dict);
1174 		if (kIOReturnSuccess == kr) {
1175 		        OSSharedPtr<OSSerialize> s = OSSerialize::withCapacity(4096);
1176 		        dict->serialize(s.get());
1177 		        IOLog("test handler %s\n", s->text());
1178 		}
1179 		return kIOReturnSuccess;
1180 	});
1181 	assert(kIOReturnSuccess == kr);
1182 
1183 	OSSharedPtr<IOEventSource> es =
1184 	    IOServiceStateNotificationEventSource::serviceStateNotificationEventSource(
1185 		service, array.get(),
1186 		^void () {
1187 		IOLog("test es handler\n");
1188 		kern_return_t kr;
1189 		OSDictionary * dict;
1190 		kr = service->StateNotificationItemCopy(str.get(), &dict);
1191 		if (kIOReturnSuccess == kr) {
1192 		        OSSharedPtr<OSSerialize> s = OSSerialize::withCapacity(4096);
1193 		        dict->serialize(s.get());
1194 		        IOLog("test es handler %s\n", s->text());
1195 		}
1196 	});
1197 	assert(es);
1198 	IOService::getPlatform()->getWorkLoop()->addEventSource(es.get());
1199 	es->enable();
1200 	IOSleep(30 * 1000);
1201 	IOService::getPlatform()->getWorkLoop()->removeEventSource(es.get());
1202 
1203 	return kIOReturnSuccess;
1204 }
1205 
1206 static int
IOMallocPageableTests(int)1207 IOMallocPageableTests(int)
1208 {
1209 	vm_size_t size = 0;
1210 	vm_size_t alignment = 0;
1211 
1212 	for (size = 0; size <= 4 * page_size; size += 64) {
1213 		for (alignment = 1; alignment <= page_size; alignment <<= 1) {
1214 			uintptr_t alignMask = alignment - 1;
1215 			void * addr = IOMallocPageable(size, alignment);
1216 			if (addr == NULL) {
1217 				IOLog("IOMallocPageable(size=%u, alignment=%u) failed\n", (uint32_t)size, (uint32_t)alignment);
1218 				return kIOReturnError;
1219 			}
1220 			if (((uintptr_t)addr & alignMask) != 0) {
1221 				IOLog("IOMallocPageable(size=%u, alignment=%u) returned unaligned pointer %p\n", (uint32_t)size, (uint32_t)alignment, addr);
1222 				return kIOReturnError;
1223 			}
1224 			IOFreePageable(addr, size);
1225 
1226 			addr = IOMallocPageableZero(size, alignment);
1227 			if (addr == NULL) {
1228 				IOLog("IOMallocPageableZero(size=%u, alignment=%u) failed\n", (uint32_t)size, (uint32_t)alignment);
1229 				return kIOReturnError;
1230 			}
1231 			if (((uintptr_t)addr & alignMask) != 0) {
1232 				IOLog("IOMallocPageableZero(size=%u, alignment=%u) returned unaligned pointer %p\n", (uint32_t)size, (uint32_t)alignment, addr);
1233 				return kIOReturnError;
1234 			}
1235 			for (char * ptr = (char *)addr; ptr < (char *)addr + size; ptr++) {
1236 				if (*ptr != 0) {
1237 					IOLog("IOMallocPageableZero(size=%u, alignment=%u) -> %p, byte at %p is nonzero\n", (uint32_t)size, (uint32_t)alignment, addr, ptr);
1238 				}
1239 			}
1240 			IOFreePageable(addr, size);
1241 		}
1242 	}
1243 
1244 	return kIOReturnSuccess;
1245 }
1246 
1247 
1248 #endif  /* DEVELOPMENT || DEBUG */
1249 
1250 #ifndef __clang_analyzer__
1251 // All the scary things that this function is doing, such as the intentional
1252 // overrelease of an OSData, are hidden from the static analyzer.
1253 static int
sysctl_iokittest(__unused struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1254 sysctl_iokittest(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1255 {
1256 	int error;
1257 	int newValue, changed;
1258 
1259 	error = sysctl_io_number(req, 0, sizeof(int), &newValue, &changed);
1260 	if (error) {
1261 		return error;
1262 	}
1263 
1264 #if DEVELOPMENT || DEBUG
1265 	if (changed && (66 == newValue)) {
1266 		IOReturn ret;
1267 		OSSharedPtr<IOWorkLoop> wl = IOWorkLoop::workLoop();
1268 		OSSharedPtr<IOCommandGate> cg = IOCommandGate::commandGate(wl.get());
1269 		ret = wl->addEventSource(cg.get());
1270 
1271 		struct x {
1272 			uint64_t h;
1273 			uint64_t l;
1274 		};
1275 		struct x y;
1276 
1277 		y.h = 0x1111111122222222;
1278 		y.l = 0x3333333344444444;
1279 
1280 		kprintf("ret1 %d\n", ret);
1281 		ret = cg->runActionBlock(^(){
1282 			printf("hello %d 0x%qx\n", wl->inGate(), y.h);
1283 			return 99;
1284 		});
1285 		kprintf("ret %d\n", ret);
1286 	}
1287 
1288 	if (changed && (999 == newValue)) {
1289 		OSSharedPtr<OSData> data = OSData::withCapacity(16);
1290 		data->release();
1291 	}
1292 
1293 	if (changed && (newValue >= 6666) && (newValue <= 6669)) {
1294 		OSSharedPtr<OSIterator> iter;
1295 		IOService  * service;
1296 
1297 		service = NULL;
1298 		OSSharedPtr<OSDictionary> matchingDict = IOService::nameMatching("XHC1");
1299 		iter = IOService::getMatchingServices(matchingDict.get());
1300 		if (iter && (service = (IOService *) iter->getNextObject())) {
1301 			if (newValue == 6666) {
1302 				IOLog("terminating 0x%qx\n", service->getRegistryEntryID());
1303 				service->terminate();
1304 			} else if (newValue == 6667) {
1305 				IOLog("register 0x%qx\n", service->getRegistryEntryID());
1306 				service->registerService();
1307 			}
1308 		}
1309 		if (service) {
1310 			return 0;
1311 		}
1312 	}
1313 
1314 
1315 	if (changed && (555 == newValue)) {
1316 		IOServiceStateNotificationTests(newValue);
1317 	}
1318 
1319 	if (changed && newValue) {
1320 		error = IOWorkLoopTest(newValue);
1321 		assert(KERN_SUCCESS == error);
1322 		error = IOServiceTest(newValue);
1323 		assert(KERN_SUCCESS == error);
1324 		error = OSCollectionTest(newValue);
1325 		assert(KERN_SUCCESS == error);
1326 		error = OSCollectionIteratorTests(newValue);
1327 		assert(KERN_SUCCESS == error);
1328 		error = OSAllocationTests(newValue);
1329 		assert(KERN_SUCCESS == error);
1330 		error = OSDataAllocationTests(newValue);
1331 		assert(KERN_SUCCESS == error);
1332 		error = OSBoundedArrayTests(newValue);
1333 		assert(KERN_SUCCESS == error);
1334 		error = OSBoundedArrayRefTests(newValue);
1335 		assert(KERN_SUCCESS == error);
1336 		error = OSBoundedPtrTests(newValue);
1337 		assert(KERN_SUCCESS == error);
1338 		error = OSValueObjectTests(newValue);
1339 		assert(KERN_SUCCESS == error);
1340 		error = IOMemoryDescriptorTest(newValue);
1341 		assert(KERN_SUCCESS == error);
1342 		error = OSSharedPtrTests(newValue);
1343 		assert(KERN_SUCCESS == error);
1344 		error = IOSharedDataQueue_44636964(newValue);
1345 		assert(KERN_SUCCESS == error);
1346 		error = IOUserNotificationTests(newValue);
1347 		assert(KERN_SUCCESS == error);
1348 		error = IOMallocPageableTests(newValue);
1349 		assert(KERN_SUCCESS == error);
1350 	}
1351 #endif  /* DEVELOPMENT || DEBUG */
1352 
1353 	return error;
1354 }
1355 
1356 SYSCTL_PROC(_kern, OID_AUTO, iokittest,
1357     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1358     NULL, 0, sysctl_iokittest, "I", "");
1359 #endif // __clang_analyzer__
1360 
1361 #if DEVELOPMENT || DEBUG
1362 
1363 /*
1364  * A simple wrapper around an IOService. This terminates the IOService in free().
1365  */
1366 class TestIOServiceHandle : public OSObject
1367 {
1368 	OSDeclareDefaultStructors(TestIOServiceHandle);
1369 public:
1370 	static TestIOServiceHandle * withService(IOService * service);
1371 
1372 private:
1373 	bool initWithService(IOService * service);
1374 	virtual void free() APPLE_KEXT_OVERRIDE;
1375 
1376 	IOService * fService;
1377 };
1378 
1379 OSDefineMetaClassAndStructors(TestIOServiceHandle, OSObject);
1380 
1381 TestIOServiceHandle *
withService(IOService * service)1382 TestIOServiceHandle::withService(IOService * service)
1383 {
1384 	TestIOServiceHandle * handle = new TestIOServiceHandle;
1385 	if (handle && !handle->initWithService(service)) {
1386 		return NULL;
1387 	}
1388 	return handle;
1389 }
1390 
1391 bool
initWithService(IOService * service)1392 TestIOServiceHandle::initWithService(IOService * service)
1393 {
1394 	fService = service;
1395 	fService->retain();
1396 	return true;
1397 }
1398 
1399 void
free()1400 TestIOServiceHandle::free()
1401 {
1402 	if (fService) {
1403 		fService->terminate();
1404 		OSSafeReleaseNULL(fService);
1405 	}
1406 }
1407 
1408 /*
1409  * Set up test IOServices. See the available services in xnu/iokit/Tests/TestServices.
1410  *
1411  * xnu darwintests use this sysctl to make these test services available. A send right is pushed
1412  * to the task that called the sysctl, which when deallocated removes the service. This ensures
1413  * that the registry isn't polluted by misbehaving tests.
1414  *
1415  * Since this sysctl allows callers to instantiate arbitrary classes based on their class name,
1416  * this can be a security concern. Tests that call this sysctl need the
1417  * kIOServiceTestServiceManagementEntitlementKey entitlement.
1418  */
1419 static int
sysctl_iokit_test_service_setup(struct sysctl_oid * oidp,__unused void * arg1,__unused int arg2,struct sysctl_req * req)1420 sysctl_iokit_test_service_setup(struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1421 {
1422 	char classname[128] = {0};
1423 	IOService * service; // must not release
1424 	OSObject * obj = NULL; // must release
1425 	IOService * provider = NULL; // must not release
1426 	TestIOServiceHandle * handle = NULL; // must release
1427 	mach_port_name_t name __unused;
1428 	int error;
1429 
1430 	if (!IOTaskHasEntitlement(current_task(), kIOServiceTestServiceManagementEntitlementKey)) {
1431 		error = EPERM;
1432 		goto finish;
1433 	}
1434 
1435 	error = sysctl_handle_string(oidp, classname, sizeof(classname), req);
1436 	if (error != 0) {
1437 		goto finish;
1438 	}
1439 
1440 	/*
1441 	 * All test services currently attach to IOResources.
1442 	 */
1443 	provider = IOService::getResourceService();
1444 	if (!provider) {
1445 		IOLog("Failed to find IOResources\n");
1446 		error = ENOENT;
1447 		goto finish;
1448 	}
1449 
1450 	obj = OSMetaClass::allocClassWithName(classname);
1451 	if (!obj) {
1452 		IOLog("Failed to alloc class %s\n", classname);
1453 		error = ENOENT;
1454 		goto finish;
1455 	}
1456 
1457 	service = OSDynamicCast(IOService, obj);
1458 
1459 	if (!service) {
1460 		IOLog("Instance of class %s is not an IOService\n", classname);
1461 		error = EINVAL;
1462 		goto finish;
1463 	}
1464 
1465 	if (!service->init()) {
1466 		IOLog("Failed to initialize %s\n", classname);
1467 		error = EINVAL;
1468 		goto finish;
1469 	}
1470 
1471 	if (!service->attach(provider)) {
1472 		IOLog("Failed to attach %s\n", classname);
1473 		error = EINVAL;
1474 		goto finish;
1475 	}
1476 
1477 	if (!service->start(provider)) {
1478 		IOLog("Failed to start %s\n", classname);
1479 		error = EINVAL;
1480 		goto finish;
1481 	}
1482 
1483 	handle = TestIOServiceHandle::withService(service);
1484 	if (!handle) {
1485 		IOLog("Failed to create service handle\n");
1486 		error = ENOMEM;
1487 		goto finish;
1488 	}
1489 	name = iokit_make_send_right(current_task(), handle, IKOT_IOKIT_OBJECT);
1490 
1491 	error = 0;
1492 
1493 finish:
1494 
1495 	OSSafeReleaseNULL(obj);
1496 	OSSafeReleaseNULL(handle);
1497 	return error;
1498 }
1499 
1500 
1501 SYSCTL_PROC(_kern, OID_AUTO, iokit_test_service_setup,
1502     CTLTYPE_STRING | CTLFLAG_WR | CTLFLAG_KERN | CTLFLAG_LOCKED,
1503     NULL, 0, sysctl_iokit_test_service_setup, "-", "");
1504 
1505 #endif /* DEVELOPMENT || DEBUG */
1506 
1507 
1508 static __unused void
CastCompileTest(OSObject * obj)1509 CastCompileTest(OSObject *obj)
1510 {
1511 	IOService * service1 = OSDynamicCast(IOService, obj);
1512 	if (service1) {
1513 		service1->terminate();
1514 	}
1515 	IOService *service2 = OSRequiredCast(IOService, obj);
1516 	if (service2) {
1517 		service2->terminate();
1518 	}
1519 }
1520