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 __BEGIN_DECLS
29 void ipc_port_release_send(ipc_port_t port);
30 #include <vm/pmap.h>
31 __END_DECLS
32 
33 extern "C" vm_map_t IOPageableMapForAddress( vm_address_t address );
34 
35 #define super IOGeneralMemoryDescriptor
36 OSDefineMetaClassAndStructors(IOBufferMemoryDescriptor,
37 				IOGeneralMemoryDescriptor);
38 
39 bool IOBufferMemoryDescriptor::initWithAddress(
40                                   void *      /* address       */ ,
41                                   IOByteCount /* withLength    */ ,
42                                   IODirection /* withDirection */ )
43 {
44     return false;
45 }
46 
47 bool IOBufferMemoryDescriptor::initWithAddress(
48                                   vm_address_t /* address       */ ,
49                                   IOByteCount  /* withLength    */ ,
50                                   IODirection  /* withDirection */ ,
51                                   task_t       /* withTask      */ )
52 {
53     return false;
54 }
55 
56 bool IOBufferMemoryDescriptor::initWithPhysicalAddress(
57                                   IOPhysicalAddress /* address       */ ,
58                                   IOByteCount       /* withLength    */ ,
59                                   IODirection       /* withDirection */ )
60 {
61     return false;
62 }
63 
64 bool IOBufferMemoryDescriptor::initWithPhysicalRanges(
65                                   IOPhysicalRange * /* ranges        */ ,
66                                   UInt32            /* withCount     */ ,
67                                   IODirection       /* withDirection */ ,
68                                   bool              /* asReference   */ )
69 {
70     return false;
71 }
72 
73 bool IOBufferMemoryDescriptor::initWithRanges(
74                                   IOVirtualRange * /* ranges        */ ,
75                                   UInt32           /* withCount     */ ,
76                                   IODirection      /* withDirection */ ,
77                                   task_t           /* withTask      */ ,
78                                   bool             /* asReference   */ )
79 {
80     return false;
81 }
82 
83 bool IOBufferMemoryDescriptor::initWithOptions(
84                                IOOptionBits options,
85                                vm_size_t    capacity,
86                                vm_offset_t  alignment,
87 			       task_t	    inTask)
88 {
89     vm_map_t map = 0;
90 
91     if (!capacity)
92         return false;
93 
94     _options   	  = options;
95     _capacity     = capacity;
96     _physAddrs    = 0;
97     _physSegCount = 0;
98     _buffer	  = 0;
99 
100     if ((options & kIOMemorySharingTypeMask) && (alignment < page_size))
101         alignment = page_size;
102 
103     if ((inTask != kernel_task) && !(options & kIOMemoryPageable))
104         return false;
105 
106     _alignment = alignment;
107     if (options & kIOMemoryPageable)
108     {
109 	if (inTask == kernel_task)
110 	{
111 	    /* Allocate some kernel address space. */
112 	    _buffer = IOMallocPageable(capacity, alignment);
113 	    if (_buffer)
114 		map = IOPageableMapForAddress((vm_address_t) _buffer);
115 	}
116 	else
117 	{
118 	    kern_return_t kr;
119 
120 	    if( !reserved) {
121 		reserved = IONew( ExpansionData, 1 );
122 		if( !reserved)
123 		    return( false );
124 	    }
125 	    map = get_task_map(inTask);
126 	    vm_map_reference(map);
127 	    reserved->map = map;
128 	    kr = vm_allocate( map, (vm_address_t *) &_buffer, round_page(capacity),
129 				VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_IOKIT) );
130 	    if( KERN_SUCCESS != kr)
131 		return( false );
132 
133 	    // we have to make sure that these pages don't get copied on fork.
134 	    kr = vm_inherit( map, (vm_address_t) _buffer, round_page(capacity), VM_INHERIT_NONE);
135 	    if( KERN_SUCCESS != kr)
136 		return( false );
137 	}
138     }
139     else
140     {
141 	/* Allocate a wired-down buffer inside kernel space. */
142 	if (options & kIOMemoryPhysicallyContiguous)
143 	    _buffer = IOMallocContiguous(capacity, alignment, 0);
144 	else if (alignment > 1)
145 	    _buffer = IOMallocAligned(capacity, alignment);
146 	else
147 	    _buffer = IOMalloc(capacity);
148     }
149 
150     if (!_buffer)
151 	return false;
152 
153     _singleRange.v.address = (vm_address_t) _buffer;
154     _singleRange.v.length  = capacity;
155 
156     if (!super::initWithRanges(&_singleRange.v,	1,
157                                 (IODirection) (options & kIOMemoryDirectionMask),
158                                 inTask, true))
159 	return false;
160 
161     if (options & kIOMemoryPageable)
162     {
163         _flags |= kIOMemoryRequiresWire;
164 
165         kern_return_t kr;
166         ipc_port_t sharedMem = (ipc_port_t) _memEntry;
167         vm_size_t size = round_page(_ranges.v[0].length);
168 
169         // must create the entry before any pages are allocated
170         if( 0 == sharedMem) {
171             kr = mach_make_memory_entry( map,
172                         &size, _ranges.v[0].address,
173                         VM_PROT_READ | VM_PROT_WRITE, &sharedMem,
174                         NULL );
175             if( (KERN_SUCCESS == kr) && (size != round_page(_ranges.v[0].length))) {
176                 ipc_port_release_send( sharedMem );
177                 kr = kIOReturnVMError;
178             }
179             if( KERN_SUCCESS != kr)
180                 sharedMem = 0;
181             _memEntry = (void *) sharedMem;
182         }
183     }
184     else
185     {
186         /* Precompute virtual-to-physical page mappings. */
187         vm_address_t inBuffer = (vm_address_t) _buffer;
188         _physSegCount = atop(trunc_page(inBuffer + capacity - 1) -
189                             trunc_page(inBuffer)) + 1;
190         _physAddrs = IONew(IOPhysicalAddress, _physSegCount);
191         if (!_physAddrs)
192             return false;
193 
194         inBuffer = trunc_page(inBuffer);
195         for (unsigned i = 0; i < _physSegCount; i++) {
196             _physAddrs[i] = pmap_extract(get_task_pmap(kernel_task), inBuffer);
197             assert(_physAddrs[i]); /* supposed to be wired */
198             inBuffer += page_size;
199         }
200     }
201 
202     setLength(capacity);
203 
204     return true;
205 }
206 
207 IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::inTaskWithOptions(
208 					    task_t       inTask,
209                                             IOOptionBits options,
210                                             vm_size_t    capacity,
211                                             vm_offset_t  alignment = 1)
212 {
213     IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
214 
215     if (me && !me->initWithOptions(options, capacity, alignment, inTask)) {
216 	me->release();
217 	me = 0;
218     }
219     return me;
220 }
221 
222 bool IOBufferMemoryDescriptor::initWithOptions(
223                                IOOptionBits options,
224                                vm_size_t    capacity,
225                                vm_offset_t  alignment)
226 {
227     return( initWithOptions(options, capacity, alignment, kernel_task) );
228 }
229 
230 IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::withOptions(
231                                             IOOptionBits options,
232                                             vm_size_t    capacity,
233                                             vm_offset_t  alignment = 1)
234 {
235     IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
236 
237     if (me && !me->initWithOptions(options, capacity, alignment, kernel_task)) {
238 	me->release();
239 	me = 0;
240     }
241     return me;
242 }
243 
244 
245 /*
246  * withCapacity:
247  *
248  * Returns a new IOBufferMemoryDescriptor with a buffer large enough to
249  * hold capacity bytes.  The descriptor's length is initially set to the capacity.
250  */
251 IOBufferMemoryDescriptor *
252 IOBufferMemoryDescriptor::withCapacity(vm_size_t   inCapacity,
253                                        IODirection inDirection,
254                                        bool        inContiguous)
255 {
256     return( IOBufferMemoryDescriptor::withOptions(
257                inDirection | kIOMemoryUnshared
258                 | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
259                inCapacity, inContiguous ? inCapacity : 1 ));
260 }
261 
262 /*
263  * initWithBytes:
264  *
265  * Initialize a new IOBufferMemoryDescriptor preloaded with bytes (copied).
266  * The descriptor's length and capacity are set to the input buffer's size.
267  */
268 bool IOBufferMemoryDescriptor::initWithBytes(const void * inBytes,
269                                              vm_size_t    inLength,
270                                              IODirection  inDirection,
271                                              bool         inContiguous)
272 {
273     if (!initWithOptions(
274                inDirection | kIOMemoryUnshared
275                 | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
276                inLength, inLength ))
277         return false;
278 
279     // start out with no data
280     setLength(0);
281 
282     if (!appendBytes(inBytes, inLength))
283         return false;
284 
285     return true;
286 }
287 
288 /*
289  * withBytes:
290  *
291  * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied).
292  * The descriptor's length and capacity are set to the input buffer's size.
293  */
294 IOBufferMemoryDescriptor *
295 IOBufferMemoryDescriptor::withBytes(const void * inBytes,
296                                     vm_size_t    inLength,
297                                     IODirection  inDirection,
298                                     bool         inContiguous)
299 {
300     IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
301 
302     if (me && !me->initWithBytes(inBytes, inLength, inDirection, inContiguous)){
303         me->release();
304         me = 0;
305     }
306     return me;
307 }
308 
309 /*
310  * free:
311  *
312  * Free resources
313  */
314 void IOBufferMemoryDescriptor::free()
315 {
316     IOOptionBits options   = _options;
317     vm_size_t    size	   = _capacity;
318     void *       buffer	   = _buffer;
319     vm_map_t	 map	   = 0;
320     vm_offset_t  alignment = _alignment;
321 
322     if (_physAddrs)
323         IODelete(_physAddrs, IOPhysicalAddress, _physSegCount);
324 
325     if (reserved)
326     {
327 	map = reserved->map;
328         IODelete( reserved, ExpansionData, 1 );
329     }
330 
331     /* super::free may unwire - deallocate buffer afterwards */
332     super::free();
333 
334     if (buffer)
335     {
336         if (options & kIOMemoryPageable)
337 	{
338 	    if (map)
339 		vm_deallocate(map, (vm_address_t) buffer, round_page(size));
340 	    else
341 	       IOFreePageable(buffer, size);
342 	}
343         else
344 	{
345             if (options & kIOMemoryPhysicallyContiguous)
346                 IOFreeContiguous(buffer, size);
347             else if (alignment > 1)
348                 IOFreeAligned(buffer, size);
349             else
350                 IOFree(buffer, size);
351         }
352     }
353     if (map)
354 	vm_map_deallocate(map);
355 }
356 
357 /*
358  * getCapacity:
359  *
360  * Get the buffer capacity
361  */
362 vm_size_t IOBufferMemoryDescriptor::getCapacity() const
363 {
364     return _capacity;
365 }
366 
367 /*
368  * setLength:
369  *
370  * Change the buffer length of the memory descriptor.  When a new buffer
371  * is created, the initial length of the buffer is set to be the same as
372  * the capacity.  The length can be adjusted via setLength for a shorter
373  * transfer (there is no need to create more buffer descriptors when you
374  * can reuse an existing one, even for different transfer sizes).   Note
375  * that the specified length must not exceed the capacity of the buffer.
376  */
377 void IOBufferMemoryDescriptor::setLength(vm_size_t length)
378 {
379     assert(length <= _capacity);
380 
381     _length = length;
382     _singleRange.v.length = length;
383 }
384 
385 /*
386  * setDirection:
387  *
388  * Change the direction of the transfer.  This method allows one to redirect
389  * the descriptor's transfer direction.  This eliminates the need to destroy
390  * and create new buffers when different transfer directions are needed.
391  */
392 void IOBufferMemoryDescriptor::setDirection(IODirection direction)
393 {
394     _direction = direction;
395 }
396 
397 /*
398  * appendBytes:
399  *
400  * Add some data to the end of the buffer.  This method automatically
401  * maintains the memory descriptor buffer length.  Note that appendBytes
402  * will not copy past the end of the memory descriptor's current capacity.
403  */
404 bool
405 IOBufferMemoryDescriptor::appendBytes(const void * bytes, vm_size_t withLength)
406 {
407     vm_size_t actualBytesToCopy = min(withLength, _capacity - _length);
408 
409     assert(_length <= _capacity);
410     bcopy(/* from */ bytes, (void *)(_singleRange.v.address + _length),
411           actualBytesToCopy);
412     _length += actualBytesToCopy;
413     _singleRange.v.length += actualBytesToCopy;
414 
415     return true;
416 }
417 
418 /*
419  * getBytesNoCopy:
420  *
421  * Return the virtual address of the beginning of the buffer
422  */
423 void * IOBufferMemoryDescriptor::getBytesNoCopy()
424 {
425     return (void *)_singleRange.v.address;
426 }
427 
428 /*
429  * getBytesNoCopy:
430  *
431  * Return the virtual address of an offset from the beginning of the buffer
432  */
433 void *
434 IOBufferMemoryDescriptor::getBytesNoCopy(vm_size_t start, vm_size_t withLength)
435 {
436     if (start < _length && (start + withLength) <= _length)
437         return (void *)(_singleRange.v.address + start);
438     return 0;
439 }
440 
441 /*
442  * getPhysicalSegment:
443  *
444  * Get the physical address of the buffer, relative to the current position.
445  * If the current position is at the end of the buffer, a zero is returned.
446  */
447 IOPhysicalAddress
448 IOBufferMemoryDescriptor::getPhysicalSegment(IOByteCount offset,
449 					IOByteCount * lengthOfSegment)
450 {
451     IOPhysicalAddress physAddr;
452 
453     if( offset != _position)
454 	setPosition( offset );
455 
456     assert(_position <= _length);
457 
458     /* Fail gracefully if the position is at (or past) the end-of-buffer. */
459     if (_position >= _length) {
460         *lengthOfSegment = 0;
461         return 0;
462     }
463 
464     if (_options & kIOMemoryPageable) {
465         physAddr = super::getPhysicalSegment(offset, lengthOfSegment);
466 
467     } else {
468         /* Compute the largest contiguous physical length possible. */
469         vm_address_t actualPos  = _singleRange.v.address + _position;
470         vm_address_t actualPage = trunc_page(actualPos);
471         unsigned     physInd    = atop(actualPage-trunc_page(_singleRange.v.address));
472 
473         vm_size_t physicalLength = actualPage + page_size - actualPos;
474         for (unsigned index = physInd + 1; index < _physSegCount &&
475             _physAddrs[index] == _physAddrs[index-1] + page_size; index++) {
476             physicalLength += page_size;
477         }
478 
479         /* Clip contiguous physical length at the end-of-buffer. */
480         if (physicalLength > _length - _position)
481             physicalLength = _length - _position;
482 
483         *lengthOfSegment = physicalLength;
484         physAddr = _physAddrs[physInd] + (actualPos - actualPage);
485     }
486 
487     return physAddr;
488 }
489 
490 OSMetaClassDefineReservedUsed(IOBufferMemoryDescriptor, 0);
491 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 1);
492 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 2);
493 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 3);
494 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 4);
495 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 5);
496 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 6);
497 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 7);
498 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 8);
499 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 9);
500 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 10);
501 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 11);
502 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 12);
503 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 13);
504 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 14);
505 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 15);
506