]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Tests/TestIOMemoryDescriptor.cpp
xnu-4570.1.46.tar.gz
[apple/xnu.git] / iokit / Tests / TestIOMemoryDescriptor.cpp
index 926681a7ede6f878229b28dc6ca066e031651bf3..11780e5f272e60b583d763522b8bd97dde2715d1 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2014-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -35,6 +35,7 @@
 #include <IOKit/IOMapper.h>
 #include <IOKit/IODMACommand.h>
 #include <IOKit/IOKitKeysPrivate.h>
 #include <IOKit/IOMapper.h>
 #include <IOKit/IODMACommand.h>
 #include <IOKit/IOKitKeysPrivate.h>
+#include "Tests.h"
 
 #ifndef __LP64__
 #include <IOKit/IOSubMemoryDescriptor.h>
 
 #ifndef __LP64__
 #include <IOKit/IOSubMemoryDescriptor.h>
@@ -64,6 +65,8 @@ __END_DECLS
 
 #if DEVELOPMENT || DEBUG
 
 
 #if DEVELOPMENT || DEBUG
 
+extern SInt32 gIOMemoryReferenceCount;
+
 static int IOMultMemoryDescriptorTest(int newValue)
 {
     IOMemoryDescriptor * mds[3];
 static int IOMultMemoryDescriptorTest(int newValue)
 {
     IOMemoryDescriptor * mds[3];
@@ -108,12 +111,389 @@ static int IOMultMemoryDescriptorTest(int newValue)
 }
 
 
 }
 
 
+
+// <rdar://problem/30102458>
+static int
+IODMACommandForceDoubleBufferTest(int newValue)
+{
+    IOReturn                   ret;
+    IOBufferMemoryDescriptor * bmd;
+    IODMACommand             * dma;
+    uint32_t                   dir, data;
+    IODMACommand::SegmentOptions segOptions =
+    {
+       .fStructSize      = sizeof(segOptions),
+       .fNumAddressBits  = 64,
+       .fMaxSegmentSize  = 0x2000,
+       .fMaxTransferSize = 128*1024,
+       .fAlignment       = 1,
+       .fAlignmentLength = 1,
+       .fAlignmentInternalSegments = 1
+    };
+    IODMACommand::Segment64 segments[1];
+    UInt32                  numSegments;
+    UInt64                  dmaOffset;
+
+
+    for (dir = kIODirectionIn; ; dir++)
+    {
+       bmd = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,
+                           dir | kIOMemoryPageable, ptoa(8));
+       assert(bmd);
+
+       ((uint32_t*) bmd->getBytesNoCopy())[0] = 0x53535300 | dir;
+
+       ret = bmd->prepare((IODirection) dir);
+       assert(kIOReturnSuccess == ret);
+
+       dma = IODMACommand::withSpecification(kIODMACommandOutputHost64, &segOptions,
+                                             kIODMAMapOptionMapped,
+                                             NULL, NULL);
+       assert(dma);
+       ret = dma->setMemoryDescriptor(bmd, true);
+       assert(kIOReturnSuccess == ret);
+
+       ret = dma->synchronize(IODMACommand::kForceDoubleBuffer | kIODirectionOut);
+       assert(kIOReturnSuccess == ret);
+
+       dmaOffset   = 0;
+       numSegments = 1;
+       ret = dma->gen64IOVMSegments(&dmaOffset, &segments[0], &numSegments);
+       assert(kIOReturnSuccess == ret);
+       assert(1 == numSegments);
+
+       if (kIODirectionOut & dir)
+       {
+           data = ((uint32_t*) bmd->getBytesNoCopy())[0];
+           assertf((0x53535300 | dir) == data, "mismatch 0x%x", data);
+       }
+       if (kIODirectionIn & dir)
+       {
+            IOMappedWrite32(segments[0].fIOVMAddr, 0x11223300 | dir);
+       }
+
+       ret = dma->clearMemoryDescriptor(true);
+       assert(kIOReturnSuccess == ret);
+       dma->release();
+
+       bmd->complete((IODirection) dir);
+
+       if (kIODirectionIn & dir)
+       {
+           data = ((uint32_t*) bmd->getBytesNoCopy())[0];
+           assertf((0x11223300 | dir) == data, "mismatch 0x%x", data);
+       }
+
+       bmd->release();
+
+       if (dir == kIODirectionInOut) break;
+    }
+
+    return (0);
+}
+
+// <rdar://problem/30102458>
+static int
+IOMemoryRemoteTest(int newValue)
+{
+    IOReturn             ret;
+    IOMemoryDescriptor * md;
+    IOByteCount          offset, length;
+    addr64_t             addr;
+    uint32_t             idx;
+
+    IODMACommand       * dma;
+    IODMACommand::SegmentOptions segOptions =
+    {
+       .fStructSize      = sizeof(segOptions),
+       .fNumAddressBits  = 64,
+       .fMaxSegmentSize  = 0x2000,
+       .fMaxTransferSize = 128*1024,
+       .fAlignment       = 1,
+       .fAlignmentLength = 1,
+       .fAlignmentInternalSegments = 1
+    };
+    IODMACommand::Segment64 segments[1];
+    UInt32                  numSegments;
+    UInt64                  dmaOffset;
+
+    IOAddressRange ranges[2] = {
+       { 0x1234567890123456ULL, 0x1000 }, { 0x5432109876543210, 0x2000 },
+    };
+
+    md = IOMemoryDescriptor::withAddressRanges(&ranges[0], 2, kIODirectionOutIn|kIOMemoryRemote, TASK_NULL);
+    assert(md);
+
+//    md->map();
+//    md->readBytes(0, &idx, sizeof(idx));
+
+    ret = md->prepare(kIODirectionOutIn);
+    assert(kIOReturnSuccess == ret);
+
+    printf("remote md flags 0x%qx, r %d\n",
+       md->getFlags(), (0 != (kIOMemoryRemote & md->getFlags())));
+
+    for (offset = 0, idx = 0; true; offset += length, idx++)
+    {
+       addr = md->getPhysicalSegment(offset, &length, 0);
+       if (!length) break;
+       assert(idx < 2);
+       assert(addr   == ranges[idx].address);
+       assert(length == ranges[idx].length);
+    }
+    assert(offset == md->getLength());
+
+    dma = IODMACommand::withSpecification(kIODMACommandOutputHost64, &segOptions,
+                                         kIODMAMapOptionUnmapped | kIODMAMapOptionIterateOnly,
+                                         NULL, NULL);
+    assert(dma);
+    ret = dma->setMemoryDescriptor(md, true);
+    assert(kIOReturnSuccess == ret);
+
+    for (dmaOffset = 0, idx = 0; dmaOffset < md->getLength(); idx++)
+    {
+       numSegments = 1;
+       ret = dma->gen64IOVMSegments(&dmaOffset, &segments[0], &numSegments);
+       assert(kIOReturnSuccess == ret);
+       assert(1 == numSegments);
+       assert(idx < 2);
+       assert(segments[0].fIOVMAddr == ranges[idx].address);
+       assert(segments[0].fLength   == ranges[idx].length);
+    }
+    assert(dmaOffset == md->getLength());
+
+    ret = dma->clearMemoryDescriptor(true);
+    assert(kIOReturnSuccess == ret);
+    dma->release();
+    md->complete(kIODirectionOutIn);
+    md->release();
+
+    return (0);
+}
+
+static IOReturn
+IOMemoryPrefaultTest(uint32_t options)
+{
+    IOBufferMemoryDescriptor * bmd;
+    IOMemoryMap              * map;
+    IOReturn       kr;
+    uint32_t       data;
+    uint32_t *     p;
+    IOSimpleLock * lock;
+
+    lock = IOSimpleLockAlloc();
+    assert(lock);
+
+    bmd = IOBufferMemoryDescriptor::inTaskWithOptions(current_task(),
+                        kIODirectionOutIn | kIOMemoryPageable, ptoa(8));
+    assert(bmd);
+    kr = bmd->prepare();
+    assert(KERN_SUCCESS == kr);
+
+    map = bmd->map(kIOMapPrefault);
+    assert(map);
+
+    p = (typeof(p)) map->getVirtualAddress();
+    IOSimpleLockLock(lock);
+    data = p[0];
+    IOSimpleLockUnlock(lock);
+
+    IOLog("IOMemoryPrefaultTest %d\n", data);
+
+    map->release();
+    bmd->release();
+    IOSimpleLockFree(lock);
+
+    return (kIOReturnSuccess);
+}
+
+
+// <rdar://problem/26375234>
+static IOReturn
+ZeroLengthTest(int newValue)
+{
+    IOMemoryDescriptor * md;
+
+    md = IOMemoryDescriptor::withAddressRange(
+                               0, 0, kIODirectionNone, current_task());
+    assert(md);
+    md->prepare();
+    md->complete();
+    md->release();
+    return (0);
+}
+
+// <rdar://problem/27002624>
+static IOReturn
+BadFixedAllocTest(int newValue)
+{
+    IOBufferMemoryDescriptor * bmd;
+    IOMemoryMap              * map;
+
+    bmd = IOBufferMemoryDescriptor::inTaskWithOptions(NULL,
+                        kIODirectionIn | kIOMemoryPageable, ptoa(1));
+    assert(bmd);
+    map = bmd->createMappingInTask(kernel_task, 0x2000, 0);
+    assert(!map);
+
+    bmd->release();
+    return (0);
+}
+
+// <rdar://problem/26466423>
+static IOReturn
+IODirectionPrepareNoZeroFillTest(int newValue)
+{
+    IOBufferMemoryDescriptor * bmd;
+
+    bmd = IOBufferMemoryDescriptor::inTaskWithOptions(NULL,
+                        kIODirectionIn | kIOMemoryPageable, ptoa(24));
+    assert(bmd);
+    bmd->prepare((IODirection)(kIODirectionIn | kIODirectionPrepareNoZeroFill));
+    bmd->prepare(kIODirectionIn);
+    bmd->complete((IODirection)(kIODirectionIn | kIODirectionCompleteWithDataValid));
+    bmd->complete(kIODirectionIn);
+    bmd->release();
+    return (0);
+}
+
+// <rdar://problem/28190483>
+static IOReturn
+IOMemoryMapTest(uint32_t options)
+{
+    IOBufferMemoryDescriptor * bmd;
+    IOMemoryDescriptor       * md;
+    IOMemoryMap              * map;
+    uint32_t    data;
+    user_addr_t p;
+    uint8_t *   p2;
+    int         r;
+    uint64_t    time, nano;
+
+    bmd = IOBufferMemoryDescriptor::inTaskWithOptions(current_task(),
+                        kIODirectionOutIn | kIOMemoryPageable, 0x4018+0x800);
+    assert(bmd);
+    p = (typeof(p)) bmd->getBytesNoCopy();
+    p += 0x800;
+    data = 0x11111111;
+    r = copyout(&data, p, sizeof(data));
+    assert(r == 0);
+    data = 0x22222222;
+    r = copyout(&data, p + 0x1000, sizeof(data));
+    assert(r == 0);
+    data = 0x33333333;
+    r = copyout(&data, p + 0x2000, sizeof(data));
+    assert(r == 0);
+    data = 0x44444444;
+    r = copyout(&data, p + 0x3000, sizeof(data));
+    assert(r == 0);
+
+    md = IOMemoryDescriptor::withAddressRange(p, 0x4018, 
+                                              kIODirectionOut | options,
+                                              current_task());
+    assert(md);
+    time = mach_absolute_time();
+    map = md->map(kIOMapReadOnly);
+    time = mach_absolute_time() - time;
+    assert(map);
+    absolutetime_to_nanoseconds(time, &nano);
+    
+    p2 = (typeof(p2)) map->getVirtualAddress();
+    assert(0x11 == p2[0]);
+    assert(0x22 == p2[0x1000]);
+    assert(0x33 == p2[0x2000]);
+    assert(0x44 == p2[0x3000]);
+
+    data = 0x99999999;
+    r = copyout(&data, p + 0x2000, sizeof(data));
+    assert(r == 0);
+
+    assert(0x11 == p2[0]);
+    assert(0x22 == p2[0x1000]);
+    assert(0x44 == p2[0x3000]);
+    if (kIOMemoryMapCopyOnWrite & options) assert(0x33 == p2[0x2000]);
+    else                                   assert(0x99 == p2[0x2000]);
+
+    IOLog("IOMemoryMapCopyOnWriteTest map(%s) %lld ns\n", 
+                        kIOMemoryMapCopyOnWrite & options ? "kIOMemoryMapCopyOnWrite" : "",
+                        nano);
+
+    map->release();
+    md->release();
+    bmd->release();
+
+    return (kIOReturnSuccess);
+}
+
+static int
+IOMemoryMapCopyOnWriteTest(int newValue)
+{
+    IOMemoryMapTest(0);
+    IOMemoryMapTest(kIOMemoryMapCopyOnWrite);
+    return (0);
+}
+
+static int
+AllocationNameTest(int newValue)
+{
+    IOMemoryDescriptor * bmd;
+    kern_allocation_name_t name, prior;
+
+    name = kern_allocation_name_allocate("com.apple.iokit.test", 0);
+    assert(name);
+
+    prior = thread_set_allocation_name(name);
+
+    bmd = IOBufferMemoryDescriptor::inTaskWithOptions(TASK_NULL,
+                kIODirectionOutIn | kIOMemoryPageable | kIOMemoryKernelUserShared,
+                ptoa(13));
+    assert(bmd);
+    bmd->prepare();
+
+    thread_set_allocation_name(prior);
+    kern_allocation_name_release(name);
+
+    if (newValue != 7) bmd->release();
+
+    return (0);
+}
+
 int IOMemoryDescriptorTest(int newValue)
 {
     int result;
 
 int IOMemoryDescriptorTest(int newValue)
 {
     int result;
 
+    IOLog("/IOMemoryDescriptorTest %d\n", (int) gIOMemoryReferenceCount);
+
 #if 0
 #if 0
-    if (5 == newValue)
+    if (6 == newValue)
+    {
+       IOMemoryDescriptor * sbmds[3];
+       IOMultiMemoryDescriptor * smmd;
+       IOMemoryDescriptor * mds[2];
+       IOMultiMemoryDescriptor * mmd;
+       IOMemoryMap * map;
+
+       sbmds[0] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(1));
+       sbmds[1] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(2));
+       sbmds[2] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(3));
+       smmd = IOMultiMemoryDescriptor::withDescriptors(&sbmds[0], sizeof(sbmds)/sizeof(sbmds[0]), kIODirectionOutIn, false);
+
+       mds[0] = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryKernelUserShared, ptoa(1));
+       mds[1] = smmd;
+       mmd = IOMultiMemoryDescriptor::withDescriptors(&mds[0], sizeof(mds)/sizeof(mds[0]), kIODirectionOutIn, false);
+       map = mmd->createMappingInTask(kernel_task, 0, kIOMapAnywhere);
+       assert(map);
+       map->release();
+       mmd->release();
+       mds[0]->release();
+       mds[1]->release();
+       sbmds[0]->release();
+       sbmds[1]->release();
+       sbmds[2]->release();
+
+       return (0);
+    }
+    else if (5 == newValue)
     {
        IOReturn             ret;
        IOMemoryDescriptor * md;
     {
        IOReturn             ret;
        IOMemoryDescriptor * md;
@@ -308,16 +688,43 @@ int IOMemoryDescriptorTest(int newValue)
     }
 #endif
 
     }
 #endif
 
+    result = IODMACommandForceDoubleBufferTest(newValue);
+    if (result) return (result);
+
+    result = AllocationNameTest(newValue);
+    if (result) return (result);
+
+    result = IOMemoryMapCopyOnWriteTest(newValue);
+    if (result) return (result);
+
     result = IOMultMemoryDescriptorTest(newValue);
     if (result) return (result);
 
     result = IOMultMemoryDescriptorTest(newValue);
     if (result) return (result);
 
+    result = ZeroLengthTest(newValue);
+    if (result) return (result);
+
+    result = IODirectionPrepareNoZeroFillTest(newValue);
+    if (result) return (result);
+
+    result = BadFixedAllocTest(newValue);
+    if (result) return (result);
+
+    result = IOMemoryRemoteTest(newValue);
+    if (result) return (result);
+
+    result = IOMemoryPrefaultTest(newValue);
+    if (result) return (result);
+
     IOGeneralMemoryDescriptor * md;
     vm_offset_t data[2];
     vm_size_t  bsize = 16*1024*1024;
     vm_size_t  srcsize, srcoffset, mapoffset, size;
     kern_return_t kr;
 
     IOGeneralMemoryDescriptor * md;
     vm_offset_t data[2];
     vm_size_t  bsize = 16*1024*1024;
     vm_size_t  srcsize, srcoffset, mapoffset, size;
     kern_return_t kr;
 
-    kr = vm_allocate(kernel_map, &data[0], bsize, VM_FLAGS_ANYWHERE);
+    data[0] = data[1] = 0;
+    kr = vm_allocate_kernel(kernel_map, &data[0], bsize, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT);
+    assert(KERN_SUCCESS == kr);
+
     vm_inherit(kernel_map, data[0] + ptoa(1), ptoa(1), VM_INHERIT_NONE);
     vm_inherit(kernel_map, data[0] + ptoa(16), ptoa(4), VM_INHERIT_NONE);
 
     vm_inherit(kernel_map, data[0] + ptoa(1), ptoa(1), VM_INHERIT_NONE);
     vm_inherit(kernel_map, data[0] + ptoa(16), ptoa(4), VM_INHERIT_NONE);
 
@@ -339,6 +746,7 @@ int IOMemoryDescriptorTest(int newValue)
            bzero(&ranges[0], sizeof(ranges));
            ranges[0].address = data[0] + srcoffset;
            ranges[0].length  = srcsize;
            bzero(&ranges[0], sizeof(ranges));
            ranges[0].address = data[0] + srcoffset;
            ranges[0].length  = srcsize;
+           ranges[1].address = ranges[2].address = data[0];
 
            if (srcsize > ptoa(5))
            {
 
            if (srcsize > ptoa(5))
            {
@@ -365,7 +773,7 @@ int IOMemoryDescriptorTest(int newValue)
            assert(md);
 
            IOLog("IOMemoryDescriptor::withAddressRanges [0x%lx @ 0x%lx]\n[0x%llx, 0x%llx],\n[0x%llx, 0x%llx],\n[0x%llx, 0x%llx]\n", 
            assert(md);
 
            IOLog("IOMemoryDescriptor::withAddressRanges [0x%lx @ 0x%lx]\n[0x%llx, 0x%llx],\n[0x%llx, 0x%llx],\n[0x%llx, 0x%llx]\n", 
-                   (long) srcsize, (long) srcoffset,
+                   (long) srcsize, (long) srcoffset,
                    (long long) ranges[0].address - data[0], (long long) ranges[0].length,
                    (long long) ranges[1].address - data[0], (long long) ranges[1].length,
                    (long long) ranges[2].address - data[0], (long long) ranges[2].length);
                    (long long) ranges[0].address - data[0], (long long) ranges[0].length,
                    (long long) ranges[1].address - data[0], (long long) ranges[1].length,
                    (long long) ranges[2].address - data[0], (long long) ranges[2].length);
@@ -440,6 +848,8 @@ int IOMemoryDescriptorTest(int newValue)
     vm_deallocate(kernel_map, data[0], bsize);
 //    vm_deallocate(kernel_map, data[1], size);
 
     vm_deallocate(kernel_map, data[0], bsize);
 //    vm_deallocate(kernel_map, data[1], size);
 
+    IOLog("IOMemoryDescriptorTest/ %d\n", (int) gIOMemoryReferenceCount);
+
     return (0);
 }
 
     return (0);
 }