1 /*
2  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #define _IOMEMORYDESCRIPTOR_INTERNAL_
30 
31 #include <IOKit/assert.h>
32 #include <IOKit/system.h>
33 
34 #include <IOKit/IOLib.h>
35 #include <IOKit/IOMapper.h>
36 #include <IOKit/IOBufferMemoryDescriptor.h>
37 #include <libkern/OSDebug.h>
38 
39 #include "IOKitKernelInternal.h"
40 
41 __BEGIN_DECLS
42 void ipc_port_release_send(ipc_port_t port);
43 #include <vm/pmap.h>
44 
45 __END_DECLS
46 
47 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
48 
49 enum
50 {
51     kInternalFlagPhysical  = 0x00000001,
52     kInternalFlagPageSized = 0x00000002
53 };
54 
55 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
56 
57 #define super IOGeneralMemoryDescriptor
58 OSDefineMetaClassAndStructors(IOBufferMemoryDescriptor,
59 				IOGeneralMemoryDescriptor);
60 
61 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
62 
63 #ifndef __LP64__
64 bool IOBufferMemoryDescriptor::initWithOptions(
65                                IOOptionBits options,
66                                vm_size_t    capacity,
67                                vm_offset_t  alignment,
68 			       task_t	    inTask)
69 {
70     mach_vm_address_t physicalMask = 0;
71     return (initWithPhysicalMask(inTask, options, capacity, alignment, physicalMask));
72 }
73 #endif /* !__LP64__ */
74 
75 bool IOBufferMemoryDescriptor::initWithPhysicalMask(
76 				task_t		  inTask,
77 				IOOptionBits      options,
78 				mach_vm_size_t    capacity,
79 				mach_vm_address_t alignment,
80 				mach_vm_address_t physicalMask)
81 {
82     kern_return_t 	kr;
83     task_t		mapTask = NULL;
84     vm_map_t 		vmmap = NULL;
85     mach_vm_address_t   highestMask = 0;
86     IOOptionBits	iomdOptions = kIOMemoryTypeVirtual64 | kIOMemoryAsReference;
87 
88     if (!capacity)
89         return false;
90 
91     _options   	      = options;
92     _capacity         = capacity;
93     _internalFlags    = 0;
94     _internalReserved = 0;
95     _buffer	      = 0;
96 
97     _ranges.v64 = IONew(IOAddressRange, 1);
98     if (!_ranges.v64)
99 	return (false);
100     _ranges.v64->address = 0;
101     _ranges.v64->length  = 0;
102 
103     // Grab IOMD bits from the Buffer MD options
104     iomdOptions  |= (options & kIOBufferDescriptorMemoryFlags);
105 
106     if (physicalMask && (alignment <= 1))
107     {
108 	alignment   = ((physicalMask ^ (-1ULL)) & (physicalMask - 1));
109 	highestMask = (physicalMask | alignment);
110 	alignment++;
111 	if (alignment < page_size)
112             alignment = page_size;
113     }
114 
115     if ((options & (kIOMemorySharingTypeMask | kIOMapCacheMask | kIOMemoryClearEncrypt)) && (alignment < page_size))
116 	alignment = page_size;
117 
118     if (alignment >= page_size)
119 	capacity = round_page(capacity);
120 
121     if (alignment > page_size)
122 	options |= kIOMemoryPhysicallyContiguous;
123 
124     _alignment = alignment;
125 
126     if ((inTask != kernel_task) && !(options & kIOMemoryPageable))
127 	return false;
128 
129     // set flags for entry + object create
130     vm_prot_t memEntryCacheMode = VM_PROT_READ | VM_PROT_WRITE;
131 
132     // set memory entry cache mode
133     switch (options & kIOMapCacheMask)
134     {
135 	case kIOMapInhibitCache:
136 	    SET_MAP_MEM(MAP_MEM_IO, memEntryCacheMode);
137 	    break;
138 
139 	case kIOMapWriteThruCache:
140 	    SET_MAP_MEM(MAP_MEM_WTHRU, memEntryCacheMode);
141 	    break;
142 
143 	case kIOMapWriteCombineCache:
144 	    SET_MAP_MEM(MAP_MEM_WCOMB, memEntryCacheMode);
145 	    break;
146 
147 	case kIOMapCopybackCache:
148 	    SET_MAP_MEM(MAP_MEM_COPYBACK, memEntryCacheMode);
149 	    break;
150 
151 	case kIOMapDefaultCache:
152 	default:
153 	    SET_MAP_MEM(MAP_MEM_NOOP, memEntryCacheMode);
154 	    break;
155     }
156 
157     if (options & kIOMemoryPageable)
158     {
159 	iomdOptions |= kIOMemoryBufferPageable;
160 
161 	// must create the entry before any pages are allocated
162 
163 	// set flags for entry + object create
164 	memEntryCacheMode |= MAP_MEM_NAMED_CREATE;
165 
166 	if (options & kIOMemoryPurgeable)
167 	    memEntryCacheMode |= MAP_MEM_PURGABLE;
168     }
169     else
170     {
171 	memEntryCacheMode |= MAP_MEM_NAMED_REUSE;
172 	vmmap = kernel_map;
173 
174 	// Buffer shouldn't auto prepare they should be prepared explicitly
175 	// But it never was enforced so what are you going to do?
176 	iomdOptions |= kIOMemoryAutoPrepare;
177 
178 	/* Allocate a wired-down buffer inside kernel space. */
179 
180 	if ((options & kIOMemoryPhysicallyContiguous) || highestMask || (alignment > page_size))
181 	{
182             _internalFlags |= kInternalFlagPhysical;
183             if (highestMask)
184             {
185                 _internalFlags |= kInternalFlagPageSized;
186                 capacity = round_page(capacity);
187             }
188             _buffer = (void *) IOKernelAllocateWithPhysicalRestrict(capacity, highestMask, alignment,
189                                         (0 != (options & kIOMemoryPhysicallyContiguous)));
190 	}
191 	else if (alignment > 1)
192 	{
193             _buffer = IOMallocAligned(capacity, alignment);
194 	}
195 	else
196 	{
197             _buffer = IOMalloc(capacity);
198 	}
199 
200 	if (!_buffer)
201 	{
202             return false;
203 	}
204     }
205 
206     if( (options & (kIOMemoryPageable | kIOMapCacheMask))) {
207 	ipc_port_t	sharedMem;
208 	vm_size_t	size = round_page(capacity);
209 
210 	kr = mach_make_memory_entry(vmmap,
211 				    &size, (vm_offset_t)_buffer,
212 				    memEntryCacheMode, &sharedMem,
213 				    NULL );
214 
215 	if( (KERN_SUCCESS == kr) && (size != round_page(capacity))) {
216 	    ipc_port_release_send( sharedMem );
217 	    kr = kIOReturnVMError;
218 	}
219 	if( KERN_SUCCESS != kr)
220 	    return( false );
221 
222 	_memEntry = (void *) sharedMem;
223 
224 	if( options & kIOMemoryPageable) {
225 #if IOALLOCDEBUG
226 	    debug_iomallocpageable_size += size;
227 #endif
228 	    mapTask = inTask;
229 	    if (NULL == inTask)
230 		inTask = kernel_task;
231 	}
232 	else if (options & kIOMapCacheMask)
233 	{
234 	    // Prefetch each page to put entries into the pmap
235 	    volatile UInt8 *	startAddr = (UInt8 *)_buffer;
236 	    volatile UInt8 *	endAddr   = (UInt8 *)_buffer + capacity;
237 
238 	    while (startAddr < endAddr)
239 	    {
240 		*startAddr;
241 		startAddr += page_size;
242 	    }
243 	}
244     }
245 
246     _ranges.v64->address = (mach_vm_address_t) _buffer;;
247     _ranges.v64->length  = _capacity;
248 
249     if (!super::initWithOptions(_ranges.v64, 1, 0,
250 				inTask, iomdOptions, /* System mapper */ 0))
251 	return false;
252 
253     if (mapTask)
254     {
255 	if (!reserved) {
256 	    reserved = IONew( ExpansionData, 1 );
257 	    if( !reserved)
258 		return( false );
259 	}
260 	reserved->map = createMappingInTask(mapTask, 0,
261 			    kIOMapAnywhere | (options & kIOMapCacheMask), 0, 0);
262 	if (!reserved->map)
263 	{
264 	    _buffer = 0;
265 	    return( false );
266 	}
267 	release();	    // map took a retain on this
268 	reserved->map->retain();
269 	removeMapping(reserved->map);
270 	mach_vm_address_t buffer = reserved->map->getAddress();
271 	_buffer = (void *) buffer;
272 	if (kIOMemoryTypeVirtual64 == (kIOMemoryTypeMask & iomdOptions))
273 	    _ranges.v64->address = buffer;
274     }
275 
276     setLength(_capacity);
277 
278     return true;
279 }
280 
281 IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::inTaskWithOptions(
282 					    task_t       inTask,
283                                             IOOptionBits options,
284                                             vm_size_t    capacity,
285                                             vm_offset_t  alignment)
286 {
287     IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
288 
289     if (me && !me->initWithPhysicalMask(inTask, options, capacity, alignment, 0)) {
290 	me->release();
291 	me = 0;
292     }
293     return me;
294 }
295 
296 IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
297 					    task_t	      inTask,
298                                             IOOptionBits      options,
299                                             mach_vm_size_t    capacity,
300                                             mach_vm_address_t physicalMask)
301 {
302     IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
303 
304     if (me && !me->initWithPhysicalMask(inTask, options, capacity, 1, physicalMask))
305     {
306 	me->release();
307 	me = 0;
308     }
309     return me;
310 }
311 
312 #ifndef __LP64__
313 bool IOBufferMemoryDescriptor::initWithOptions(
314                                IOOptionBits options,
315                                vm_size_t    capacity,
316                                vm_offset_t  alignment)
317 {
318     return (initWithPhysicalMask(kernel_task, options, capacity, alignment, (mach_vm_address_t)0));
319 }
320 #endif /* !__LP64__ */
321 
322 IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::withOptions(
323                                             IOOptionBits options,
324                                             vm_size_t    capacity,
325                                             vm_offset_t  alignment)
326 {
327     IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
328 
329     if (me && !me->initWithPhysicalMask(kernel_task, options, capacity, alignment, 0)) {
330 	me->release();
331 	me = 0;
332     }
333     return me;
334 }
335 
336 
337 /*
338  * withCapacity:
339  *
340  * Returns a new IOBufferMemoryDescriptor with a buffer large enough to
341  * hold capacity bytes.  The descriptor's length is initially set to the capacity.
342  */
343 IOBufferMemoryDescriptor *
344 IOBufferMemoryDescriptor::withCapacity(vm_size_t   inCapacity,
345                                        IODirection inDirection,
346                                        bool        inContiguous)
347 {
348     return( IOBufferMemoryDescriptor::withOptions(
349                inDirection | kIOMemoryUnshared
350                 | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
351                inCapacity, inContiguous ? inCapacity : 1 ));
352 }
353 
354 #ifndef __LP64__
355 /*
356  * initWithBytes:
357  *
358  * Initialize a new IOBufferMemoryDescriptor preloaded with bytes (copied).
359  * The descriptor's length and capacity are set to the input buffer's size.
360  */
361 bool IOBufferMemoryDescriptor::initWithBytes(const void * inBytes,
362                                              vm_size_t    inLength,
363                                              IODirection  inDirection,
364                                              bool         inContiguous)
365 {
366     if (!initWithPhysicalMask(kernel_task, inDirection | kIOMemoryUnshared
367 			      | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
368 			      inLength, inLength, (mach_vm_address_t)0))
369         return false;
370 
371     // start out with no data
372     setLength(0);
373 
374     if (!appendBytes(inBytes, inLength))
375         return false;
376 
377     return true;
378 }
379 #endif /* !__LP64__ */
380 
381 /*
382  * withBytes:
383  *
384  * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied).
385  * The descriptor's length and capacity are set to the input buffer's size.
386  */
387 IOBufferMemoryDescriptor *
388 IOBufferMemoryDescriptor::withBytes(const void * inBytes,
389                                     vm_size_t    inLength,
390                                     IODirection  inDirection,
391                                     bool         inContiguous)
392 {
393     IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
394 
395     if (me && !me->initWithPhysicalMask(
396                kernel_task, inDirection | kIOMemoryUnshared
397                 | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
398                inLength, inLength, 0 ))
399     {
400 	me->release();
401 	me = 0;
402     }
403 
404     if (me)
405     {
406 	// start out with no data
407 	me->setLength(0);
408 
409 	if (!me->appendBytes(inBytes, inLength))
410 	{
411 	    me->release();
412 	    me = 0;
413 	}
414     }
415     return me;
416 }
417 
418 /*
419  * free:
420  *
421  * Free resources
422  */
423 void IOBufferMemoryDescriptor::free()
424 {
425     // Cache all of the relevant information on the stack for use
426     // after we call super::free()!
427     IOOptionBits     flags         = _flags;
428     IOOptionBits     internalFlags = _internalFlags;
429     IOOptionBits     options   = _options;
430     vm_size_t        size      = _capacity;
431     void *           buffer    = _buffer;
432     IOMemoryMap *    map       = 0;
433     IOAddressRange * range     = _ranges.v64;
434     vm_offset_t      alignment = _alignment;
435 
436     if (alignment >= page_size)
437 	size = round_page(size);
438 
439     if (reserved)
440     {
441 	map = reserved->map;
442         IODelete( reserved, ExpansionData, 1 );
443 	if (map)
444 	    map->release();
445     }
446 
447     /* super::free may unwire - deallocate buffer afterwards */
448     super::free();
449 
450     if (options & kIOMemoryPageable)
451     {
452 #if IOALLOCDEBUG
453 	debug_iomallocpageable_size -= round_page(size);
454 #endif
455     }
456     else if (buffer)
457     {
458         if (internalFlags & kInternalFlagPhysical)
459         {
460             if (kInternalFlagPageSized & internalFlags)
461                 size = round_page(size);
462             IOKernelFreePhysical((mach_vm_address_t) buffer, size);
463         }
464         else if (alignment > 1)
465             IOFreeAligned(buffer, size);
466         else
467             IOFree(buffer, size);
468     }
469     if (range && (kIOMemoryAsReference & flags))
470 	IODelete(range, IOAddressRange, 1);
471 }
472 
473 /*
474  * getCapacity:
475  *
476  * Get the buffer capacity
477  */
478 vm_size_t IOBufferMemoryDescriptor::getCapacity() const
479 {
480     return _capacity;
481 }
482 
483 /*
484  * setLength:
485  *
486  * Change the buffer length of the memory descriptor.  When a new buffer
487  * is created, the initial length of the buffer is set to be the same as
488  * the capacity.  The length can be adjusted via setLength for a shorter
489  * transfer (there is no need to create more buffer descriptors when you
490  * can reuse an existing one, even for different transfer sizes).   Note
491  * that the specified length must not exceed the capacity of the buffer.
492  */
493 void IOBufferMemoryDescriptor::setLength(vm_size_t length)
494 {
495     assert(length <= _capacity);
496 
497     _length = length;
498     _ranges.v64->length = length;
499 }
500 
501 /*
502  * setDirection:
503  *
504  * Change the direction of the transfer.  This method allows one to redirect
505  * the descriptor's transfer direction.  This eliminates the need to destroy
506  * and create new buffers when different transfer directions are needed.
507  */
508 void IOBufferMemoryDescriptor::setDirection(IODirection direction)
509 {
510     _flags = (_flags & ~kIOMemoryDirectionMask) | direction;
511 #ifndef __LP64__
512     _direction = (IODirection) (_flags & kIOMemoryDirectionMask);
513 #endif /* !__LP64__ */
514 }
515 
516 /*
517  * appendBytes:
518  *
519  * Add some data to the end of the buffer.  This method automatically
520  * maintains the memory descriptor buffer length.  Note that appendBytes
521  * will not copy past the end of the memory descriptor's current capacity.
522  */
523 bool
524 IOBufferMemoryDescriptor::appendBytes(const void * bytes, vm_size_t withLength)
525 {
526     vm_size_t   actualBytesToCopy = min(withLength, _capacity - _length);
527     IOByteCount offset;
528 
529     assert(_length <= _capacity);
530 
531     offset = _length;
532     _length += actualBytesToCopy;
533     _ranges.v64->length += actualBytesToCopy;
534 
535     if (_task == kernel_task)
536 	bcopy(/* from */ bytes, (void *)(_ranges.v64->address + offset),
537 	      actualBytesToCopy);
538     else
539 	writeBytes(offset, bytes, actualBytesToCopy);
540 
541     return true;
542 }
543 
544 /*
545  * getBytesNoCopy:
546  *
547  * Return the virtual address of the beginning of the buffer
548  */
549 void * IOBufferMemoryDescriptor::getBytesNoCopy()
550 {
551     if (kIOMemoryTypePhysical64 == (_flags & kIOMemoryTypeMask))
552 	return _buffer;
553     else
554 	return (void *)_ranges.v64->address;
555 }
556 
557 
558 /*
559  * getBytesNoCopy:
560  *
561  * Return the virtual address of an offset from the beginning of the buffer
562  */
563 void *
564 IOBufferMemoryDescriptor::getBytesNoCopy(vm_size_t start, vm_size_t withLength)
565 {
566     IOVirtualAddress address;
567     if (kIOMemoryTypePhysical64 == (_flags & kIOMemoryTypeMask))
568 	address = (IOVirtualAddress) _buffer;
569     else
570 	address = _ranges.v64->address;
571 
572    if (start < _length && (start + withLength) <= _length)
573         return (void *)(address + start);
574     return 0;
575 }
576 
577 #ifndef __LP64__
578 void * IOBufferMemoryDescriptor::getVirtualSegment(IOByteCount offset,
579 							IOByteCount * lengthOfSegment)
580 {
581     void * bytes = getBytesNoCopy(offset, 0);
582 
583     if (bytes && lengthOfSegment)
584 	*lengthOfSegment = _length - offset;
585 
586     return bytes;
587 }
588 #endif /* !__LP64__ */
589 
590 #ifdef __LP64__
591 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 0);
592 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 1);
593 #else /* !__LP64__ */
594 OSMetaClassDefineReservedUsed(IOBufferMemoryDescriptor, 0);
595 OSMetaClassDefineReservedUsed(IOBufferMemoryDescriptor, 1);
596 #endif /* !__LP64__ */
597 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 2);
598 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 3);
599 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 4);
600 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 5);
601 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 6);
602 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 7);
603 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 8);
604 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 9);
605 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 10);
606 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 11);
607 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 12);
608 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 13);
609 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 14);
610 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 15);
611