+addr64_t
+IOGeneralMemoryDescriptor::getPhysicalSegment(IOByteCount offset, IOByteCount *lengthOfSegment, IOOptionBits options)
+{
+ IOReturn ret;
+ addr64_t address = 0;
+ IOByteCount length = 0;
+ IOMapper * mapper = gIOSystemMapper;
+ IOOptionBits type = _flags & kIOMemoryTypeMask;
+
+ if (lengthOfSegment)
+ *lengthOfSegment = 0;
+
+ if (offset >= _length)
+ return 0;
+
+ // IOMemoryDescriptor::doMap() cannot use getPhysicalSegment() to obtain the page offset, since it must
+ // support the unwired memory case in IOGeneralMemoryDescriptor, and hibernate_write_image() cannot use
+ // map()->getVirtualAddress() to obtain the kernel pointer, since it must prevent the memory allocation
+ // due to IOMemoryMap, so _kIOMemorySourceSegment is a necessary evil until all of this gets cleaned up
+
+ if ((options & _kIOMemorySourceSegment) && (kIOMemoryTypeUPL != type))
+ {
+ unsigned rangesIndex = 0;
+ Ranges vec = _ranges;
+ user_addr_t addr;
+
+ // Find starting address within the vector of ranges
+ for (;;) {
+ getAddrLenForInd(addr, length, type, vec, rangesIndex);
+ if (offset < length)
+ break;
+ offset -= length; // (make offset relative)
+ rangesIndex++;
+ }
+
+ // Now that we have the starting range,
+ // lets find the last contiguous range
+ addr += offset;
+ length -= offset;
+
+ for ( ++rangesIndex; rangesIndex < _rangesCount; rangesIndex++ ) {
+ user_addr_t newAddr;
+ IOPhysicalLength newLen;
+
+ getAddrLenForInd(newAddr, newLen, type, vec, rangesIndex);
+ if (addr + length != newAddr)
+ break;
+ length += newLen;
+ }
+ if (addr)
+ address = (IOPhysicalAddress) addr; // Truncate address to 32bit
+ }
+ else
+ {
+ IOMDDMAWalkSegmentState _state;
+ IOMDDMAWalkSegmentArgs * state = (IOMDDMAWalkSegmentArgs *) &_state;
+
+ state->fOffset = offset;
+ state->fLength = _length - offset;
+ state->fMapped = (0 == (options & kIOMemoryMapperNone));
+
+ ret = dmaCommandOperation(kIOMDFirstSegment, _state, sizeof(_state));
+
+ if ((kIOReturnSuccess != ret) && (kIOReturnOverrun != ret))
+ DEBG("getPhysicalSegment dmaCommandOperation(%lx), %p, offset %qx, addr %qx, len %qx\n",
+ ret, this, state->fOffset,
+ state->fIOVMAddr, state->fLength);
+ if (kIOReturnSuccess == ret)
+ {
+ address = state->fIOVMAddr;
+ length = state->fLength;
+ }
+
+ // dmaCommandOperation() does not distinguish between "mapped" and "unmapped" physical memory, even
+ // with fMapped set correctly, so we must handle the transformation here until this gets cleaned up
+
+ if (mapper && ((kIOMemoryTypePhysical == type) || (kIOMemoryTypePhysical64 == type)))
+ {
+ if ((options & kIOMemoryMapperNone) && !(_flags & kIOMemoryMapperNone))
+ {
+ addr64_t origAddr = address;
+ IOByteCount origLen = length;
+
+ address = mapper->mapAddr(origAddr);
+ length = page_size - (address & (page_size - 1));
+ while ((length < origLen)
+ && ((address + length) == mapper->mapAddr(origAddr + length)))
+ length += page_size;
+ if (length > origLen)
+ length = origLen;
+ }
+#ifdef __LP64__
+ else if (!(options & kIOMemoryMapperNone) && (_flags & kIOMemoryMapperNone))
+ {
+ panic("getPhysicalSegment not mapped for I/O");
+ }
+#endif /* __LP64__ */
+ }
+ }
+
+ if (!address)
+ length = 0;
+
+ if (lengthOfSegment)
+ *lengthOfSegment = length;
+
+ return (address);
+}
+
+#ifndef __LP64__
+addr64_t
+IOMemoryDescriptor::getPhysicalSegment(IOByteCount offset, IOByteCount *lengthOfSegment, IOOptionBits options)
+{
+ addr64_t address = 0;
+
+ if (options & _kIOMemorySourceSegment)
+ {
+ address = getSourceSegment(offset, lengthOfSegment);
+ }
+ else if (options & kIOMemoryMapperNone)
+ {
+ address = getPhysicalSegment64(offset, lengthOfSegment);
+ }
+ else
+ {
+ address = getPhysicalSegment(offset, lengthOfSegment);
+ }
+
+ return (address);
+}
+
+addr64_t
+IOGeneralMemoryDescriptor::getPhysicalSegment64(IOByteCount offset, IOByteCount *lengthOfSegment)
+{
+ return (getPhysicalSegment(offset, lengthOfSegment, kIOMemoryMapperNone));
+}
+
+IOPhysicalAddress
+IOGeneralMemoryDescriptor::getPhysicalSegment(IOByteCount offset, IOByteCount *lengthOfSegment)
+{
+ addr64_t address = 0;
+ IOByteCount length = 0;
+
+ address = getPhysicalSegment(offset, lengthOfSegment, 0);
+
+ if (lengthOfSegment)
+ length = *lengthOfSegment;
+
+ if ((address + length) > 0x100000000ULL)
+ {
+ panic("getPhysicalSegment() out of 32b range 0x%qx, len 0x%lx, class %s",
+ address, (long) length, (getMetaClass())->getClassName());
+ }
+
+ return ((IOPhysicalAddress) address);
+}
+
+addr64_t
+IOMemoryDescriptor::getPhysicalSegment64(IOByteCount offset, IOByteCount *lengthOfSegment)