]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Tests/Tests.cpp
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / iokit / Tests / Tests.cpp
index 5e570cc273a9ea14822964a971cd8966cc8a7c04..ac67b43b553c8d26d1dd0e23da2800bdad2e7d80 100644 (file)
 /*
  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  *
  */
 
-#include <IOKit/IODeviceTreeSupport.h>
+#define TEST_HEADERS    0
+
+#if TEST_HEADERS
+
+#include <libkern/OSByteOrder.h>
+#include <libkern/c++/OSArray.h>
+#include <libkern/c++/OSAllocation.h>
+#include <libkern/c++/OSBoolean.h>
+#include <libkern/c++/OSBoundedArray.h>
+#include <libkern/c++/OSBoundedArrayRef.h>
+#include <libkern/c++/OSBoundedPtr.h>
+#include <libkern/c++/OSCollection.h>
+#include <libkern/c++/OSCollectionIterator.h>
 #include <libkern/c++/OSContainers.h>
+#include <libkern/c++/OSCPPDebug.h>
+#include <libkern/c++/OSData.h>
+#include <libkern/c++/OSDictionary.h>
+#include <libkern/c++/OSEndianTypes.h>
+#include <libkern/c++/OSIterator.h>
+#include <libkern/c++/OSKext.h>
+#include <libkern/c++/OSLib.h>
+#include <libkern/c++/OSMetaClass.h>
+#include <libkern/c++/OSNumber.h>
+#include <libkern/c++/OSObject.h>
+#include <libkern/c++/OSOrderedSet.h>
+#include <libkern/c++/OSSerialize.h>
+#include <libkern/c++/OSSet.h>
+#include <libkern/c++/OSSharedPtr.h>
+#include <libkern/c++/OSString.h>
+#include <libkern/c++/OSSymbol.h>
+#include <libkern/c++/OSUnserialize.h>
+#include <libkern/crypto/aes.h>
+#include <libkern/crypto/aesxts.h>
+#include <libkern/crypto/crypto_internal.h>
+#include <libkern/crypto/des.h>
+#include <libkern/crypto/md5.h>
+#include <libkern/crypto/register_crypto.h>
+#include <libkern/crypto/sha1.h>
+#include <libkern/crypto/sha2.h>
+#include <libkern/kernel_mach_header.h>
+#include <libkern/kext_request_keys.h>
+#include <libkern/kxld.h>
+#include <libkern/kxld_types.h>
+#include <libkern/locks.h>
+#include <libkern/mkext.h>
+#include <libkern/OSAtomic.h>
+#include <libkern/OSBase.h>
+#include <libkern/OSDebug.h>
+#include <libkern/OSKextLib.h>
+#include <libkern/OSKextLibPrivate.h>
+#include <libkern/OSReturn.h>
+#include <libkern/OSSerializeBinary.h>
+#include <libkern/OSTypes.h>
+#include <libkern/prelink.h>
+#include <libkern/stack_protector.h>
+#include <libkern/sysctl.h>
+#include <libkern/tree.h>
+#include <libkern/zconf.h>
+#include <libkern/zlib.h>
+
+#include <IOKit/AppleKeyStoreInterface.h>
+#include <IOKit/assert.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/IOBufferMemoryDescriptor.h>
+#include <IOKit/IOCatalogue.h>
+#include <IOKit/IOCommand.h>
+#include <IOKit/IOCommandGate.h>
+#include <IOKit/IOCommandPool.h>
+#include <IOKit/IOCommandQueue.h>
+#include <IOKit/IOConditionLock.h>
+#include <IOKit/IOCPU.h>
+//#include <IOKit/IODataQueue.h>
+#include <IOKit/IODataQueueShared.h>
+#include <IOKit/IODeviceMemory.h>
+#include <IOKit/IODeviceTreeSupport.h>
+#include <IOKit/IODMACommand.h>
+#include <IOKit/IODMAController.h>
+#include <IOKit/IODMAEventSource.h>
+#include <IOKit/IOEventSource.h>
+#include <IOKit/IOFilterInterruptEventSource.h>
+#include <IOKit/IOHibernatePrivate.h>
+#include <IOKit/IOInterleavedMemoryDescriptor.h>
+#include <IOKit/IOInterruptAccounting.h>
+#include <IOKit/IOInterruptAccountingPrivate.h>
+#include <IOKit/IOInterruptController.h>
+#include <IOKit/IOInterruptEventSource.h>
+#include <IOKit/IOInterrupts.h>
+#include <IOKit/IOKernelReporters.h>
+#include <IOKit/IOKernelReportStructs.h>
+#include <IOKit/IOKitDebug.h>
+#include <IOKit/IOKitDiagnosticsUserClient.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/IOKitKeysPrivate.h>
+#include <IOKit/IOKitServer.h>
 #include <IOKit/IOLib.h>
+#include <IOKit/IOLocks.h>
+#include <IOKit/IOLocksPrivate.h>
+#include <IOKit/IOMapper.h>
+#include <IOKit/IOMemoryCursor.h>
+#include <IOKit/IOMemoryDescriptor.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/IOMultiMemoryDescriptor.h>
+#include <IOKit/IONotifier.h>
+#include <IOKit/IONVRAM.h>
+#include <IOKit/IOPlatformExpert.h>
+#include <IOKit/IOPolledInterface.h>
+#include <IOKit/IORangeAllocator.h>
+#include <IOKit/IORegistryEntry.h>
+#include <IOKit/IOReportMacros.h>
+#include <IOKit/IOReportTypes.h>
+#include <IOKit/IOReturn.h>
+#include <IOKit/IOService.h>
+#include <IOKit/IOServicePM.h>
+#include <IOKit/IOSharedDataQueue.h>
+#include <IOKit/IOSharedLock.h>
+#include <IOKit/IOStatistics.h>
+#include <IOKit/IOStatisticsPrivate.h>
+#include <IOKit/IOSubMemoryDescriptor.h>
+#include <IOKit/IOSyncer.h>
+#include <IOKit/IOTimerEventSource.h>
+#include <IOKit/IOTimeStamp.h>
+#include <IOKit/IOTypes.h>
+#include <IOKit/IOUserClient.h>
+#include <IOKit/IOWorkLoop.h>
+#include <IOKit/nvram/IONVRAMController.h>
+#include <IOKit/OSMessageNotification.h>
+#include <IOKit/platform/AppleMacIO.h>
+#include <IOKit/platform/AppleMacIODevice.h>
+#include <IOKit/platform/AppleNMI.h>
+#include <IOKit/platform/ApplePlatformExpert.h>
+#include <IOKit/power/IOPwrController.h>
+#include <IOKit/pwr_mgt/IOPM.h>
+#include <IOKit/pwr_mgt/IOPMinformee.h>
+#include <IOKit/pwr_mgt/IOPMinformeeList.h>
+#include <IOKit/pwr_mgt/IOPMLibDefs.h>
+#include <IOKit/pwr_mgt/IOPMlog.h>
+#include <IOKit/pwr_mgt/IOPMPowerSource.h>
+#include <IOKit/pwr_mgt/IOPMPowerSourceList.h>
+#include <IOKit/pwr_mgt/IOPMpowerState.h>
+#include <IOKit/pwr_mgt/IOPMPrivate.h>
+#include <IOKit/pwr_mgt/IOPowerConnection.h>
+#include <IOKit/pwr_mgt/RootDomain.h>
+#include <IOKit/rtc/IORTCController.h>
+#include <IOKit/system.h>
+#include <IOKit/system_management/IOWatchDogTimer.h>
+
+#endif /* TEST_HEADERS */
+
+#include <sys/sysctl.h>
+#include <libkern/c++/OSData.h>
+#include "Tests.h"
+
 
-#include <assert.h>
-
-
-extern "C" {
-extern int debug_container_malloc_size;
-extern int debug_ivars_size;
-}
-
-static void DumpTree( void )
+#if DEVELOPMENT || DEBUG
+
+#include <IOKit/IOWorkLoop.h>
+#include <IOKit/IOTimerEventSource.h>
+#include <IOKit/IOInterruptEventSource.h>
+#include <IOKit/IOCommandGate.h>
+#include <IOKit/IOPlatformExpert.h>
+#include <IOKit/IOSharedDataQueue.h>
+#include <IOKit/IODataQueueShared.h>
+#include <libkern/Block.h>
+#include <libkern/Block_private.h>
+#include <libkern/c++/OSAllocation.h>
+#include <libkern/c++/OSBoundedArray.h>
+#include <libkern/c++/OSBoundedArrayRef.h>
+#include <libkern/c++/OSBoundedPtr.h>
+#include <libkern/c++/OSSharedPtr.h>
+#include <os/cpp_util.h>
+
+static uint64_t gIOWorkLoopTestDeadline;
+
+static void
+TESAction(OSObject * owner, IOTimerEventSource * tes)
 {
-    IORegistryEntry *          next;
-    IORegistryEntry *          packages = 0;
-    IORegistryEntry *          deblocker = 0;
-    IORegistryEntry *          keyboard = 0;
-    IORegistryIterator *       iter;
-    OSOrderedSet *             all;
+       if (mach_absolute_time() < gIOWorkLoopTestDeadline) {
+               tes->setTimeout(1, kMicrosecondScale);
+       }
+}
+
+static int
+IOWorkLoopTest(int newValue)
+{
+       IOReturn err;
+       uint32_t idx;
+       IOWorkLoop * wl;
+       IOTimerEventSource * tes;
+       IOInterruptEventSource * ies;
+
+       wl = IOWorkLoop::workLoop();
+       assert(wl);
+       tes = IOTimerEventSource::timerEventSource(kIOTimerEventSourceOptionsPriorityWorkLoop, wl, &TESAction);
+       assert(tes);
+       err = wl->addEventSource(tes);
+       assert(kIOReturnSuccess == err);
+       clock_interval_to_deadline(100, kMillisecondScale, &gIOWorkLoopTestDeadline);
+       for (idx = 0; mach_absolute_time() < gIOWorkLoopTestDeadline; idx++) {
+               tes->setTimeout(idx & 1023, kNanosecondScale);
+       }
+       tes->cancelTimeout();
+       wl->removeEventSource(tes);
+       tes->release();
+
+       int value = 3;
 
-    IOLog("ivars %08x, containers %08x\n",
-       debug_ivars_size, debug_container_malloc_size);
+       tes = IOTimerEventSource::timerEventSource(kIOTimerEventSourceOptionsDefault, wl, ^(IOTimerEventSource * tes){
+               kprintf("wl %p, value %d\n", wl, value);
+       });
+       err = wl->addEventSource(tes);
+       assert(kIOReturnSuccess == err);
 
-    iter = IORegistryIterator::iterateOver( gIODTPlane );
-    assert( iter );
+       value = 2;
+       tes->setTimeout(1, kNanosecondScale);
+       IOSleep(1);
+       wl->removeEventSource(tes);
+       tes->release();
 
-    all = iter->iterateAll();
-    IOLog("\nCount %d\n", all->getCount() );
-    all->release();
-
-    iter->reset();
-    while( (next = iter->nextEntryRecursive())) {
-       if( 0 == strcmp( "packages", next->getName()))
-           packages = next;
-       if( 0 == strcmp( "deblocker", next->getName()))
-           deblocker = next;
-       if( 0 == strcmp( "keyboard", next->getName()))
-           keyboard = next;
-    }
+       ies = IOInterruptEventSource::interruptEventSource(wl, NULL, 0, ^void (IOInterruptEventSource *sender, int count){
+               kprintf("ies block %p, %d\n", sender, count);
+       });
 
-    if( deblocker && keyboard)
-       deblocker->attachToParent( keyboard, gIODTPlane);
+       assert(ies);
+       kprintf("ies %p\n", ies);
+       err = wl->addEventSource(ies);
+       assert(kIOReturnSuccess == err);
+       ies->interruptOccurred(NULL, NULL, 0);
+       IOSleep(1);
+       ies->interruptOccurred(NULL, NULL, 0);
+       IOSleep(1);
+       wl->removeEventSource(ies);
+       ies->release();
 
-    iter->reset();
-    while( (next = iter->nextEntryRecursive())) {
-       IOLog("%s=%d,", next->getName(), next->getDepth( gIODTPlane ));
-       if( 0 == strcmp( "gc", next->getName())) {
-           packages = next;
+       wl->release();
+
+       return 0;
+}
+
+static int
+OSCollectionTest(int newValue)
+{
+       OSArray * array = OSArray::withCapacity(8);
+       array->setObject(kOSBooleanTrue);
+       array->setObject(kOSBooleanFalse);
+       array->setObject(kOSBooleanFalse);
+       array->setObject(kOSBooleanTrue);
+       array->setObject(kOSBooleanFalse);
+       array->setObject(kOSBooleanTrue);
+
+       __block unsigned int index;
+       index = 0;
+       array->iterateObjects(^bool (OSObject * obj) {
+               kprintf("%d:%d ", index, (obj == kOSBooleanTrue) ? 1 : (obj == kOSBooleanFalse) ? 0 : 2);
+               index++;
+               return false;
+       });
+       kprintf("\n");
+       array->release();
+
+       OSDictionary * dict = IOService::resourceMatching("hello");
+       assert(dict);
+       index = 0;
+       dict->iterateObjects(^bool (const OSSymbol * sym, OSObject * obj) {
+               OSString * str = OSDynamicCast(OSString, obj);
+               assert(str);
+               kprintf("%d:%s=%s\n", index, sym->getCStringNoCopy(), str->getCStringNoCopy());
+               index++;
+               return false;
+       });
+       dict->release();
+
+       OSSerializer * serializer = OSSerializer::withBlock(^bool (OSSerialize * s){
+               return gIOBSDUnitKey->serialize(s);
+       });
+       assert(serializer);
+       IOService::getPlatform()->setProperty("OSSerializer_withBlock", serializer);
+       serializer->release();
+
+       return 0;
+}
+
+static int
+OSAllocationTests(int)
+{
+       OSAllocation<int> ints(100, OSAllocateMemory);
+       assert(ints);
+
+       {
+               int counter = 0;
+               for (int& i : ints) {
+                       i = counter++;
+               }
+       }
+
+       {
+               int counter = 0;
+               for (int& i : ints) {
+                       assert(i == counter);
+                       ++counter;
+               }
+       }
+
+       // Make sure we can have two-level OSAllocations
+       {
+               OSAllocation<OSAllocation<int> > testArray(10, OSAllocateMemory);
+               for (int i = 0; i < 10; i++) {
+                       testArray[i] = OSAllocation<int>(10, OSAllocateMemory);
+                       for (int j = 0; j < 10; ++j) {
+                               testArray[i][j] = i + j;
+                       }
+               }
+
+               for (int i = 0; i < 10; i++) {
+                       for (int j = 0; j < 10; ++j) {
+                               assert(testArray[i][j] == i + j);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int
+OSBoundedArrayTests(int)
+{
+       OSBoundedArray<int, 5> ints = {0, 1, 2, 3, 4};
+       assert(ints.size() == 5);
+
+       {
+               int counter = 0;
+               for (int& i : ints) {
+                       i = counter++;
+               }
+       }
+
+       {
+               int counter = 0;
+               for (int& i : ints) {
+                       assert(i == counter);
+                       ++counter;
+               }
        }
-    }
 
-    IOLog("ivars %08x, containers %08x\n",
-       debug_ivars_size, debug_container_malloc_size);
+       return 0;
+}
 
-    if( packages)
-       packages->detachAll( gIODTPlane);
-    all = iter->iterateAll();
-    IOLog("del gc/, count now %d\n", all->getCount() );
-    all->release();
+static int
+OSBoundedArrayRefTests(int)
+{
+       OSBoundedArray<int, 5> storage = {0, 1, 2, 3, 4};
+       OSBoundedArrayRef<int> ints(storage);
+       assert(ints);
 
-    iter->release();
+       {
+               int counter = 0;
+               for (int& i : ints) {
+                       i = counter++;
+               }
+       }
 
-    IOLog("ivars %08x, containers %08x\n",
-       debug_ivars_size, debug_container_malloc_size);
+       {
+               int counter = 0;
+               for (int& i : ints) {
+                       assert(i == counter);
+                       ++counter;
+               }
+       }
 
+       return 0;
 }
 
-extern "C" {
-void PathTests( void )
+static int
+OSBoundedPtrTests(int)
 {
-    const char * tests[] = {
-        "IODeviceTree:/bandit",
-        "IODeviceTree:/",
-       "IODeviceTree:/xxxx",
-       "IODeviceTree:/bandit/xxx",
-        "IODeviceTree:/bandit@F2000000",
-        "IODeviceTree:/bandit/gc",
-        "IODeviceTree:/bandit/gc/mace:17.202.42.95,\\mach_kernel",
-        "IODeviceTree:/bandit/@10/mesh",
-        "IODeviceTree:enet:17.202",
-        "IODeviceTree:scsi/@0:0",
-        "IODeviceTree:scsi-int",
-        "IODeviceTree:/bandit/gc@10/mesh",
-        "IODeviceTree:/bandit/gc/53c94/disk@0:6,mach_kernel",
-        "IOService:/",
-        "IOService:/ApplePlatformExpert",
-        "IOService:/ApplePlatformExpert/hammerhead@F8000000",
-        "IOService:/ApplePlatformExpert/bandit/AppleMacRiscPCI"
-    };
+       int array[5] = {55, 66, 77, 88, 99};
+       OSBoundedPtr<int> begin(&array[0], &array[0], &array[5]);
+       OSBoundedPtr<int> end(&array[5], &array[0], &array[5]);
+
+       {
+               int counter = 0;
+               for (OSBoundedPtr<int> b = begin; b != end; ++b) {
+                       *b = counter++;
+               }
+       }
 
-    IORegistryEntry *  entry;
-    char               str[256];
-    int                        len;
+       {
+               int counter = 0;
+               for (OSBoundedPtr<int> b = begin; b != end; ++b) {
+                       assert(*b == counter);
+                       ++counter;
+               }
+       }
+
+       return 0;
+}
+
+static int
+IOSharedDataQueue_44636964(__unused int newValue)
+{
+       IOSharedDataQueue* sd = IOSharedDataQueue::withCapacity(DATA_QUEUE_ENTRY_HEADER_SIZE + sizeof(UInt64));
+       UInt64 data = 0x11223344aa55aa55;
+       UInt32 data2 = 0x44332211;
+       UInt32 size = sizeof(UInt32);
+       /* enqueue moves tail to end */
+       sd->enqueue(&data, sizeof(UInt64));
+       /* dequeue moves head to end */
+       sd->dequeue(&data, &size);
+       /* Tail wraps around, head is still at end */
+       sd->enqueue(&data2, sizeof(UInt32));
+       /* something in the queue so peek() should return non-null */
+       assert(sd->peek() != NULL);
+       return KERN_SUCCESS;
+}
+
+#if 0
+#include <IOKit/IOUserClient.h>
+class TestUserClient : public IOUserClient
+{
+       OSDeclareDefaultStructors(TestUserClient);
+       virtual void stop( IOService *provider) APPLE_KEXT_OVERRIDE;
+       virtual bool finalize(IOOptionBits options) APPLE_KEXT_OVERRIDE;
+       virtual IOReturn externalMethod( uint32_t selector,
+           IOExternalMethodArguments * arguments,
+           IOExternalMethodDispatch * dispatch,
+           OSObject * target,
+           void * reference ) APPLE_KEXT_OVERRIDE;
+};
 
-    for( unsigned int i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
+void
+TestUserClient::stop( IOService *provider)
+{
+       kprintf("TestUserClient::stop\n");
+}
+bool
+TestUserClient::finalize(IOOptionBits options)
+{
+       kprintf("TestUserClient::finalize\n");
+       return true;
+}
+IOReturn
+TestUserClient::externalMethod( uint32_t selector,
+    IOExternalMethodArguments * arguments,
+    IOExternalMethodDispatch * dispatch,
+    OSObject * target,
+    void * reference )
+{
+       getProvider()->terminate();
+       IOSleep(500);
+       return 0;
+}
+OSDefineMetaClassAndStructors(TestUserClient, IOUserClient);
+#endif
+
+static int
+IOServiceTest(int newValue)
+{
+       OSDictionary      * matching;
+       IONotifier        * note;
+       __block IOService * found;
+
+#if 0
+       found = new IOService;
+       found->init();
+       found->setName("IOTestUserClientProvider");
+       found->attach(IOService::getPlatform());
+       found->setProperty("IOUserClientClass", "TestUserClient");
+       found->registerService();
+#endif
+
+       matching = IOService::serviceMatching("IOPlatformExpert");
+       assert(matching);
+       found = nullptr;
+       note = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0,
+           ^bool (IOService * newService, IONotifier * notifier) {
+               kprintf("found %s, %d\n", newService->getName(), newService->getRetainCount());
+               found = newService;
+               found->retain();
+               return true;
+       }
+           );
+       assert(note);
+       assert(found);
+       matching->release();
+       note->remove();
+
+       note = found->registerInterest(gIOBusyInterest,
+           ^IOReturn (uint32_t messageType, IOService * provider,
+           void   * messageArgument, size_t argSize) {
+               kprintf("%p messageType 0x%08x %p\n", provider, messageType, messageArgument);
+               return kIOReturnSuccess;
+       });
+       assert(note);
+       IOSleep(1 * 1000);
+       note->remove();
+       found->release();
+
+       return 0;
+}
+
+static void
+OSStaticPtrCastTests()
+{
+       // const& overload
+       {
+               OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
+               OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
+               assert(collection == dict);
+       }
+       {
+               OSSharedPtr<OSDictionary> const dict = nullptr;
+               OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(dict);
+               assert(collection == nullptr);
+       }
+       // && overload
+       {
+               OSSharedPtr<OSDictionary> dict = OSMakeShared<OSDictionary>();
+               OSDictionary* oldDict = dict.get();
+               OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
+               assert(collection.get() == oldDict);
+               assert(dict == nullptr);
+       }
+       {
+               OSSharedPtr<OSDictionary> dict = nullptr;
+               OSSharedPtr<OSCollection> collection = OSStaticPtrCast<OSCollection>(os::move(dict));
+               assert(collection == nullptr);
+               assert(dict == nullptr);
+       }
+}
+
+static void
+OSConstPtrCastTests()
+{
+       // const& overload
+       {
+               OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
+               OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
+               assert(dict2 == dict);
+       }
+       {
+               OSSharedPtr<OSDictionary const> const dict = OSMakeShared<OSDictionary>();
+               OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
+               assert(dict2 == dict);
+       }
+       {
+               OSSharedPtr<OSDictionary const> const dict = nullptr;
+               OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(dict);
+               assert(dict2 == nullptr);
+       }
+       {
+               OSSharedPtr<OSDictionary const> const dict = nullptr;
+               OSSharedPtr<OSDictionary const> dict2 = OSConstPtrCast<OSDictionary const>(dict);
+               assert(dict2 == nullptr);
+       }
+
+       // && overload
+       {
+               OSSharedPtr<OSDictionary const> dict = OSMakeShared<OSDictionary>();
+               OSDictionary const* oldDict = dict.get();
+               OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
+               assert(dict == nullptr);
+               assert(dict2 == oldDict);
+       }
+       {
+               OSSharedPtr<OSDictionary const> dict = nullptr;
+               OSSharedPtr<OSDictionary> dict2 = OSConstPtrCast<OSDictionary>(os::move(dict));
+               assert(dict == nullptr);
+               assert(dict2 == nullptr);
+       }
+}
+
+static void
+OSDynamicPtrCastTests()
+{
+       OSSharedPtr<OSDictionary> const dict = OSMakeShared<OSDictionary>();
+       {
+               OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
+               assert(collection != nullptr);
+       }
+       {
+               OSSharedPtr<OSArray> array = OSDynamicPtrCast<OSArray>(dict);
+               assert(array == nullptr);
+               assert(dict != nullptr);
+       }
+       {
+               OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
+               OSTaggedSharedPtr<OSCollection, OSCollection> collection = OSDynamicPtrCast<OSCollection>(taggedDict);
+               assert(collection != nullptr);
+       }
+       {
+               OSTaggedSharedPtr<OSCollection, OSCollection> taggedDict(dict.get(), OSRetain);
+               OSTaggedSharedPtr<OSArray, OSCollection> array = OSDynamicPtrCast<OSArray>(taggedDict);
+               assert(array == nullptr);
+               assert(dict != nullptr);
+       }
+       {
+               OSSharedPtr<OSCollection> collection = OSDynamicPtrCast<OSCollection>(dict);
+               assert(collection.get() == OSDynamicCast(OSDictionary, dict.get()));
+               OSSharedPtr<OSDictionary> newDict = OSDynamicPtrCast<OSDictionary>(os::move(collection));
+               assert(collection == nullptr);
+               assert(newDict != nullptr);
+               assert(newDict.get() == dict.get());
+       }
+}
+
+static int
+OSSharedPtrTests(int)
+{
+       OSDynamicPtrCastTests();
+       OSConstPtrCastTests();
+       OSStaticPtrCastTests();
+       return 0;
+}
+
+#endif  /* DEVELOPMENT || DEBUG */
+
+#ifndef __clang_analyzer__
+// All the scary things that this function is doing, such as the intentional
+// overrelease of an OSData, are hidden from the static analyzer.
+static int
+sysctl_iokittest(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
+{
+       int error;
+       int newValue, changed;
+
+       error = sysctl_io_number(req, 0, sizeof(int), &newValue, &changed);
+       if (error) {
+               return error;
+       }
+
+#if DEVELOPMENT || DEBUG
+       if (changed && (66 == newValue)) {
+               IOReturn ret;
+               IOWorkLoop * wl = IOWorkLoop::workLoop();
+               IOCommandGate * cg = IOCommandGate::commandGate(wl);
+               ret = wl->addEventSource(cg);
+
+               struct x {
+                       uint64_t h;
+                       uint64_t l;
+               };
+               struct x y;
+
+               y.h = 0x1111111122222222;
+               y.l = 0x3333333344444444;
+
+               kprintf("ret1 %d\n", ret);
+               ret = cg->runActionBlock(^(){
+                       printf("hello %d 0x%qx\n", wl->inGate(), y.h);
+                       return 99;
+               });
+               kprintf("ret %d\n", ret);
+       }
+
+       if (changed && (999 == newValue)) {
+               OSData * data = OSData::withCapacity(16);
+               data->release();
+               data->release();
+       }
+
+       if (changed && (newValue >= 6666) && (newValue <= 6669)) {
+               OSIterator * iter;
+               IOService  * service;
+
+               service = NULL;
+               iter = IOService::getMatchingServices(IOService::nameMatching("XHC1"));
+               if (iter && (service = (IOService *) iter->getNextObject())) {
+                       if (newValue == 6666) {
+                               IOLog("terminating 0x%qx\n", service->getRegistryEntryID());
+                               service->terminate();
+                       } else if (newValue == 6667) {
+                               IOLog("register 0x%qx\n", service->getRegistryEntryID());
+                               service->registerService();
+                       }
+               }
+               OSSafeReleaseNULL(iter);
+               if (service) {
+                       return 0;
+               }
+       }
+
+
+       if (changed && newValue) {
+               error = IOWorkLoopTest(newValue);
+               assert(KERN_SUCCESS == error);
+               error = IOServiceTest(newValue);
+               assert(KERN_SUCCESS == error);
+               error = OSCollectionTest(newValue);
+               assert(KERN_SUCCESS == error);
+               error = OSAllocationTests(newValue);
+               assert(KERN_SUCCESS == error);
+               error = OSBoundedArrayTests(newValue);
+               assert(KERN_SUCCESS == error);
+               error = OSBoundedArrayRefTests(newValue);
+               assert(KERN_SUCCESS == error);
+               error = OSBoundedPtrTests(newValue);
+               assert(KERN_SUCCESS == error);
+               error = IOMemoryDescriptorTest(newValue);
+               assert(KERN_SUCCESS == error);
+               error = OSSharedPtrTests(newValue);
+               assert(KERN_SUCCESS == error);
+               error = IOSharedDataQueue_44636964(newValue);
+               assert(KERN_SUCCESS == error);
+       }
+#endif  /* DEVELOPMENT || DEBUG */
 
-       len = sizeof( str );
-       entry = IORegistryEntry::fromPath( tests[i], 0, str, &len );
-        IOLog("\"%s\" ", tests[i] );
-       if( entry) {
-           IOLog("found %s, tail = \"%s\"\n", entry->getName(), str );
-            len = sizeof( str );
-           if( entry->getPath( str, &len,
-                       IORegistryEntry::getPlane("IODeviceTree"))) {
-               IOLog("path = \"%s\"\n", str);
-           }
-           entry->release();
-       } else
-           IOLog("not found\n");
-    }
-}
-}
-
-void TestsCpp( void * dtTop )
-{
-    IORegistryEntry * dt;
-
-    IOLog("\nivars %08x, containers %08x\n",
-       debug_ivars_size, debug_container_malloc_size);
-
-    OSMetaClass::printInstanceCounts();
-    dt = IODeviceTreeAlloc( dtTop );
-    assert( dt );
-
-//    OSMetaClass::printInstanceCounts();
-    DumpTree();
-//    OSMetaClass::printInstanceCounts();
-    dt->detachAll( gIODTPlane);
-    OSMetaClass::printInstanceCounts();
-    IOLog("ivars %08x, containers %08x\n",
-       debug_ivars_size, debug_container_malloc_size);
+       return error;
 }
 
+SYSCTL_PROC(_kern, OID_AUTO, iokittest,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
+    NULL, 0, sysctl_iokittest, "I", "");
+#endif // __clang_analyzer__