|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /**
25: * IOMemoryContainer.m
26: * Copyright 1997-98 Apple Computer Inc. All Rights Reserved.
27: *
28: * IOMemoryContainer describes client memory. It is constructed and manipulated
29: * by MemoryDescriptor classes. It is not "visible" to client and server
30: * code. Note that IOMemoryContainer objects do not provide enumeration or
31: * positioning services: they only describe a particular range of memory.
32: *
33: * IOMemoryContainer may be used in both user space and kernel space.
34: * The memory described by a user-space IOMemoryContainer can be
35: * accessed by the creating task as a collection of logical extents.
36: * Kernel processes, after making the memory resident, can access
37: * the container memory as either logical or physical extents.
38: */
39: #import <driverkit/IOMemoryContainer.h>
40: #import <driverkit/generalFuncs.h>
41: #import <mach/vm_param.h>
42:
43: /*
44: * This is the information that is transferred by the serialization
45: * methods. This fixed-length header will be followed by <rangeCount>
46: * IORange values.
47: */
48: typedef struct {
49: vm_task_t client;
50: unsigned int rangeCount;
51: } IOMemoryContainerSerialization;
52: #define kSerializationSize (sizeof (IOMemoryContainerSerialization))
53:
54: @interface IOMemoryContainer(Private)
55: - (id) init;
56: - (id) free;
57: @end /* IOMemoryContainer(Private) */
58:
59: @implementation IOMemoryContainer(Private)
60: /**
61: * Initialize an empty IOMemoryContainer object.
62: */
63: - (id) init
64: {
65: /*
66: * Initialize all fields to zero (but with one reference).
67: */
68: options = 0;
69: retainCount = 1;
70: residencyCount = 0;
71: #ifdef KERNEL
72: client = IOVmTaskSelf();
73: #else
74: client = IO_NULL_VM_TASK;
75: #endif /* KERNEL */
76: rangeCount = 0;
77: totalByteCount = 0;
78: range.logical.start = 0;
79: range.logical.size = 0;
80: return (self);
81: }
82:
83: /**
84: * Dispose of the object. Note that free ignores the retainCount and
85: * referenceCount and always frees the IOMemoryContainer object.
86: */
87: - (id) free
88: {
89: if (rangeCount > 1 && range.vector != NULL) {
90: if ((options & ioRangeByReference) == 0) {
91: IOFree((void *) range.vector, rangeCount * sizeof (IORange));
92: }
93: rangeCount = 0;
94: range.vector = NULL;
95: }
96: return [super free];
97: }
98:
99: @end /* IOMemoryContainer(Private) */
100:
101:
102: @implementation IOMemoryContainer
103:
104: /**
105: * Create an IOMemoryContainer object for a logical scatter-gather list in the
106: * caller's address map. The scatter-gather list is provided in DriverKit
107: * IORange format. If byReference is TRUE, the IOMemoryContainer will hold
108: * a reference to the range vector (which must remain addressable during the
109: * lifetime of the object). If FALSE, the range vector will be copied into
110: * the IOMemoryContainer object.
111: */
112: - (id) initWithIORange
113: : (const IORange *) ioRange
114: count : (unsigned int) thisRangeCount
115: byReference : (BOOL) initByReference
116: {
117: unsigned int size;
118: unsigned int i;
119:
120: switch (thisRangeCount) {
121: case 0:
122: [self initWithAddress
123: : NULL
124: length : 0
125: ];
126: break;
127: case 1:
128: [self initWithAddress
129: : (void *) ioRange->start
130: length : ioRange->size
131: ];
132: break;
133: default:
134: [self init];
135: rangeCount = thisRangeCount;
136: size = thisRangeCount * sizeof (IORange);
137: if (initByReference) {
138: options |= ioRangeByReference;
139: range.vector = ioRange;
140: }
141: else {
142: range.vector = IOMalloc(size);
143: IOCopyMemory(
144: (void *) ioRange, /* Copy from here */
145: (void *) range.vector, /* Copy to here */
146: size, /* Total byte count */
147: 4 /* Bytes per transfer */
148: );
149: }
150: for (i = 0; i < thisRangeCount; i++) {
151: totalByteCount += ioRange[i].size;
152: }
153: break;
154: }
155: return (self);
156: }
157:
158: /**
159: * Create an IOMemoryContainer object for a single logical range.
160: */
161: - (id) initWithAddress
162: : (void *) address
163: length : (unsigned int) length
164: {
165: [self init];
166: rangeCount = 1;
167: range.logical.start = (unsigned int) address;
168: range.logical.size = length;
169: totalByteCount = length;
170: return (self);
171: }
172:
173:
174: /**
175: * Create an IOMemoryContainer object for a logical scatter-gather list in the
176: * caller's address map. The scatter-gather list is provided in BSD
177: * Unix iov format.
178: */
179: - (id) initWithIOV
180: : (const struct iovec *) iov
181: count : (unsigned int) iovCount
182: {
183: unsigned int size;
184: unsigned int i;
185:
186: switch (iovCount) {
187: case 0:
188: [self initWithAddress : NULL
189: length : 0
190: ];
191: break;
192: case 1:
193: [self initWithAddress : iov->iov_base
194: length : iov->iov_len
195: ];
196: break;
197: default:
198: [self init];
199: range.vector = IOMalloc(size);
200: rangeCount = iovCount;
201: size = iovCount * sizeof (IORange);
202: for (i = 0; i < iovCount; i++, iov++) {
203: ((IORange *) range.vector)[i].start =
204: (unsigned int) iov->iov_base;
205: ((IORange *) range.vector)[i].size = iov->iov_len;
206: totalByteCount += iov->iov_len;
207: }
208: break;
209: }
210: return (self);
211: }
212:
213: /**
214: * Accessor methods
215: */
216: - (unsigned int) rangeCount
217: {
218: return (rangeCount);
219: }
220:
221: - (unsigned int) totalByteCount
222: {
223: return (totalByteCount);
224: }
225:
226: /**
227: * Manage the retain/release reference count. See NSObject for details.
228: */
229: - (unsigned int) retainCount
230: {
231: return (retainCount);
232: }
233:
234: - (id) retain
235: {
236: ++retainCount;
237: return (self);
238: }
239:
240: - (oneway void) release
241: {
242: if (--retainCount == 0) {
243: [self free];
244: }
245: }
246:
247: /**
248: * Return one range segment. These return errors if the parameter is
249: * incorrect (calling logicalRange on physicalRanges, index out of bounds).
250: */
251:
252: /**
253: * Return the logical address and length for the i'th logical range.
254: * Return IO_R_INVALID_ARG if the index is outside the allocated range.
255: */
256: - (IOReturn) logicalRange
257: : (IORange *) logicalRange
258: index : (unsigned int) thisIndex
259: {
260: IOReturn ioReturn;
261:
262: if (thisIndex >= rangeCount || logicalRange == NULL) {
263: ioReturn = IO_R_INVALID_ARG;
264: }
265: else {
266: ioReturn = IO_R_SUCCESS;
267: if (rangeCount == 1) {
268: *logicalRange = range.logical;
269: }
270: else {
271: *logicalRange = range.vector[thisIndex];
272: }
273: }
274: return (ioReturn);
275: }
276: @end /* IOMemoryContainer : Object */
277:
278: #ifdef KERNEL
279: @implementation IOMemoryContainer(Kernel)
280:
281: /*
282: * Kernel-specific methods. By default, non-kernel objects contain a NULL
283: * vm_task_t value. Kernel tasks will set the client to the task that
284: * provided this memory.
285: */
286:
287: - (vm_task_t) client
288: {
289: return (client);
290: }
291:
292: - (void) setClient
293: : (vm_task_t) thisClient
294: {
295: client = thisClient;
296: }
297:
298:
299: /**
300: * Make the memory described by this IOMemoryContainer resident.
301: * This is called by the virtual memory manager and/or file system before
302: * starting an I/O request. Residency is an all-or-nothing process. The
303: * IOMemoryContainer maintains a reference count: the first caller makes the
304: * memory resident; the others just increment the count. This method returns
305: * an error status if any range cannot be made resident and all memory will
306: * be made pageable. This method may only be called by kernel servers.
307: */
308: - (IOReturn) wireMemory
309: : (BOOL) forReading
310: {
311: IOReturn ioReturn = IO_R_SUCCESS;
312: kern_return_t status;
313: unsigned int i;
314: unsigned int successCount;
315: IORange thisRange;
316: vm_offset_t rangeStart;
317: vm_offset_t rangeEnd;
318:
319: /*
320: * Increment the residency counter. If it was not zero when we were
321: * called, we have already made this memory resident, so just exit.
322: * If it was zero, this is the first call and we must make all ranges
323: * resident.
324: */
325: if (forReading)
326: options |= ioWiredForRead;
327: else
328: options &= ~ioWiredForRead;
329:
330: if (residencyCount++ == 0) { /* NOTE: AtomicIncrement */
331: successCount = 0;
332: for (i = 0; i < rangeCount && ioReturn == IO_R_SUCCESS; i++) {
333: ioReturn = [self logicalRange : &thisRange
334: index : i
335: ];
336: if (ioReturn == IO_R_SUCCESS) {
337: rangeStart = trunc_page(thisRange.start);
338: rangeEnd = round_page(thisRange.start + thisRange.size);
339: status = vm_map_pageable(
340: client,
341: rangeStart,
342: rangeEnd,
343: FALSE /* Wire range */
344: );
345: if (status != KERN_SUCCESS)
346: ioReturn = IO_R_CANT_WIRE; /* Wire failed */
347: else {
348: if (forReading == FALSE) {
349: /*
350: * Is this really needed?
351: */
352: // flush_cache_v(rangeStart, rangeEnd - rangeStart);
353: }
354: ++successCount;
355: }
356: }
357: }
358: }
359: if (ioReturn != IO_R_SUCCESS) {
360: /*
361: * Unwire partial preparations.
362: */
363: for (i = 0; i < successCount; i++) {
364: [self logicalRange : &thisRange index : i];
365: rangeStart = trunc_page(thisRange.start);
366: rangeEnd = round_page(thisRange.start + thisRange.size);
367: (void) vm_map_pageable(
368: client,
369: rangeStart,
370: rangeEnd,
371: TRUE /* Unwire range */
372: );
373: }
374: --residencyCount;
375: }
376: return (ioReturn);
377: }
378:
379: /**
380: * Make the memory described by this underlying IOMemoryContainer pageable.
381: * This is called by the virtual memory manager and/or file system after
382: * completing an I/O request. The IOMemoryContainer maintains a reference
383: * count: the last caller frees the memory the others just decrement the count.
384: * This method returns an error status if any range could not be freed,
385: * but always tries to free all ranges. Return IO_R_VM_FAILURE if any range
386: * can't be unwired (but there is no indication as to which range).
387: */
388: - (IOReturn) unwireMemory
389: {
390: IOReturn ioReturn = IO_R_SUCCESS;
391: IOReturn finalResult = IO_R_SUCCESS;
392: kern_return_t status;
393: unsigned int i;
394: IORange thisRange;
395: vm_offset_t rangeStart;
396: vm_offset_t rangeEnd;
397:
398: /*
399: * Decrement the residency counter. If is zero after decrement, this
400: * is the last caller, so make the ranges pageable.
401: */
402: if (--residencyCount == 0) { /* NOTE: AtomicDecrement */
403: for (i = 0; i < rangeCount; i++) {
404: ioReturn = [self logicalRange : &thisRange
405: index : i
406: ];
407: if (finalResult != IO_R_SUCCESS) {
408: finalResult = ioReturn;
409: }
410: else {
411: rangeStart = trunc_page(thisRange.start);
412: rangeEnd = round_page(thisRange.start + thisRange.size);
413: status = vm_map_pageable(
414: client,
415: rangeStart,
416: rangeEnd,
417: TRUE /* Make range pageable */
418: );
419: if (status != KERN_SUCCESS && finalResult == IO_R_SUCCESS) {
420: finalResult = IO_R_VM_FAILURE;
421: }
422: }
423: }
424: }
425: return (finalResult);
426: }
427:
428: /**
429: * Normalize cache coherency (if needed by this particular hardware
430: * architecture) before starting a DMA operation. This normalizes all
431: * memory described by this IOMemoryContainer. This is used as follows:
432: * mem = [[IOMemoryDescriptor alloc] initWithAddress
433: * : address
434: * length : length];
435: * [mem makeResident];
436: * [mem checkpoint : ioCheckpointInput];
437: * ... Extract physical ranges and do DMA I/O ...
438: * [mem checkpoint : ioCheckpointComplete];
439: * [mem makePageable];
440: * [mem free];
441: * A checkpoint call may specify any combination of ioCheckpointInput,
442: * ioCheckpointOutput, or ioCheckpointNoDirection. After DMA completes,
443: * drivers must call checkpoint with ioCheckpointComplete as the only
444: * parameter. The actual operation of checkpoint is processor-specific.
445: * Note that wireMemory and unwireMemory will call checkpoint with appropriate
446: * options: it need only be called explicitly if the same buffer is used
447: * for multiple I/O requests, as might be the case for a video-to-disk
448: * process.
449: */
450: - (IOReturn) checkpoint
451: : (IOMemoryCheckpointOption) option
452: {
453: /* Override if necessary */
454: return (IO_R_SUCCESS);
455: }
456:
457: @end /* IOMemoryContainer(Kernel) */
458: #endif /* KERNEL */
459:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.