|
|
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: * IOSimpleMemoryDescriptor.m
26: * Copyright 1997-98 Apple Computer Inc. All Rights Reserved.
27: *
28: * IOSimpleMemoryDescriptor provides a limited subset of IOMemoryDescriptor
29: * functionality for the benefit of low-level drivers (such as the SCSI bus
30: * interface driver). The IOSimpleMemoryDescriptor supports a single
31: * input logical range. It cannot be replicated, and does not have a separate
32: * IOMemoryContainer. It supports the following IOMemoryDescriptor methods:
33: * allocSingleRange
34: * free
35: * currentOffset
36: * totalByteCount
37: * state
38: * setState
39: * setPosition
40: * setOffset
41: * getLogicalRanges
42: * getPhysicalRanges
43: * checkpoint
44: * Other methods must not be used. They fail with an IOPanic.
45: */
46: #ifdef KERNEL
47: #import <driverkit/IOSimpleMemoryDescriptor.h>
48: #import <mach/vm_param.h>
49:
50: /*
51: * Compute the start of the next physical page
52: */
53: #define next_page(x) (trunc_page(((unsigned int) x) + page_size))
54:
55: @interface IOSimpleMemoryDescriptor(Private)
56: - (IOReturn) getCurrentPhysicalRange;
57: - (void) validate;
58: - (void) setPositionAtEnd;
59: @end /* IOSimpleMemoryDescriptor(Private) */
60:
61: @implementation IOSimpleMemoryDescriptor(Private)
62:
63: /**
64: * Return the physical address that corresponds to the current logical
65: * address. The state is valid at this point. This method sets the
66: * physicalPageLength to the maximumn number of bytes that can be
67: * transferred in this page.
68: */
69: - (IOReturn) getCurrentPhysicalRange
70: {
71: IOReturn ioReturn;
72: unsigned int nextPageAddress;
73:
74: state.physicalOffset = 0; /* At page start */
75: ioReturn = IOPhysicalFromVirtual(
76: client,
77: state.ioRange.start + state.currentOffset,
78: (vm_offset_t *) &state.physical.address
79: );
80: if (ioReturn != IO_R_SUCCESS) {
81: state.physical.address = 0;
82: state.physical.length = 0;
83: }
84: else {
85: /*
86: * The amount we can transfer is the number of bytes
87: * from the current start index to the next page
88: * (limited by scsiReq->maxTransfer). Mach lacks
89: * a method for determining the page size. We'll
90: * use 4096 for convenience (the only cost is extra
91: * cycles through the for loop).
92: */
93: nextPageAddress = next_page(state.physical.address);
94: state.physical.length =
95: nextPageAddress - ((unsigned int) state.physical.address);
96: }
97: return (ioReturn);
98: }
99:
100: /**
101: * Validate the state so that all state values agree with
102: * the currentOffset.
103: */
104: - (void) validate
105: {
106: if (state.currentOffset >= [self totalByteCount]) {
107: [self setPositionAtEnd];
108: }
109: state.physicalOffset = 0;
110: valid = TRUE;
111: }
112:
113: /*
114: * Force the state to the end of the entire container (for reposition
115: * errors).
116: */
117: - (void) setPositionAtEnd
118: {
119: state.currentOffset = state.ioRange.size;
120: }
121:
122: @end /* IOSimpleMemoryDescriptor(Private) */
123:
124: @implementation IOSimpleMemoryDescriptor
125:
126: /**
127: * Destroy any existing data, replacing it with the specified data.
128: */
129: - (id) initWithAddress
130: : (void *) address
131: length : (unsigned int) length
132: {
133: retainCount = 1;
134: ioMemoryContainer = NULL;
135: state.currentOffset = 0;
136: state.rangeIndex = (length == 0) ? 0 : 1;
137: state.ioRange.start = (unsigned int) address;
138: state.ioRange.size = length;
139: state.logicalOffset = 0xDEADBEEF; /* Unused */
140: state.physicalOffset = 0; /* Invalidate */
141: valid = TRUE;
142: options = 0;
143: maxSegmentCount = length;
144: client = IOVmTaskSelf();
145: return (self);
146: }
147:
148: - (id) initWithIORange
149: : (const IORange *) ioRange
150: count : (unsigned int) count
151: byReference : (BOOL) byReference
152: {
153: switch (count) {
154: case 0:
155: [self initWithAddress: (void *) NULL length: 0];
156: break;
157: case 1:
158: [self initWithAddress: (void *) ioRange->start
159: length: ioRange->size];
160: break;
161: default:
162: IOPanic("IOSimpleMemoryDescriptor : "
163: "initWithIORange (only one range allowed)");
164: return [self free];
165: }
166: return (self);
167: }
168:
169: - (id) initWithIOV
170: : (const struct iovec *) iov
171: count : (unsigned int) iovCount
172: {
173: switch (iovCount) {
174: [self initWithAddress: (void *) NULL length: 0];
175: break;
176: case 1:
177: [self initWithAddress: (void *) iov->iov_base
178: length: iov->iov_len];
179: break;
180: default:
181: IOPanic("IOSimpleMemoryDescriptor : "
182: "initWithIOV (only one range allowed)");
183: return [self free];
184: }
185: return (self);
186: }
187:
188: /**
189: * Return a copy of this IOMemoryDescriptor and its IOMemoryContainer.
190: * The IOMemoryContainer's reference count will be incremented.
191: * The current position is not duplicated.
192: */
193: - (id) replicate
194: {
195: IOPanic("IOSimpleMemoryDescriptor : replicate invalid");
196: return (NULL);
197: }
198:
199: /**
200: * Accessor methods
201: */
202: - (unsigned int) rangeCount
203: {
204: return (state.rangeIndex);
205: }
206:
207: - (unsigned int) totalByteCount
208: {
209: return (state.ioRange.size);
210: }
211:
212: /*
213: * Kernel-specific methods. By default, non-kernel objects contain a NULL
214: * vm_task_t value. Kernel tasks will set the client to the task that
215: * provided this memory.
216: */
217:
218: - (vm_task_t) client
219: {
220: return (client);
221: }
222:
223: - (void) setClient
224: : (vm_task_t) thisClient
225: {
226: client = thisClient;
227: }
228:
229:
230: /**
231: * Return one or more logical ranges. Return zero if the transfer is outside
232: * of the defined range (I.e., if all data has been transferred).
233: * @param maxRanges The maximum number of ranges to retrieve.
234: * @param maxByteCount The maximum number of bytes to retrieve
235: * in the entire sequence. To use the remaining
236: * transfer count, specify UINT_MAX (from limits.h).
237: * @param newPosition The new value of currentOffset (may be NULL)
238: * @param actualRanges The actual number of ranges retrieved
239: * (NULL if not needed)
240: * @param logicalRanges A vector of logical range elements.
241: * Return the total number of bytes in all ranges. Return zero if the current
242: * offset is beyond the end of the range.
243: */
244: - (unsigned int) getLogicalRanges
245: : (unsigned int) maxRanges
246: maxByteCount : (unsigned int) maxByteCount
247: newPosition : (unsigned int *) newPosition
248: actualRanges : (unsigned int *) actualRanges
249: logicalRanges : (IORange *) logicalRanges
250: {
251: unsigned int transferCount = 0;
252: unsigned int byteCount;
253: unsigned int rangeCount;
254:
255: if (valid == FALSE) {
256: [self validate];
257: }
258: for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) {
259: byteCount = state.ioRange.size - state.currentOffset;
260: if (byteCount > maxSegmentCount) {
261: byteCount = maxSegmentCount;
262: }
263: if (byteCount + transferCount > maxByteCount) {
264: byteCount = maxByteCount - transferCount;
265: }
266: if (byteCount == 0) {
267: break;
268: }
269: logicalRanges->size = byteCount;
270: logicalRanges->start =
271: (state.ioRange.start + state.currentOffset);
272: logicalRanges++;
273: transferCount += byteCount;
274: state.currentOffset += byteCount;
275: }
276: if (actualRanges != NULL) {
277: *actualRanges = rangeCount;
278: }
279: if (newPosition != NULL) {
280: *newPosition = state.currentOffset;
281: }
282: state.physicalOffset = 0; /* Invalid physical range */
283: return (transferCount);
284: }
285:
286: /**
287: * Return one or more physical ranges. Return zero if the transfer is outside
288: * of the defined range (I.e., if all data has been transferred).
289: * @param maxRanges The maximum number of ranges to retrieve.
290: * @param maxByteCount The maximum number of bytes to retrieve
291: * in the entire sequence. To use the remaining
292: * transfer count, specify UINT_MAX (from limits.h).
293: * @param newPosition The new value of currentOffset (may be NULL)
294: * @param actualRanges The actual number of ranges retrieved
295: * (NULL if not needed)
296: * @param physicalRanges A vector of physical range elements.
297: * Return the total number of bytes in all ranges. Return zero if the current
298: * offset is beyond the end of the range.
299: */
300: - (unsigned int) getPhysicalRanges
301: : (unsigned int) maxRanges
302: maxByteCount : (unsigned int) maxByteCount
303: newPosition : (unsigned int *) newPosition
304: actualRanges : (unsigned int *) actualRanges
305: physicalRanges : (PhysicalRange *) physicalRanges
306: {
307: unsigned int transferCount = 0;
308: unsigned int byteCount;
309: unsigned int rangeCount;
310:
311: if (valid == FALSE) {
312: [self validate];
313: }
314: for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) {
315: byteCount = state.ioRange.size - state.currentOffset;
316: if (byteCount > maxSegmentCount) {
317: byteCount = maxSegmentCount;
318: }
319: if (byteCount + transferCount > maxByteCount) {
320: byteCount = maxByteCount - transferCount;
321: }
322: if (byteCount == 0) {
323: break;
324: }
325: if (state.physicalOffset == 0
326: || state.physicalOffset >= state.physical.length) {
327: if ([self getCurrentPhysicalRange] != IO_R_SUCCESS) {
328: break;
329: }
330: }
331: if (byteCount > (state.physical.length - state.physicalOffset)) {
332: byteCount = state.physical.length - state.physicalOffset;
333: }
334: physicalRanges->length = byteCount;
335: physicalRanges->address = (void *)
336: (((unsigned int) state.physical.address)
337: + state.physicalOffset);
338: physicalRanges++;
339: transferCount += byteCount;
340: state.currentOffset += byteCount;
341: state.physicalOffset += byteCount;
342: }
343: if (actualRanges != NULL) {
344: *actualRanges = rangeCount;
345: }
346: if (newPosition != NULL) {
347: *newPosition = state.currentOffset;
348: }
349: return (transferCount);
350: }
351:
352: /**
353: * Make the memory described by this IOMemoryDescriptor resident.
354: * This is called by the virtual memory manager and/or file system before
355: * starting an I/O request. Residency is an all-or-nothing process. The
356: * IOMemoryDescriptor maintains a reference count: the first caller makes the
357: * memory resident; the others just increment the count. This method returns
358: * an error status if any range cannot be made resident and all memory will
359: * be made pageable. This method may only be called by kernel servers.
360: */
361: - (IOReturn) wireMemory
362: : (BOOL) forReading;
363: {
364: IOReturn ioReturn = IO_R_SUCCESS;
365: kern_return_t status;
366: vm_offset_t rangeStart;
367: vm_offset_t rangeEnd;
368:
369: if (forReading) {
370: options |= ioWiredForRead;
371: }
372: else {
373: options &= ~ioWiredForRead;
374: }
375: if (residencyCount++ == 0) { /* Note: AtomicIncrement */
376: rangeStart = trunc_page(state.ioRange.start);
377: rangeEnd = round_page(
378: state.ioRange.start + state.ioRange.size);
379: status = vm_map_pageable(
380: /* (vm_map_t) */ client,
381: rangeStart,
382: rangeEnd,
383: FALSE /* Wire range */
384: );
385: if (status != KERN_SUCCESS) {
386: ioReturn = IO_R_CANT_WIRE;
387: --residencyCount;
388: }
389: else if (forReading == FALSE) {
390: /*
391: * Is this really needed?
392: */
393: // flush_cache_v(rangeStart, rangeEnd - rangeStart);
394: }
395: }
396: return (ioReturn);
397: }
398:
399: /**
400: * Make the memory described by this underlying IOMemoryContainer pageable.
401: * This is called by the virtual memory manager and/or file system after
402: * completing an I/O request. The IOMemoryContainer maintains a reference
403: * count: the last caller frees the memory the others just decrement the count.
404: * This method returns an error status if any range could not be freed,
405: * but always tries to free all ranges. Return IO_R_VM_FAILURE if any range
406: * can't be unwired (but there is no indication as to which range).
407: */
408: - (IOReturn) unwireMemory
409: {
410: IOReturn ioReturn = IO_R_SUCCESS;
411: kern_return_t status;
412: vm_offset_t rangeStart;
413: vm_offset_t rangeEnd;
414:
415: if (residencyCount-- == 1) { /* NOTE: AtomicDecrement */
416: rangeStart = trunc_page(state.ioRange.start);
417: rangeEnd = round_page(
418: state.ioRange.start + state.ioRange.size);
419: status = vm_map_pageable(
420: /* (vm_map_t) */ client,
421: rangeStart,
422: rangeEnd,
423: TRUE /* Make pageable */
424: );
425: if (status != KERN_SUCCESS) {
426: ioReturn = IO_R_CANT_WIRE;
427: }
428: }
429: return (ioReturn);
430: }
431:
432: @end /* IOSimpleMemoryDescriptor : IOMemoryDescriptor */
433: #endif /* KERNEL */
434:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.