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