|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: #include <IOKit/assert.h>
23: #include <IOKit/system.h>
24:
25: #include <IOKit/IOLib.h>
26: #include <IOKit/IOBufferMemoryDescriptor.h>
27:
28: #define super IOGeneralMemoryDescriptor
29: OSDefineMetaClassAndStructors(IOBufferMemoryDescriptor,
30: IOGeneralMemoryDescriptor);
31:
32: /*
33: * initWithCapacity:
34: *
35: * Initialize a new IOBufferMemoryDescriptor with a buffer large enough to
36: * hold capacity bytes. The descriptor's length is initially set to zero.
37: */
38: bool IOBufferMemoryDescriptor::initWithCapacity(vm_size_t inCapacity,
39: IODirection inDirection,
40: bool inContiguous)
41: {
42: if (!inCapacity)
43: return false;
44:
45: /* Allocate a wired-down buffer inside kernel space. */
46: _buffer = (inContiguous) ?
47: IOMallocContiguous(inCapacity, inCapacity, 0) :
48: IOMalloc(inCapacity);
49: _contiguous = inContiguous;
50: _capacity = inCapacity;
51: _physAddrs = 0;
52: _physSegCount = 0;
53:
54: if (!_buffer)
55: return false;
56:
57: if (!super::initWithAddress(_buffer, inCapacity, inDirection))
58: return false;
59:
60: /* Precompute virtual-to-physical page mappings. */
61: vm_address_t inBuffer = (vm_address_t) _buffer;
62: _physSegCount = atop(trunc_page(inBuffer + inCapacity - 1) -
63: trunc_page(inBuffer)) + 1;
64: _physAddrs = IONew(IOPhysicalAddress, _physSegCount);
65: if (!_physAddrs)
66: return false;
67:
68: inBuffer = trunc_page(inBuffer);
69: for (unsigned i = 0; i < _physSegCount; i++) {
70: _physAddrs[i] = pmap_extract(get_task_pmap(kernel_task), inBuffer);
71: assert(_physAddrs[i]); /* supposed to be wired */
72: inBuffer += page_size;
73: }
74:
75: // start out with no data
76: setLength(0);
77:
78: return true;
79: }
80:
81: /*
82: * withCapacity:
83: *
84: * Returns a new IOBufferMemoryDescriptor with a buffer large enough to
85: * hold capacity bytes. The descriptor's length is initially set to zero.
86: */
87: IOBufferMemoryDescriptor *
88: IOBufferMemoryDescriptor::withCapacity(vm_size_t inCapacity,
89: IODirection inDirection,
90: bool inContiguous)
91: {
92: IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
93:
94: if (me && !me->initWithCapacity(inCapacity, inDirection, inContiguous)) {
95: me->release();
96: me = 0;
97: }
98: return me;
99: }
100:
101: /*
102: * initWithBytes:
103: *
104: * Initialize a new IOBufferMemoryDescriptor preloaded with bytes (copied).
105: * The descriptor's length and capacity are set to the input buffer's size.
106: */
107: bool IOBufferMemoryDescriptor::initWithBytes(const void * inBytes,
108: vm_size_t inLength,
109: IODirection inDirection,
110: bool inContiguous)
111: {
112: if (!initWithCapacity(inLength, inDirection, inContiguous))
113: return false;
114:
115: if (!appendBytes(inBytes, inLength))
116: return false;
117:
118: return true;
119: }
120:
121: /*
122: * withBytes:
123: *
124: * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied).
125: * The descriptor's length and capacity are set to the input buffer's size.
126: */
127: IOBufferMemoryDescriptor *
128: IOBufferMemoryDescriptor::withBytes(const void * inBytes,
129: vm_size_t inLength,
130: IODirection inDirection,
131: bool inContiguous)
132: {
133: IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
134:
135: if (me && !me->initWithBytes(inBytes, inLength, inDirection, inContiguous)){
136: me->release();
137: me = 0;
138: }
139: return me;
140: }
141:
142: /*
143: * free:
144: *
145: * Free resources
146: */
147: void IOBufferMemoryDescriptor::free()
148: {
149: if (_physAddrs)
150: IODelete(_physAddrs, IOPhysicalAddress, _physSegCount);
151:
152: super::free();
153:
154: if (_buffer) {
155: if (_contiguous)
156: IOFreeContiguous(_buffer, _capacity);
157: else
158: IOFree(_buffer, _capacity);
159: }
160: }
161:
162: /*
163: * getCapacity:
164: *
165: * Get the buffer capacity
166: */
167: vm_size_t IOBufferMemoryDescriptor::getCapacity() const
168: {
169: return _capacity;
170: }
171:
172: /*
173: * setLength:
174: *
175: * Change the buffer length of the memory descriptor. When a new buffer is
176: * created with initWithBytes, the descriptor's length is set to capacity,
177: * or its length is initially zero. This method allows one to resize the
178: * buffer length up to capacity or less. This eliminates the need to
179: * destroy and create new buffers when different sizes are needed. The
180: * descriptor position is implicitly reset to zero as a result of this call.
181: */
182: void IOBufferMemoryDescriptor::setLength(vm_size_t length)
183: {
184: assert(length <= _capacity);
185:
186: _length = length;
187: _singleRange.v.length = length;
188: }
189:
190: /*
191: * setDirection:
192: *
193: * Change the direction of the transfer. This method allows one to redirect
194: * the descriptor's transfer direction. This eliminates the need to destroy
195: * and create new buffers when different transfer directions are needed.
196: */
197: void IOBufferMemoryDescriptor::setDirection(IODirection direction)
198: {
199: _direction = direction;
200: }
201:
202: /*
203: * appendBytes:
204: *
205: * Add some data to the end of the buffer. This method automatically
206: * maintains the memory descriptor buffer length. Note that appendBytes
207: * will not copy past the end of the memory descriptor's current capacity.
208: */
209: bool
210: IOBufferMemoryDescriptor::appendBytes(const void * bytes, vm_size_t withLength)
211: {
212: vm_size_t actualBytesToCopy = min(withLength, _capacity - _length);
213:
214: assert(_length <= _capacity);
215: bcopy(/* from */ bytes, (void *)(_singleRange.v.address + _length),
216: actualBytesToCopy);
217: _length += actualBytesToCopy;
218: _singleRange.v.length += actualBytesToCopy;
219:
220: return true;
221: }
222:
223: /*
224: * getBytesNoCopy:
225: *
226: * Return the virtual address of the beginning of the buffer
227: */
228: void * IOBufferMemoryDescriptor::getBytesNoCopy()
229: {
230: return (void *)_singleRange.v.address;
231: }
232:
233: /*
234: * getBytesNoCopy:
235: *
236: * Return the virtual address of an offset from the beginning of the buffer
237: */
238: void *
239: IOBufferMemoryDescriptor::getBytesNoCopy(vm_size_t start, vm_size_t withLength)
240: {
241: if (start < _length && (start + withLength) <= _length)
242: return (void *)(_singleRange.v.address + start);
243: return 0;
244: }
245:
246: /*
247: * getPhysicalSegment:
248: *
249: * Get the physical address of the buffer, relative to the current position.
250: * If the current position is at the end of the buffer, a zero is returned.
251: */
252: IOPhysicalAddress
253: IOBufferMemoryDescriptor::getPhysicalSegment(IOByteCount offset,
254: IOPhysicalLength * lengthOfSegment)
255: {
256: if( offset != _position)
257: setPosition( offset );
258:
259: assert(_position <= _length);
260:
261: /* Fail gracefully if the position is at (or past) the end-of-buffer. */
262: if (_position >= _length) {
263: *lengthOfSegment = 0;
264: return 0;
265: }
266:
267: /* Compute the largest contiguous physical length possible. */
268: vm_address_t actualPos = _singleRange.v.address + _position;
269: vm_address_t actualPage = trunc_page(actualPos);
270: unsigned physInd = atop(actualPage-trunc_page(_singleRange.v.address));
271:
272: vm_size_t physicalLength = actualPage + page_size - actualPos;
273: for (unsigned index = physInd + 1; index < _physSegCount &&
274: _physAddrs[index] == _physAddrs[index-1] + page_size; index++) {
275: physicalLength += page_size;
276: }
277:
278: /* Clip contiguous physical length at the end-of-buffer. */
279: if (physicalLength > _length - _position)
280: physicalLength = _length - _position;
281:
282: *lengthOfSegment = physicalLength;
283: return _physAddrs[physInd] + (actualPos - actualPage);
284: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.