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