1c1dac77fSApple OSS Distributions /*
2c1dac77fSApple OSS Distributions  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3c1dac77fSApple OSS Distributions  *
4e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5c1dac77fSApple OSS Distributions  *
6e13b1fa5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7e13b1fa5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8e13b1fa5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9e13b1fa5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10e13b1fa5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11e13b1fa5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12e13b1fa5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13e13b1fa5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14c1dac77fSApple OSS Distributions  *
15e13b1fa5SApple OSS Distributions  * Please obtain a copy of the License at
16e13b1fa5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17e13b1fa5SApple OSS Distributions  *
18e13b1fa5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19e13b1fa5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20c1dac77fSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21c1dac77fSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22e13b1fa5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23e13b1fa5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24e13b1fa5SApple OSS Distributions  * limitations under the License.
25c1dac77fSApple OSS Distributions  *
26e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27c1dac77fSApple OSS Distributions  */
28*bb611c8fSApple OSS Distributions #define IOKIT_ENABLE_SHARED_PTR
293ca3bd55SApple OSS Distributions 
303ca3bd55SApple OSS Distributions #define _IOMEMORYDESCRIPTOR_INTERNAL_
313ca3bd55SApple OSS Distributions 
32c1dac77fSApple OSS Distributions #include <IOKit/assert.h>
33c1dac77fSApple OSS Distributions #include <IOKit/system.h>
34c1dac77fSApple OSS Distributions 
35c1dac77fSApple OSS Distributions #include <IOKit/IOLib.h>
36e13b1fa5SApple OSS Distributions #include <IOKit/IOMapper.h>
37c1dac77fSApple OSS Distributions #include <IOKit/IOBufferMemoryDescriptor.h>
383ca3bd55SApple OSS Distributions #include <libkern/OSDebug.h>
39186b8fceSApple OSS Distributions #include <mach/mach_vm.h>
40c1dac77fSApple OSS Distributions 
4114e3d835SApple OSS Distributions #include "IOKitKernelInternal.h"
4214e3d835SApple OSS Distributions 
43186b8fceSApple OSS Distributions #ifdef IOALLOCDEBUG
44186b8fceSApple OSS Distributions #include <libkern/c++/OSCPPDebug.h>
45186b8fceSApple OSS Distributions #endif
46186b8fceSApple OSS Distributions #include <IOKit/IOStatisticsPrivate.h>
47186b8fceSApple OSS Distributions 
48186b8fceSApple OSS Distributions #if IOKITSTATS
49186b8fceSApple OSS Distributions #define IOStatisticsAlloc(type, size) \
50186b8fceSApple OSS Distributions do { \
51186b8fceSApple OSS Distributions 	IOStatistics::countAlloc(type, size); \
52186b8fceSApple OSS Distributions } while (0)
53186b8fceSApple OSS Distributions #else
54186b8fceSApple OSS Distributions #define IOStatisticsAlloc(type, size)
55186b8fceSApple OSS Distributions #endif /* IOKITSTATS */
56186b8fceSApple OSS Distributions 
57186b8fceSApple OSS Distributions 
58c1dac77fSApple OSS Distributions __BEGIN_DECLS
59c1dac77fSApple OSS Distributions void ipc_port_release_send(ipc_port_t port);
60fad439e7SApple OSS Distributions #include <vm/pmap.h>
61c1dac77fSApple OSS Distributions 
62368ad365SApple OSS Distributions __END_DECLS
63c1dac77fSApple OSS Distributions 
64e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
65e13b1fa5SApple OSS Distributions 
66a5e72196SApple OSS Distributions enum{
67855239e5SApple OSS Distributions 	kInternalFlagPhysical      = 0x00000001,
68186b8fceSApple OSS Distributions 	kInternalFlagPageSized     = 0x00000002,
6976e12aa3SApple OSS Distributions 	kInternalFlagPageAllocated = 0x00000004,
7076e12aa3SApple OSS Distributions 	kInternalFlagInit          = 0x00000008
713ca3bd55SApple OSS Distributions };
723ca3bd55SApple OSS Distributions 
73e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
74e13b1fa5SApple OSS Distributions 
75c1dac77fSApple OSS Distributions #define super IOGeneralMemoryDescriptor
76*bb611c8fSApple OSS Distributions OSDefineMetaClassAndStructorsWithZone(IOBufferMemoryDescriptor,
77*bb611c8fSApple OSS Distributions     IOGeneralMemoryDescriptor, ZC_ZFREE_CLEARMEM);
78c1dac77fSApple OSS Distributions 
793ca3bd55SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
80c1dac77fSApple OSS Distributions 
81a5e72196SApple OSS Distributions static uintptr_t
82a5e72196SApple OSS Distributions IOBMDPageProc(iopa_t * a)
83186b8fceSApple OSS Distributions {
84186b8fceSApple OSS Distributions 	kern_return_t kr;
85186b8fceSApple OSS Distributions 	vm_address_t  vmaddr  = 0;
86186b8fceSApple OSS Distributions 	int           options = 0;// KMA_LOMEM;
87186b8fceSApple OSS Distributions 
88186b8fceSApple OSS Distributions 	kr = kernel_memory_allocate(kernel_map, &vmaddr,
890f3703acSApple OSS Distributions 	    page_size, 0, options, VM_KERN_MEMORY_IOKIT);
90186b8fceSApple OSS Distributions 
91a5e72196SApple OSS Distributions 	if (KERN_SUCCESS != kr) {
92a5e72196SApple OSS Distributions 		vmaddr = 0;
93a5e72196SApple OSS Distributions 	} else {
94a5e72196SApple OSS Distributions 		bzero((void *) vmaddr, page_size);
95a5e72196SApple OSS Distributions 	}
96186b8fceSApple OSS Distributions 
97a5e72196SApple OSS Distributions 	return (uintptr_t) vmaddr;
98186b8fceSApple OSS Distributions }
99186b8fceSApple OSS Distributions 
100186b8fceSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
101186b8fceSApple OSS Distributions 
1023ca3bd55SApple OSS Distributions #ifndef __LP64__
103a5e72196SApple OSS Distributions bool
104a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::initWithOptions(
105c1dac77fSApple OSS Distributions 	IOOptionBits options,
106c1dac77fSApple OSS Distributions 	vm_size_t    capacity,
107fad439e7SApple OSS Distributions 	vm_offset_t  alignment,
108fad439e7SApple OSS Distributions 	task_t       inTask)
109c1dac77fSApple OSS Distributions {
110e13b1fa5SApple OSS Distributions 	mach_vm_address_t physicalMask = 0;
111a5e72196SApple OSS Distributions 	return initWithPhysicalMask(inTask, options, capacity, alignment, physicalMask);
112e13b1fa5SApple OSS Distributions }
1133ca3bd55SApple OSS Distributions #endif /* !__LP64__ */
114e13b1fa5SApple OSS Distributions 
115*bb611c8fSApple OSS Distributions OSSharedPtr<IOBufferMemoryDescriptor>
116a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::withCopy(
117a5e72196SApple OSS Distributions 	task_t                inTask,
118a5e72196SApple OSS Distributions 	IOOptionBits      options,
119a5e72196SApple OSS Distributions 	vm_map_t              sourceMap,
120a5e72196SApple OSS Distributions 	mach_vm_address_t source,
121a5e72196SApple OSS Distributions 	mach_vm_size_t    size)
122a5e72196SApple OSS Distributions {
123*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOBufferMemoryDescriptor> inst;
124a5e72196SApple OSS Distributions 	kern_return_t              err;
125a5e72196SApple OSS Distributions 	vm_map_copy_t              copy;
126a5e72196SApple OSS Distributions 	vm_map_address_t           address;
127a5e72196SApple OSS Distributions 
128a5e72196SApple OSS Distributions 	copy = NULL;
129a5e72196SApple OSS Distributions 	do {
130a5e72196SApple OSS Distributions 		err = kIOReturnNoMemory;
131*bb611c8fSApple OSS Distributions 		inst = OSMakeShared<IOBufferMemoryDescriptor>();
132a5e72196SApple OSS Distributions 		if (!inst) {
133a5e72196SApple OSS Distributions 			break;
134a5e72196SApple OSS Distributions 		}
135a5e72196SApple OSS Distributions 		inst->_ranges.v64 = IONew(IOAddressRange, 1);
136a5e72196SApple OSS Distributions 		if (!inst->_ranges.v64) {
137a5e72196SApple OSS Distributions 			break;
138a5e72196SApple OSS Distributions 		}
139a5e72196SApple OSS Distributions 
140a5e72196SApple OSS Distributions 		err = vm_map_copyin(sourceMap, source, size,
141a5e72196SApple OSS Distributions 		    false /* src_destroy */, &copy);
142a5e72196SApple OSS Distributions 		if (KERN_SUCCESS != err) {
143a5e72196SApple OSS Distributions 			break;
144a5e72196SApple OSS Distributions 		}
145a5e72196SApple OSS Distributions 
146a5e72196SApple OSS Distributions 		err = vm_map_copyout(get_task_map(inTask), &address, copy);
147a5e72196SApple OSS Distributions 		if (KERN_SUCCESS != err) {
148a5e72196SApple OSS Distributions 			break;
149a5e72196SApple OSS Distributions 		}
150a5e72196SApple OSS Distributions 		copy = NULL;
151a5e72196SApple OSS Distributions 
152a5e72196SApple OSS Distributions 		inst->_ranges.v64->address = address;
153a5e72196SApple OSS Distributions 		inst->_ranges.v64->length  = size;
154a5e72196SApple OSS Distributions 
155a5e72196SApple OSS Distributions 		if (!inst->initWithPhysicalMask(inTask, options, size, page_size, 0)) {
156a5e72196SApple OSS Distributions 			err = kIOReturnError;
157a5e72196SApple OSS Distributions 		}
158a5e72196SApple OSS Distributions 	} while (false);
159a5e72196SApple OSS Distributions 
160a5e72196SApple OSS Distributions 	if (KERN_SUCCESS == err) {
161a5e72196SApple OSS Distributions 		return inst;
162a5e72196SApple OSS Distributions 	}
163a5e72196SApple OSS Distributions 
164a5e72196SApple OSS Distributions 	if (copy) {
165a5e72196SApple OSS Distributions 		vm_map_copy_discard(copy);
166a5e72196SApple OSS Distributions 	}
167*bb611c8fSApple OSS Distributions 
168*bb611c8fSApple OSS Distributions 	return nullptr;
169a5e72196SApple OSS Distributions }
170a5e72196SApple OSS Distributions 
171a5e72196SApple OSS Distributions 
172a5e72196SApple OSS Distributions bool
173a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::initWithPhysicalMask(
174e13b1fa5SApple OSS Distributions 	task_t            inTask,
175e13b1fa5SApple OSS Distributions 	IOOptionBits      options,
176e13b1fa5SApple OSS Distributions 	mach_vm_size_t    capacity,
177e13b1fa5SApple OSS Distributions 	mach_vm_address_t alignment,
178e13b1fa5SApple OSS Distributions 	mach_vm_address_t physicalMask)
179e13b1fa5SApple OSS Distributions {
180e13b1fa5SApple OSS Distributions 	task_t                mapTask = NULL;
181e13b1fa5SApple OSS Distributions 	vm_map_t              vmmap = NULL;
1823ca3bd55SApple OSS Distributions 	mach_vm_address_t     highestMask = 0;
1833ca3bd55SApple OSS Distributions 	IOOptionBits          iomdOptions = kIOMemoryTypeVirtual64 | kIOMemoryAsReference;
184186b8fceSApple OSS Distributions 	IODMAMapSpecification mapSpec;
185186b8fceSApple OSS Distributions 	bool                  mapped = false;
186a5e72196SApple OSS Distributions 	bool                  withCopy = false;
187*bb611c8fSApple OSS Distributions 	bool                  mappedOrShared = false;
188fad439e7SApple OSS Distributions 
189a5e72196SApple OSS Distributions 	if (!capacity) {
190a5e72196SApple OSS Distributions 		return false;
191a5e72196SApple OSS Distributions 	}
192c1dac77fSApple OSS Distributions 
193c1dac77fSApple OSS Distributions 	_options          = options;
194c1dac77fSApple OSS Distributions 	_capacity         = capacity;
1953ca3bd55SApple OSS Distributions 	_internalFlags    = 0;
1963ca3bd55SApple OSS Distributions 	_internalReserved = 0;
197a5e72196SApple OSS Distributions 	_buffer           = NULL;
198c1dac77fSApple OSS Distributions 
199a5e72196SApple OSS Distributions 	if (!_ranges.v64) {
2003ca3bd55SApple OSS Distributions 		_ranges.v64 = IONew(IOAddressRange, 1);
201a5e72196SApple OSS Distributions 		if (!_ranges.v64) {
202a5e72196SApple OSS Distributions 			return false;
203a5e72196SApple OSS Distributions 		}
2043ca3bd55SApple OSS Distributions 		_ranges.v64->address = 0;
2053ca3bd55SApple OSS Distributions 		_ranges.v64->length  = 0;
206a5e72196SApple OSS Distributions 	} else {
207a5e72196SApple OSS Distributions 		if (!_ranges.v64->address) {
208a5e72196SApple OSS Distributions 			return false;
209a5e72196SApple OSS Distributions 		}
210a5e72196SApple OSS Distributions 		if (!(kIOMemoryPageable & options)) {
211a5e72196SApple OSS Distributions 			return false;
212a5e72196SApple OSS Distributions 		}
213a5e72196SApple OSS Distributions 		if (!inTask) {
214a5e72196SApple OSS Distributions 			return false;
215a5e72196SApple OSS Distributions 		}
216a5e72196SApple OSS Distributions 		_buffer = (void *) _ranges.v64->address;
217a5e72196SApple OSS Distributions 		withCopy = true;
218a5e72196SApple OSS Distributions 	}
219d0c1fef6SApple OSS Distributions 	//  make sure super::free doesn't dealloc _ranges before super::init
220d0c1fef6SApple OSS Distributions 	_flags = kIOMemoryAsReference;
2213ca3bd55SApple OSS Distributions 
2223ca3bd55SApple OSS Distributions 	// Grab IOMD bits from the Buffer MD options
2233ca3bd55SApple OSS Distributions 	iomdOptions  |= (options & kIOBufferDescriptorMemoryFlags);
2243ca3bd55SApple OSS Distributions 
225a5e72196SApple OSS Distributions 	if (!(kIOMemoryMapperNone & options)) {
226186b8fceSApple OSS Distributions 		IOMapper::checkForSystemMapper();
227a5e72196SApple OSS Distributions 		mapped = (NULL != IOMapper::gSystem);
228186b8fceSApple OSS Distributions 	}
229186b8fceSApple OSS Distributions 
230a5e72196SApple OSS Distributions 	if (physicalMask && (alignment <= 1)) {
2313ca3bd55SApple OSS Distributions 		alignment   = ((physicalMask ^ (-1ULL)) & (physicalMask - 1));
2323ca3bd55SApple OSS Distributions 		highestMask = (physicalMask | alignment);
2333ca3bd55SApple OSS Distributions 		alignment++;
234a5e72196SApple OSS Distributions 		if (alignment < page_size) {
235a5e72196SApple OSS Distributions 			alignment = page_size;
236a5e72196SApple OSS Distributions 		}
237a5e72196SApple OSS Distributions 	}
238a5e72196SApple OSS Distributions 
239a5e72196SApple OSS Distributions 	if ((options & (kIOMemorySharingTypeMask | kIOMapCacheMask | kIOMemoryClearEncrypt)) && (alignment < page_size)) {
240855239e5SApple OSS Distributions 		alignment = page_size;
2413ca3bd55SApple OSS Distributions 	}
242368ad365SApple OSS Distributions 
243a5e72196SApple OSS Distributions 	if (alignment >= page_size) {
244*bb611c8fSApple OSS Distributions 		if (round_page_overflow(capacity, &capacity)) {
245*bb611c8fSApple OSS Distributions 			return false;
246*bb611c8fSApple OSS Distributions 		}
247a5e72196SApple OSS Distributions 	}
2483ca3bd55SApple OSS Distributions 
249a5e72196SApple OSS Distributions 	if (alignment > page_size) {
2503ca3bd55SApple OSS Distributions 		options |= kIOMemoryPhysicallyContiguous;
251a5e72196SApple OSS Distributions 	}
252fad439e7SApple OSS Distributions 
253c1dac77fSApple OSS Distributions 	_alignment = alignment;
254fad439e7SApple OSS Distributions 
255a5e72196SApple OSS Distributions 	if ((capacity + alignment) < _capacity) {
256e13b1fa5SApple OSS Distributions 		return false;
257a5e72196SApple OSS Distributions 	}
258a5e72196SApple OSS Distributions 
259a5e72196SApple OSS Distributions 	if ((inTask != kernel_task) && !(options & kIOMemoryPageable)) {
260a5e72196SApple OSS Distributions 		return false;
261a5e72196SApple OSS Distributions 	}
262c1dac77fSApple OSS Distributions 
263186b8fceSApple OSS Distributions 	bzero(&mapSpec, sizeof(mapSpec));
264186b8fceSApple OSS Distributions 	mapSpec.alignment      = _alignment;
265186b8fceSApple OSS Distributions 	mapSpec.numAddressBits = 64;
266a5e72196SApple OSS Distributions 	if (highestMask && mapped) {
267a5e72196SApple OSS Distributions 		if (highestMask <= 0xFFFFFFFF) {
268*bb611c8fSApple OSS Distributions 			mapSpec.numAddressBits = (uint8_t)(32 - __builtin_clz((unsigned int) highestMask));
269a5e72196SApple OSS Distributions 		} else {
270*bb611c8fSApple OSS Distributions 			mapSpec.numAddressBits = (uint8_t)(64 - __builtin_clz((unsigned int) (highestMask >> 32)));
271a5e72196SApple OSS Distributions 		}
272186b8fceSApple OSS Distributions 		highestMask = 0;
273186b8fceSApple OSS Distributions 	}
274186b8fceSApple OSS Distributions 
275a3bb9fccSApple OSS Distributions 	// set memory entry cache mode, pageable, purgeable
276a3bb9fccSApple OSS Distributions 	iomdOptions |= ((options & kIOMapCacheMask) >> kIOMapCacheShift) << kIOMemoryBufferCacheShift;
277a5e72196SApple OSS Distributions 	if (options & kIOMemoryPageable) {
278e13b1fa5SApple OSS Distributions 		iomdOptions |= kIOMemoryBufferPageable;
279a5e72196SApple OSS Distributions 		if (options & kIOMemoryPurgeable) {
280a5e72196SApple OSS Distributions 			iomdOptions |= kIOMemoryBufferPurgeable;
281e13b1fa5SApple OSS Distributions 		}
282a5e72196SApple OSS Distributions 	} else {
283e13b1fa5SApple OSS Distributions 		vmmap = kernel_map;
284e13b1fa5SApple OSS Distributions 
285e13b1fa5SApple OSS Distributions 		// Buffer shouldn't auto prepare they should be prepared explicitly
286e13b1fa5SApple OSS Distributions 		// But it never was enforced so what are you going to do?
287e13b1fa5SApple OSS Distributions 		iomdOptions |= kIOMemoryAutoPrepare;
288e13b1fa5SApple OSS Distributions 
289e13b1fa5SApple OSS Distributions 		/* Allocate a wired-down buffer inside kernel space. */
290855239e5SApple OSS Distributions 
291186b8fceSApple OSS Distributions 		bool contig = (0 != (options & kIOMemoryHostPhysicallyContiguous));
292186b8fceSApple OSS Distributions 
293a5e72196SApple OSS Distributions 		if (!contig && (0 != (options & kIOMemoryPhysicallyContiguous))) {
294186b8fceSApple OSS Distributions 			contig |= (!mapped);
295186b8fceSApple OSS Distributions 			contig |= (0 != (kIOMemoryMapperNone & options));
296186b8fceSApple OSS Distributions #if 0
297186b8fceSApple OSS Distributions 			// treat kIOMemoryPhysicallyContiguous as kIOMemoryHostPhysicallyContiguous for now
298186b8fceSApple OSS Distributions 			contig |= true;
299186b8fceSApple OSS Distributions #endif
300186b8fceSApple OSS Distributions 		}
301186b8fceSApple OSS Distributions 
302*bb611c8fSApple OSS Distributions 		mappedOrShared = (mapped || (0 != (kIOMemorySharingTypeMask & options)));
303a5e72196SApple OSS Distributions 		if (contig || highestMask || (alignment > page_size)) {
304855239e5SApple OSS Distributions 			_internalFlags |= kInternalFlagPhysical;
305a5e72196SApple OSS Distributions 			if (highestMask) {
306855239e5SApple OSS Distributions 				_internalFlags |= kInternalFlagPageSized;
307*bb611c8fSApple OSS Distributions 				if (round_page_overflow(capacity, &capacity)) {
308*bb611c8fSApple OSS Distributions 					return false;
309*bb611c8fSApple OSS Distributions 				}
310855239e5SApple OSS Distributions 			}
311186b8fceSApple OSS Distributions 			_buffer = (void *) IOKernelAllocateWithPhysicalRestrict(
312186b8fceSApple OSS Distributions 				capacity, highestMask, alignment, contig);
313*bb611c8fSApple OSS Distributions 		} else if (mappedOrShared
314*bb611c8fSApple OSS Distributions 		    && (capacity + alignment) <= (page_size - gIOPageAllocChunkBytes)) {
315186b8fceSApple OSS Distributions 			_internalFlags |= kInternalFlagPageAllocated;
316186b8fceSApple OSS Distributions 			_buffer         = (void *) iopa_alloc(&gIOBMDPageAllocator, &IOBMDPageProc, capacity, alignment);
317a5e72196SApple OSS Distributions 			if (_buffer) {
318186b8fceSApple OSS Distributions 				IOStatisticsAlloc(kIOStatisticsMallocAligned, capacity);
319186b8fceSApple OSS Distributions #if IOALLOCDEBUG
320*bb611c8fSApple OSS Distributions 				OSAddAtomicLong(capacity, &debug_iomalloc_size);
321186b8fceSApple OSS Distributions #endif
322186b8fceSApple OSS Distributions 			}
323a5e72196SApple OSS Distributions 		} else if (alignment > 1) {
324e13b1fa5SApple OSS Distributions 			_buffer = IOMallocAligned(capacity, alignment);
325a5e72196SApple OSS Distributions 		} else {
326e13b1fa5SApple OSS Distributions 			_buffer = IOMalloc(capacity);
3273ca3bd55SApple OSS Distributions 		}
328a5e72196SApple OSS Distributions 		if (!_buffer) {
329e13b1fa5SApple OSS Distributions 			return false;
330e13b1fa5SApple OSS Distributions 		}
331a5e72196SApple OSS Distributions 		bzero(_buffer, capacity);
332a5e72196SApple OSS Distributions 	}
333e13b1fa5SApple OSS Distributions 
334855239e5SApple OSS Distributions 	if ((options & (kIOMemoryPageable | kIOMapCacheMask))) {
3353ca3bd55SApple OSS Distributions 		vm_size_t       size = round_page(capacity);
336e13b1fa5SApple OSS Distributions 
337a3bb9fccSApple OSS Distributions 		// initWithOptions will create memory entry
338a5e72196SApple OSS Distributions 		if (!withCopy) {
339a3bb9fccSApple OSS Distributions 			iomdOptions |= kIOMemoryPersistent;
340a5e72196SApple OSS Distributions 		}
341e13b1fa5SApple OSS Distributions 
342e13b1fa5SApple OSS Distributions 		if (options & kIOMemoryPageable) {
34314e3d835SApple OSS Distributions #if IOALLOCDEBUG
3440f3703acSApple OSS Distributions 			OSAddAtomicLong(size, &debug_iomallocpageable_size);
34514e3d835SApple OSS Distributions #endif
346a5e72196SApple OSS Distributions 			if (!withCopy) {
347e13b1fa5SApple OSS Distributions 				mapTask = inTask;
348a5e72196SApple OSS Distributions 			}
349a5e72196SApple OSS Distributions 			if (NULL == inTask) {
35014e3d835SApple OSS Distributions 				inTask = kernel_task;
351e13b1fa5SApple OSS Distributions 			}
352a5e72196SApple OSS Distributions 		} else if (options & kIOMapCacheMask) {
353e13b1fa5SApple OSS Distributions 			// Prefetch each page to put entries into the pmap
354e13b1fa5SApple OSS Distributions 			volatile UInt8 *    startAddr = (UInt8 *)_buffer;
355e13b1fa5SApple OSS Distributions 			volatile UInt8 *    endAddr   = (UInt8 *)_buffer + capacity;
356e13b1fa5SApple OSS Distributions 
357a5e72196SApple OSS Distributions 			while (startAddr < endAddr) {
358186b8fceSApple OSS Distributions 				UInt8 dummyVar = *startAddr;
359186b8fceSApple OSS Distributions 				(void) dummyVar;
360e13b1fa5SApple OSS Distributions 				startAddr += page_size;
361e13b1fa5SApple OSS Distributions 			}
362e13b1fa5SApple OSS Distributions 		}
363e13b1fa5SApple OSS Distributions 	}
364e13b1fa5SApple OSS Distributions 
365a5e72196SApple OSS Distributions 	_ranges.v64->address = (mach_vm_address_t) _buffer;
3663ca3bd55SApple OSS Distributions 	_ranges.v64->length  = _capacity;
367e13b1fa5SApple OSS Distributions 
3683ca3bd55SApple OSS Distributions 	if (!super::initWithOptions(_ranges.v64, 1, 0,
369a5e72196SApple OSS Distributions 	    inTask, iomdOptions, /* System mapper */ NULL)) {
370e13b1fa5SApple OSS Distributions 		return false;
371a5e72196SApple OSS Distributions 	}
372e13b1fa5SApple OSS Distributions 
37376e12aa3SApple OSS Distributions 	_internalFlags |= kInternalFlagInit;
37476e12aa3SApple OSS Distributions #if IOTRACKING
375a5e72196SApple OSS Distributions 	if (!(options & kIOMemoryPageable)) {
376a5e72196SApple OSS Distributions 		trackingAccumSize(capacity);
377a5e72196SApple OSS Distributions 	}
37876e12aa3SApple OSS Distributions #endif /* IOTRACKING */
37976e12aa3SApple OSS Distributions 
380186b8fceSApple OSS Distributions 	// give any system mapper the allocation params
381186b8fceSApple OSS Distributions 	if (kIOReturnSuccess != dmaCommandOperation(kIOMDAddDMAMapSpec,
382a5e72196SApple OSS Distributions 	    &mapSpec, sizeof(mapSpec))) {
383186b8fceSApple OSS Distributions 		return false;
384a5e72196SApple OSS Distributions 	}
385186b8fceSApple OSS Distributions 
386a5e72196SApple OSS Distributions 	if (mapTask) {
38714e3d835SApple OSS Distributions 		if (!reserved) {
38814e3d835SApple OSS Distributions 			reserved = IONew( ExpansionData, 1 );
389a5e72196SApple OSS Distributions 			if (!reserved) {
390a5e72196SApple OSS Distributions 				return false;
391a5e72196SApple OSS Distributions 			}
39214e3d835SApple OSS Distributions 		}
3933ca3bd55SApple OSS Distributions 		reserved->map = createMappingInTask(mapTask, 0,
394*bb611c8fSApple OSS Distributions 		    kIOMapAnywhere | (options & kIOMapPrefault) | (options & kIOMapCacheMask), 0, 0).detach();
395a5e72196SApple OSS Distributions 		if (!reserved->map) {
396a5e72196SApple OSS Distributions 			_buffer = NULL;
397a5e72196SApple OSS Distributions 			return false;
39814e3d835SApple OSS Distributions 		}
399e13b1fa5SApple OSS Distributions 		release();  // map took a retain on this
4003ca3bd55SApple OSS Distributions 		reserved->map->retain();
4013ca3bd55SApple OSS Distributions 		removeMapping(reserved->map);
402e13b1fa5SApple OSS Distributions 		mach_vm_address_t buffer = reserved->map->getAddress();
403e13b1fa5SApple OSS Distributions 		_buffer = (void *) buffer;
404a5e72196SApple OSS Distributions 		if (kIOMemoryTypeVirtual64 == (kIOMemoryTypeMask & iomdOptions)) {
405e13b1fa5SApple OSS Distributions 			_ranges.v64->address = buffer;
406fad439e7SApple OSS Distributions 		}
407a5e72196SApple OSS Distributions 	}
408c1dac77fSApple OSS Distributions 
4093ca3bd55SApple OSS Distributions 	setLength(_capacity);
410c1dac77fSApple OSS Distributions 
411c1dac77fSApple OSS Distributions 	return true;
412c1dac77fSApple OSS Distributions }
413c1dac77fSApple OSS Distributions 
414*bb611c8fSApple OSS Distributions OSSharedPtr<IOBufferMemoryDescriptor>
415a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::inTaskWithOptions(
416fad439e7SApple OSS Distributions 	task_t       inTask,
417fad439e7SApple OSS Distributions 	IOOptionBits options,
418fad439e7SApple OSS Distributions 	vm_size_t    capacity,
419368ad365SApple OSS Distributions 	vm_offset_t  alignment)
420fad439e7SApple OSS Distributions {
421*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOBufferMemoryDescriptor> me = OSMakeShared<IOBufferMemoryDescriptor>();
422fad439e7SApple OSS Distributions 
4233ca3bd55SApple OSS Distributions 	if (me && !me->initWithPhysicalMask(inTask, options, capacity, alignment, 0)) {
424*bb611c8fSApple OSS Distributions 		me.reset();
425e13b1fa5SApple OSS Distributions 	}
426e13b1fa5SApple OSS Distributions 	return me;
427e13b1fa5SApple OSS Distributions }
428e13b1fa5SApple OSS Distributions 
429*bb611c8fSApple OSS Distributions OSSharedPtr<IOBufferMemoryDescriptor>
430*bb611c8fSApple OSS Distributions IOBufferMemoryDescriptor::inTaskWithOptions(
431*bb611c8fSApple OSS Distributions 	task_t       inTask,
432*bb611c8fSApple OSS Distributions 	IOOptionBits options,
433*bb611c8fSApple OSS Distributions 	vm_size_t    capacity,
434*bb611c8fSApple OSS Distributions 	vm_offset_t  alignment,
435*bb611c8fSApple OSS Distributions 	uint32_t     kernTag,
436*bb611c8fSApple OSS Distributions 	uint32_t     userTag)
437*bb611c8fSApple OSS Distributions {
438*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOBufferMemoryDescriptor> me = OSMakeShared<IOBufferMemoryDescriptor>();
439*bb611c8fSApple OSS Distributions 
440*bb611c8fSApple OSS Distributions 	if (me) {
441*bb611c8fSApple OSS Distributions 		me->setVMTags(kernTag, userTag);
442*bb611c8fSApple OSS Distributions 
443*bb611c8fSApple OSS Distributions 		if (!me->initWithPhysicalMask(inTask, options, capacity, alignment, 0)) {
444*bb611c8fSApple OSS Distributions 			me.reset();
445*bb611c8fSApple OSS Distributions 		}
446*bb611c8fSApple OSS Distributions 	}
447*bb611c8fSApple OSS Distributions 	return me;
448*bb611c8fSApple OSS Distributions }
449*bb611c8fSApple OSS Distributions 
450*bb611c8fSApple OSS Distributions OSSharedPtr<IOBufferMemoryDescriptor>
451a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
452e13b1fa5SApple OSS Distributions 	task_t            inTask,
453e13b1fa5SApple OSS Distributions 	IOOptionBits      options,
454e13b1fa5SApple OSS Distributions 	mach_vm_size_t    capacity,
455e13b1fa5SApple OSS Distributions 	mach_vm_address_t physicalMask)
456e13b1fa5SApple OSS Distributions {
457*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOBufferMemoryDescriptor> me = OSMakeShared<IOBufferMemoryDescriptor>();
458e13b1fa5SApple OSS Distributions 
459a5e72196SApple OSS Distributions 	if (me && !me->initWithPhysicalMask(inTask, options, capacity, 1, physicalMask)) {
460*bb611c8fSApple OSS Distributions 		me.reset();
461fad439e7SApple OSS Distributions 	}
462fad439e7SApple OSS Distributions 	return me;
463fad439e7SApple OSS Distributions }
464fad439e7SApple OSS Distributions 
4653ca3bd55SApple OSS Distributions #ifndef __LP64__
466a5e72196SApple OSS Distributions bool
467a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::initWithOptions(
468fad439e7SApple OSS Distributions 	IOOptionBits options,
469fad439e7SApple OSS Distributions 	vm_size_t    capacity,
470fad439e7SApple OSS Distributions 	vm_offset_t  alignment)
471fad439e7SApple OSS Distributions {
472a5e72196SApple OSS Distributions 	return initWithPhysicalMask(kernel_task, options, capacity, alignment, (mach_vm_address_t)0);
473fad439e7SApple OSS Distributions }
4743ca3bd55SApple OSS Distributions #endif /* !__LP64__ */
475fad439e7SApple OSS Distributions 
476*bb611c8fSApple OSS Distributions OSSharedPtr<IOBufferMemoryDescriptor>
477a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::withOptions(
478c1dac77fSApple OSS Distributions 	IOOptionBits options,
479c1dac77fSApple OSS Distributions 	vm_size_t    capacity,
480368ad365SApple OSS Distributions 	vm_offset_t  alignment)
481c1dac77fSApple OSS Distributions {
482*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOBufferMemoryDescriptor> me = OSMakeShared<IOBufferMemoryDescriptor>();
4833ca3bd55SApple OSS Distributions 
4843ca3bd55SApple OSS Distributions 	if (me && !me->initWithPhysicalMask(kernel_task, options, capacity, alignment, 0)) {
485*bb611c8fSApple OSS Distributions 		me.reset();
4863ca3bd55SApple OSS Distributions 	}
4873ca3bd55SApple OSS Distributions 	return me;
488c1dac77fSApple OSS Distributions }
489c1dac77fSApple OSS Distributions 
490c1dac77fSApple OSS Distributions 
491c1dac77fSApple OSS Distributions /*
492c1dac77fSApple OSS Distributions  * withCapacity:
493c1dac77fSApple OSS Distributions  *
494c1dac77fSApple OSS Distributions  * Returns a new IOBufferMemoryDescriptor with a buffer large enough to
495c1dac77fSApple OSS Distributions  * hold capacity bytes.  The descriptor's length is initially set to the capacity.
496c1dac77fSApple OSS Distributions  */
497*bb611c8fSApple OSS Distributions OSSharedPtr<IOBufferMemoryDescriptor>
498c1dac77fSApple OSS Distributions IOBufferMemoryDescriptor::withCapacity(vm_size_t   inCapacity,
499c1dac77fSApple OSS Distributions     IODirection inDirection,
500c1dac77fSApple OSS Distributions     bool        inContiguous)
501c1dac77fSApple OSS Distributions {
502a5e72196SApple OSS Distributions 	return IOBufferMemoryDescriptor::withOptions(
503c1dac77fSApple OSS Distributions 		inDirection | kIOMemoryUnshared
504c1dac77fSApple OSS Distributions 		| (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
505a5e72196SApple OSS Distributions 		inCapacity, inContiguous ? inCapacity : 1 );
506c1dac77fSApple OSS Distributions }
507c1dac77fSApple OSS Distributions 
5083ca3bd55SApple OSS Distributions #ifndef __LP64__
509c1dac77fSApple OSS Distributions /*
510c1dac77fSApple OSS Distributions  * initWithBytes:
511c1dac77fSApple OSS Distributions  *
512c1dac77fSApple OSS Distributions  * Initialize a new IOBufferMemoryDescriptor preloaded with bytes (copied).
513c1dac77fSApple OSS Distributions  * The descriptor's length and capacity are set to the input buffer's size.
514c1dac77fSApple OSS Distributions  */
515a5e72196SApple OSS Distributions bool
516a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::initWithBytes(const void * inBytes,
517c1dac77fSApple OSS Distributions     vm_size_t    inLength,
518c1dac77fSApple OSS Distributions     IODirection  inDirection,
519c1dac77fSApple OSS Distributions     bool         inContiguous)
520c1dac77fSApple OSS Distributions {
5213ca3bd55SApple OSS Distributions 	if (!initWithPhysicalMask(kernel_task, inDirection | kIOMemoryUnshared
522c1dac77fSApple OSS Distributions 	    | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
523a5e72196SApple OSS Distributions 	    inLength, inLength, (mach_vm_address_t)0)) {
524c1dac77fSApple OSS Distributions 		return false;
525a5e72196SApple OSS Distributions 	}
526c1dac77fSApple OSS Distributions 
527c1dac77fSApple OSS Distributions 	// start out with no data
528c1dac77fSApple OSS Distributions 	setLength(0);
529c1dac77fSApple OSS Distributions 
530a5e72196SApple OSS Distributions 	if (!appendBytes(inBytes, inLength)) {
531c1dac77fSApple OSS Distributions 		return false;
532a5e72196SApple OSS Distributions 	}
533c1dac77fSApple OSS Distributions 
534c1dac77fSApple OSS Distributions 	return true;
535c1dac77fSApple OSS Distributions }
5363ca3bd55SApple OSS Distributions #endif /* !__LP64__ */
537c1dac77fSApple OSS Distributions 
538c1dac77fSApple OSS Distributions /*
539c1dac77fSApple OSS Distributions  * withBytes:
540c1dac77fSApple OSS Distributions  *
541c1dac77fSApple OSS Distributions  * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied).
542c1dac77fSApple OSS Distributions  * The descriptor's length and capacity are set to the input buffer's size.
543c1dac77fSApple OSS Distributions  */
544*bb611c8fSApple OSS Distributions OSSharedPtr<IOBufferMemoryDescriptor>
545c1dac77fSApple OSS Distributions IOBufferMemoryDescriptor::withBytes(const void * inBytes,
546c1dac77fSApple OSS Distributions     vm_size_t    inLength,
547c1dac77fSApple OSS Distributions     IODirection  inDirection,
548c1dac77fSApple OSS Distributions     bool         inContiguous)
549c1dac77fSApple OSS Distributions {
550*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOBufferMemoryDescriptor> me = OSMakeShared<IOBufferMemoryDescriptor>();
551c1dac77fSApple OSS Distributions 
5523ca3bd55SApple OSS Distributions 	if (me && !me->initWithPhysicalMask(
5533ca3bd55SApple OSS Distributions 		    kernel_task, inDirection | kIOMemoryUnshared
5543ca3bd55SApple OSS Distributions 		    | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
555a5e72196SApple OSS Distributions 		    inLength, inLength, 0 )) {
556*bb611c8fSApple OSS Distributions 		me.reset();
557c1dac77fSApple OSS Distributions 	}
5583ca3bd55SApple OSS Distributions 
559a5e72196SApple OSS Distributions 	if (me) {
5603ca3bd55SApple OSS Distributions 		// start out with no data
5613ca3bd55SApple OSS Distributions 		me->setLength(0);
5623ca3bd55SApple OSS Distributions 
563a5e72196SApple OSS Distributions 		if (!me->appendBytes(inBytes, inLength)) {
564*bb611c8fSApple OSS Distributions 			me.reset();
5653ca3bd55SApple OSS Distributions 		}
5663ca3bd55SApple OSS Distributions 	}
567c1dac77fSApple OSS Distributions 	return me;
568c1dac77fSApple OSS Distributions }
569c1dac77fSApple OSS Distributions 
570c1dac77fSApple OSS Distributions /*
571c1dac77fSApple OSS Distributions  * free:
572c1dac77fSApple OSS Distributions  *
573c1dac77fSApple OSS Distributions  * Free resources
574c1dac77fSApple OSS Distributions  */
575a5e72196SApple OSS Distributions void
576a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::free()
577c1dac77fSApple OSS Distributions {
578368ad365SApple OSS Distributions 	// Cache all of the relevant information on the stack for use
579368ad365SApple OSS Distributions 	// after we call super::free()!
580e13b1fa5SApple OSS Distributions 	IOOptionBits     flags         = _flags;
581855239e5SApple OSS Distributions 	IOOptionBits     internalFlags = _internalFlags;
582c1dac77fSApple OSS Distributions 	IOOptionBits     options   = _options;
583c1dac77fSApple OSS Distributions 	vm_size_t        size      = _capacity;
584c1dac77fSApple OSS Distributions 	void *           buffer    = _buffer;
585a5e72196SApple OSS Distributions 	IOMemoryMap *    map       = NULL;
5863ca3bd55SApple OSS Distributions 	IOAddressRange * range     = _ranges.v64;
587c1dac77fSApple OSS Distributions 	vm_offset_t      alignment = _alignment;
588c1dac77fSApple OSS Distributions 
589a5e72196SApple OSS Distributions 	if (alignment >= page_size) {
5903ca3bd55SApple OSS Distributions 		size = round_page(size);
591a5e72196SApple OSS Distributions 	}
5923ca3bd55SApple OSS Distributions 
593a5e72196SApple OSS Distributions 	if (reserved) {
594e13b1fa5SApple OSS Distributions 		map = reserved->map;
595fad439e7SApple OSS Distributions 		IODelete( reserved, ExpansionData, 1 );
596a5e72196SApple OSS Distributions 		if (map) {
597e13b1fa5SApple OSS Distributions 			map->release();
598fad439e7SApple OSS Distributions 		}
599a5e72196SApple OSS Distributions 	}
600fad439e7SApple OSS Distributions 
60176e12aa3SApple OSS Distributions 	if ((options & kIOMemoryPageable)
602a5e72196SApple OSS Distributions 	    || (kInternalFlagPageSized & internalFlags)) {
603a5e72196SApple OSS Distributions 		size = round_page(size);
604a5e72196SApple OSS Distributions 	}
60576e12aa3SApple OSS Distributions 
60676e12aa3SApple OSS Distributions #if IOTRACKING
60776e12aa3SApple OSS Distributions 	if (!(options & kIOMemoryPageable)
60876e12aa3SApple OSS Distributions 	    && buffer
609a5e72196SApple OSS Distributions 	    && (kInternalFlagInit & _internalFlags)) {
610a5e72196SApple OSS Distributions 		trackingAccumSize(-size);
611a5e72196SApple OSS Distributions 	}
61276e12aa3SApple OSS Distributions #endif /* IOTRACKING */
61376e12aa3SApple OSS Distributions 
614c1dac77fSApple OSS Distributions 	/* super::free may unwire - deallocate buffer afterwards */
615c1dac77fSApple OSS Distributions 	super::free();
616c1dac77fSApple OSS Distributions 
617a5e72196SApple OSS Distributions 	if (options & kIOMemoryPageable) {
61814e3d835SApple OSS Distributions #if IOALLOCDEBUG
61976e12aa3SApple OSS Distributions 		OSAddAtomicLong(-size, &debug_iomallocpageable_size);
62014e3d835SApple OSS Distributions #endif
621a5e72196SApple OSS Distributions 	} else if (buffer) {
622a5e72196SApple OSS Distributions 		if (kInternalFlagPhysical & internalFlags) {
623855239e5SApple OSS Distributions 			IOKernelFreePhysical((mach_vm_address_t) buffer, size);
624a5e72196SApple OSS Distributions 		} else if (kInternalFlagPageAllocated & internalFlags) {
625186b8fceSApple OSS Distributions 			uintptr_t page;
626186b8fceSApple OSS Distributions 			page = iopa_free(&gIOBMDPageAllocator, (uintptr_t) buffer, size);
627a5e72196SApple OSS Distributions 			if (page) {
628186b8fceSApple OSS Distributions 				kmem_free(kernel_map, page, page_size);
629186b8fceSApple OSS Distributions 			}
630186b8fceSApple OSS Distributions #if IOALLOCDEBUG
631*bb611c8fSApple OSS Distributions 			OSAddAtomicLong(-size, &debug_iomalloc_size);
632186b8fceSApple OSS Distributions #endif
633186b8fceSApple OSS Distributions 			IOStatisticsAlloc(kIOStatisticsFreeAligned, size);
634a5e72196SApple OSS Distributions 		} else if (alignment > 1) {
635c1dac77fSApple OSS Distributions 			IOFreeAligned(buffer, size);
636a5e72196SApple OSS Distributions 		} else {
637c1dac77fSApple OSS Distributions 			IOFree(buffer, size);
638c1dac77fSApple OSS Distributions 		}
639186b8fceSApple OSS Distributions 	}
640a5e72196SApple OSS Distributions 	if (range && (kIOMemoryAsReference & flags)) {
6413ca3bd55SApple OSS Distributions 		IODelete(range, IOAddressRange, 1);
642c1dac77fSApple OSS Distributions 	}
643a5e72196SApple OSS Distributions }
644c1dac77fSApple OSS Distributions 
645c1dac77fSApple OSS Distributions /*
646c1dac77fSApple OSS Distributions  * getCapacity:
647c1dac77fSApple OSS Distributions  *
648c1dac77fSApple OSS Distributions  * Get the buffer capacity
649c1dac77fSApple OSS Distributions  */
650a5e72196SApple OSS Distributions vm_size_t
651a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::getCapacity() const
652c1dac77fSApple OSS Distributions {
653c1dac77fSApple OSS Distributions 	return _capacity;
654c1dac77fSApple OSS Distributions }
655c1dac77fSApple OSS Distributions 
656c1dac77fSApple OSS Distributions /*
657c1dac77fSApple OSS Distributions  * setLength:
658c1dac77fSApple OSS Distributions  *
659c1dac77fSApple OSS Distributions  * Change the buffer length of the memory descriptor.  When a new buffer
660c1dac77fSApple OSS Distributions  * is created, the initial length of the buffer is set to be the same as
661c1dac77fSApple OSS Distributions  * the capacity.  The length can be adjusted via setLength for a shorter
662c1dac77fSApple OSS Distributions  * transfer (there is no need to create more buffer descriptors when you
663c1dac77fSApple OSS Distributions  * can reuse an existing one, even for different transfer sizes).   Note
664c1dac77fSApple OSS Distributions  * that the specified length must not exceed the capacity of the buffer.
665c1dac77fSApple OSS Distributions  */
666a5e72196SApple OSS Distributions void
667a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::setLength(vm_size_t length)
668c1dac77fSApple OSS Distributions {
669c1dac77fSApple OSS Distributions 	assert(length <= _capacity);
670a5e72196SApple OSS Distributions 	if (length > _capacity) {
671a5e72196SApple OSS Distributions 		return;
672a5e72196SApple OSS Distributions 	}
673c1dac77fSApple OSS Distributions 
674c1dac77fSApple OSS Distributions 	_length = length;
675e13b1fa5SApple OSS Distributions 	_ranges.v64->length = length;
676c1dac77fSApple OSS Distributions }
677c1dac77fSApple OSS Distributions 
678c1dac77fSApple OSS Distributions /*
679c1dac77fSApple OSS Distributions  * setDirection:
680c1dac77fSApple OSS Distributions  *
681c1dac77fSApple OSS Distributions  * Change the direction of the transfer.  This method allows one to redirect
682c1dac77fSApple OSS Distributions  * the descriptor's transfer direction.  This eliminates the need to destroy
683c1dac77fSApple OSS Distributions  * and create new buffers when different transfer directions are needed.
684c1dac77fSApple OSS Distributions  */
685a5e72196SApple OSS Distributions void
686a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::setDirection(IODirection direction)
687c1dac77fSApple OSS Distributions {
6883ca3bd55SApple OSS Distributions 	_flags = (_flags & ~kIOMemoryDirectionMask) | direction;
6893ca3bd55SApple OSS Distributions #ifndef __LP64__
6903ca3bd55SApple OSS Distributions 	_direction = (IODirection) (_flags & kIOMemoryDirectionMask);
6913ca3bd55SApple OSS Distributions #endif /* !__LP64__ */
692c1dac77fSApple OSS Distributions }
693c1dac77fSApple OSS Distributions 
694c1dac77fSApple OSS Distributions /*
695c1dac77fSApple OSS Distributions  * appendBytes:
696c1dac77fSApple OSS Distributions  *
697c1dac77fSApple OSS Distributions  * Add some data to the end of the buffer.  This method automatically
698c1dac77fSApple OSS Distributions  * maintains the memory descriptor buffer length.  Note that appendBytes
699c1dac77fSApple OSS Distributions  * will not copy past the end of the memory descriptor's current capacity.
700c1dac77fSApple OSS Distributions  */
701c1dac77fSApple OSS Distributions bool
702c1dac77fSApple OSS Distributions IOBufferMemoryDescriptor::appendBytes(const void * bytes, vm_size_t withLength)
703c1dac77fSApple OSS Distributions {
704c1dac77fSApple OSS Distributions 	vm_size_t   actualBytesToCopy = min(withLength, _capacity - _length);
705e13b1fa5SApple OSS Distributions 	IOByteCount offset;
706c1dac77fSApple OSS Distributions 
707c1dac77fSApple OSS Distributions 	assert(_length <= _capacity);
708e13b1fa5SApple OSS Distributions 
709e13b1fa5SApple OSS Distributions 	offset = _length;
710c1dac77fSApple OSS Distributions 	_length += actualBytesToCopy;
711e13b1fa5SApple OSS Distributions 	_ranges.v64->length += actualBytesToCopy;
712e13b1fa5SApple OSS Distributions 
713a5e72196SApple OSS Distributions 	if (_task == kernel_task) {
714e13b1fa5SApple OSS Distributions 		bcopy(/* from */ bytes, (void *)(_ranges.v64->address + offset),
715e13b1fa5SApple OSS Distributions 		    actualBytesToCopy);
716a5e72196SApple OSS Distributions 	} else {
717e13b1fa5SApple OSS Distributions 		writeBytes(offset, bytes, actualBytesToCopy);
718a5e72196SApple OSS Distributions 	}
719c1dac77fSApple OSS Distributions 
720c1dac77fSApple OSS Distributions 	return true;
721c1dac77fSApple OSS Distributions }
722c1dac77fSApple OSS Distributions 
723c1dac77fSApple OSS Distributions /*
724c1dac77fSApple OSS Distributions  * getBytesNoCopy:
725c1dac77fSApple OSS Distributions  *
726c1dac77fSApple OSS Distributions  * Return the virtual address of the beginning of the buffer
727c1dac77fSApple OSS Distributions  */
728a5e72196SApple OSS Distributions void *
729a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::getBytesNoCopy()
730c1dac77fSApple OSS Distributions {
731a5e72196SApple OSS Distributions 	if (kIOMemoryTypePhysical64 == (_flags & kIOMemoryTypeMask)) {
732e13b1fa5SApple OSS Distributions 		return _buffer;
733a5e72196SApple OSS Distributions 	} else {
734e13b1fa5SApple OSS Distributions 		return (void *)_ranges.v64->address;
735c1dac77fSApple OSS Distributions 	}
736a5e72196SApple OSS Distributions }
737c1dac77fSApple OSS Distributions 
738e13b1fa5SApple OSS Distributions 
739c1dac77fSApple OSS Distributions /*
740c1dac77fSApple OSS Distributions  * getBytesNoCopy:
741c1dac77fSApple OSS Distributions  *
742c1dac77fSApple OSS Distributions  * Return the virtual address of an offset from the beginning of the buffer
743c1dac77fSApple OSS Distributions  */
744c1dac77fSApple OSS Distributions void *
745c1dac77fSApple OSS Distributions IOBufferMemoryDescriptor::getBytesNoCopy(vm_size_t start, vm_size_t withLength)
746c1dac77fSApple OSS Distributions {
747e13b1fa5SApple OSS Distributions 	IOVirtualAddress address;
74888cc0b97SApple OSS Distributions 
749a5e72196SApple OSS Distributions 	if ((start + withLength) < start) {
750a5e72196SApple OSS Distributions 		return NULL;
751a5e72196SApple OSS Distributions 	}
75288cc0b97SApple OSS Distributions 
753a5e72196SApple OSS Distributions 	if (kIOMemoryTypePhysical64 == (_flags & kIOMemoryTypeMask)) {
754e13b1fa5SApple OSS Distributions 		address = (IOVirtualAddress) _buffer;
755a5e72196SApple OSS Distributions 	} else {
756e13b1fa5SApple OSS Distributions 		address = _ranges.v64->address;
757a5e72196SApple OSS Distributions 	}
758e13b1fa5SApple OSS Distributions 
759a5e72196SApple OSS Distributions 	if (start < _length && (start + withLength) <= _length) {
760e13b1fa5SApple OSS Distributions 		return (void *)(address + start);
761a5e72196SApple OSS Distributions 	}
762a5e72196SApple OSS Distributions 	return NULL;
763c1dac77fSApple OSS Distributions }
764c1dac77fSApple OSS Distributions 
7653ca3bd55SApple OSS Distributions #ifndef __LP64__
766a5e72196SApple OSS Distributions void *
767a5e72196SApple OSS Distributions IOBufferMemoryDescriptor::getVirtualSegment(IOByteCount offset,
7683ca3bd55SApple OSS Distributions     IOByteCount * lengthOfSegment)
769e13b1fa5SApple OSS Distributions {
770e13b1fa5SApple OSS Distributions 	void * bytes = getBytesNoCopy(offset, 0);
771e13b1fa5SApple OSS Distributions 
772a5e72196SApple OSS Distributions 	if (bytes && lengthOfSegment) {
773e13b1fa5SApple OSS Distributions 		*lengthOfSegment = _length - offset;
774a5e72196SApple OSS Distributions 	}
775e13b1fa5SApple OSS Distributions 
776e13b1fa5SApple OSS Distributions 	return bytes;
777e13b1fa5SApple OSS Distributions }
7783ca3bd55SApple OSS Distributions #endif /* !__LP64__ */
779e13b1fa5SApple OSS Distributions 
7803ca3bd55SApple OSS Distributions #ifdef __LP64__
7813ca3bd55SApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 0);
7823ca3bd55SApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 1);
7833ca3bd55SApple OSS Distributions #else /* !__LP64__ */
784*bb611c8fSApple OSS Distributions OSMetaClassDefineReservedUsedX86(IOBufferMemoryDescriptor, 0);
785*bb611c8fSApple OSS Distributions OSMetaClassDefineReservedUsedX86(IOBufferMemoryDescriptor, 1);
7863ca3bd55SApple OSS Distributions #endif /* !__LP64__ */
787c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 2);
788c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 3);
789c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 4);
790c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 5);
791c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 6);
792c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 7);
793c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 8);
794c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 9);
795c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 10);
796c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 11);
797c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 12);
798c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 13);
799c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 14);
800c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 15);
801