|
|
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.