1 /*
2  * Copyright (c) 1998-2007 Apple 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 #include <IOKit/IOSubMemoryDescriptor.h>
30 
31 #include "IOKitKernelInternal.h"
32 
33 #define super IOMemoryDescriptor
34 
35 OSDefineMetaClassAndStructors(IOSubMemoryDescriptor, IOMemoryDescriptor)
36 
37 IOReturn IOSubMemoryDescriptor::redirect( task_t safeTask, bool doRedirect )
38 {
39 #ifdef __LP64__
40     super::redirect( safeTask, doRedirect );
41 #endif /* __LP64__ */
42     return( _parent->redirect( safeTask, doRedirect ));
43 }
44 
45 IOSubMemoryDescriptor *
46 IOSubMemoryDescriptor::withSubRange(IOMemoryDescriptor *	of,
47 				IOByteCount		offset,
48 				IOByteCount		length,
49 				IOOptionBits		options)
50 {
51     IOSubMemoryDescriptor *self = new IOSubMemoryDescriptor;
52 
53     if (self && !self->initSubRange(of, offset, length, (IODirection) options)) {
54         self->release();
55 	self = 0;
56     }
57     return self;
58 }
59 
60 bool IOSubMemoryDescriptor::initSubRange( IOMemoryDescriptor * parent,
61 					IOByteCount offset, IOByteCount length,
62 					IODirection direction )
63 {
64     if( parent && ((offset + length) > parent->getLength()))
65 	return( false);
66 
67     /*
68      * We can check the _parent instance variable before having ever set it
69      * to an initial value because I/O Kit guarantees that all our instance
70      * variables are zeroed on an object's allocation.
71      */
72 
73     if( !_parent) {
74 	if( !super::init())
75 	    return( false );
76     } else {
77 	/*
78 	 * An existing memory descriptor is being retargeted to
79 	 * point to somewhere else.  Clean up our present state.
80 	 */
81 
82 	_parent->release();
83     }
84 
85     if (parent) {
86 	parent->retain();
87 	_tag	= parent->getTag();
88     }
89     else {
90         _tag    = 0;
91     }
92     _parent	= parent;
93     _start	= offset;
94     _length	= length;
95     _flags	= direction;
96     _flags |= kIOMemoryThreadSafe;
97 
98 #ifndef __LP64__
99     _direction  = (IODirection) (_flags & kIOMemoryDirectionMask);
100 #endif /* !__LP64__ */
101 
102     return( true );
103 }
104 
105 void IOSubMemoryDescriptor::free( void )
106 {
107     if( _parent)
108 	_parent->release();
109 
110     super::free();
111 }
112 
113 addr64_t
114 IOSubMemoryDescriptor::getPhysicalSegment(IOByteCount offset, IOByteCount * length, IOOptionBits options)
115 {
116     addr64_t	address;
117     IOByteCount	actualLength;
118 
119     assert(offset <= _length);
120 
121     if( length)
122         *length = 0;
123 
124     if( offset >= _length)
125         return( 0 );
126 
127     address = _parent->getPhysicalSegment( offset + _start, &actualLength, options );
128 
129     if( address && length)
130 	*length = min( _length - offset, actualLength );
131 
132     return( address );
133 }
134 
135 IOReturn IOSubMemoryDescriptor::setPurgeable( IOOptionBits newState,
136                                     IOOptionBits * oldState )
137 {
138     IOReturn err;
139 
140     err = _parent->setPurgeable( newState, oldState );
141 
142     return( err );
143 }
144 
145 IOReturn IOSubMemoryDescriptor::prepare(
146 		IODirection forDirection)
147 {
148     IOReturn	err;
149 
150     err = _parent->prepare( forDirection);
151 
152     return( err );
153 }
154 
155 IOReturn IOSubMemoryDescriptor::complete(
156 		IODirection forDirection)
157 {
158     IOReturn	err;
159 
160     err = _parent->complete( forDirection);
161 
162     return( err );
163 }
164 
165 IOMemoryMap * IOSubMemoryDescriptor::makeMapping(
166 	IOMemoryDescriptor *	owner,
167 	task_t			intoTask,
168 	IOVirtualAddress	address,
169 	IOOptionBits		options,
170 	IOByteCount		offset,
171 	IOByteCount		length )
172 {
173     IOMemoryMap * mapping = 0;
174 
175 #ifndef __LP64__
176     if (!(kIOMap64Bit & options))
177     {
178 	panic("IOSubMemoryDescriptor::makeMapping !64bit");
179     }
180 #endif /* !__LP64__ */
181 
182     mapping = (IOMemoryMap *) _parent->makeMapping(
183 					owner,
184 					intoTask,
185 					address,
186 					options, _start + offset, length );
187 
188     return( mapping );
189 }
190 
191 uint64_t
192 IOSubMemoryDescriptor::getPreparationID( void )
193 {
194     uint64_t pID;
195 
196     if (!super::getKernelReserved())
197         return (kIOPreparationIDUnsupported);
198 
199     pID = _parent->getPreparationID();
200     if (reserved->kernReserved[0] != pID)
201     {
202         reserved->kernReserved[0] = pID;
203         reserved->preparationID   = kIOPreparationIDUnprepared;
204         super::setPreparationID();
205     }
206 
207     return (super::getPreparationID());
208 }
209 
210 IOReturn
211 IOSubMemoryDescriptor::getPageCounts(IOByteCount * residentPageCount,
212                                      IOByteCount * dirtyPageCount)
213 {
214     return (_parent->getPageCounts(residentPageCount, dirtyPageCount));
215 }
216