X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3e170ce000f1506b7b5d2c5c7faec85ceabb573d..5ba3f43ea354af8ad55bea84372a2bc834d8757c:/iokit/Tests/TestIOMemoryDescriptor.cpp diff --git a/iokit/Tests/TestIOMemoryDescriptor.cpp b/iokit/Tests/TestIOMemoryDescriptor.cpp index 926681a7e..11780e5f2 100644 --- a/iokit/Tests/TestIOMemoryDescriptor.cpp +++ b/iokit/Tests/TestIOMemoryDescriptor.cpp @@ -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@ * @@ -35,6 +35,7 @@ #include #include #include +#include "Tests.h" #ifndef __LP64__ #include @@ -64,6 +65,8 @@ __END_DECLS #if DEVELOPMENT || DEBUG +extern SInt32 gIOMemoryReferenceCount; + static int IOMultMemoryDescriptorTest(int newValue) { IOMemoryDescriptor * mds[3]; @@ -108,12 +111,389 @@ static int IOMultMemoryDescriptorTest(int newValue) } + +// +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); +} + +// +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); +} + + +// +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); +} + +// +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); +} + +// +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); +} + +// +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; + IOLog("/IOMemoryDescriptorTest %d\n", (int) gIOMemoryReferenceCount); + #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; @@ -308,16 +688,43 @@ int IOMemoryDescriptorTest(int newValue) } #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 = 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; - 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); @@ -339,6 +746,7 @@ int IOMemoryDescriptorTest(int newValue) 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)) { @@ -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", - (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); @@ -440,6 +848,8 @@ int IOMemoryDescriptorTest(int newValue) vm_deallocate(kernel_map, data[0], bsize); // vm_deallocate(kernel_map, data[1], size); + IOLog("IOMemoryDescriptorTest/ %d\n", (int) gIOMemoryReferenceCount); + return (0); }