|
|
1.1.1.4 ! root 1: /* $Id: posix-memory.c,v 1.7 2009/08/30 21:50:17 fredette Exp $ */ 1.1 root 2: 1.1.1.2 root 3: /* host/posix/posix-memory.c - implementation of memory on a POSIX system: */ 1.1 root 4: 5: /* 6: * Copyright (c) 2003 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.4 ! root 37: _TME_RCSID("$Id: posix-memory.c,v 1.7 2009/08/30 21:50:17 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/bus-device.h> 1.1.1.4 ! root 41: #include <tme/hash.h> 1.1 root 42: #include <fcntl.h> 43: #include <stdio.h> 44: #include <strings.h> 45: #include <sys/stat.h> 46: #ifdef HAVE_MMAP 47: #include <sys/types.h> 48: #include <sys/mman.h> 49: #endif /* HAVE_MMAP */ 50: 51: /* macros: */ 52: #define TME_POSIX_MEMORY_RAM (0) 53: #define TME_POSIX_MEMORY_ROM (1) 54: #define TME_POSIX_MEMORY_PERSISTENT (2) 55: 1.1.1.4 ! root 56: /* the minimum size of a cacheable RAM: */ ! 57: #define TME_MEMORY_POSIX_CACHEABLE_SIZE_RAM (1024 * 1024) ! 58: ! 59: /* the minimum size of a cacheable ROM: */ ! 60: #define TME_MEMORY_POSIX_CACHEABLE_SIZE_ROM (64 * 1024) ! 61: ! 62: /* the size of the writable TLB entry set: */ ! 63: #define TME_MEMORY_POSIX_TLBS_SIZE (631) ! 64: 1.1 root 65: /* structures: */ 1.1.1.4 ! root 66: ! 67: /* a valids bitmask: */ ! 68: struct tme_posix_memory_valids { ! 69: ! 70: /* valid bitmasks are kept on a linked list: */ ! 71: struct tme_posix_memory_valids *tme_posix_memory_valids_next; ! 72: ! 73: /* the log2 of the page size for this valids bitmask: */ ! 74: tme_uint32_t tme_posix_memory_valids_page_size_log2; ! 75: ! 76: /* the valids bitmask: */ ! 77: tme_shared tme_uint8_t tme_posix_memory_valids_bitmask[1]; ! 78: }; ! 79: ! 80: /* the memory structure: */ 1.1 root 81: struct tme_posix_memory { 82: 83: /* our simple bus device header: */ 84: struct tme_bus_device tme_posix_memory_device; 85: 1.1.1.4 ! root 86: /* the mutex protecting the device: */ ! 87: tme_mutex_t tme_posix_memory_mutex; ! 88: 1.1 root 89: /* our memory type: */ 90: unsigned int tme_posix_memory_type; 91: 92: /* the file descriptor to any backing file: */ 93: int tme_posix_memory_fd; 94: 95: /* this is nonzero if the backing file is mmapped: */ 96: int tme_posix_memory_mapped; 97: 98: /* our rwlock: */ 1.1.1.4 ! root 99: tme_rwlock_t tme_posix_memory_rwlock; 1.1 root 100: 101: /* our memory contents: */ 102: tme_uint8_t *tme_posix_memory_contents; 1.1.1.4 ! root 103: ! 104: /* our writable TLB entry set: */ ! 105: struct tme_token **tme_posix_memory_tlb_tokens; ! 106: ! 107: /* any valids bitmasks: */ ! 108: struct tme_posix_memory_valids *tme_posix_memory_valids; ! 109: ! 110: /* the current writable TLB size: */ ! 111: tme_uint32_t tme_posix_memory_tlb_size; ! 112: ! 113: /* our bus cacheable structure: */ ! 114: struct tme_bus_cacheable tme_posix_memory_cacheable; 1.1 root 115: }; 116: 117: /* the memory bus cycle handler: */ 118: static int 119: _tme_posix_memory_bus_cycle(void *_memory, struct tme_bus_cycle *cycle) 120: { 121: struct tme_posix_memory *memory; 122: 123: /* recover our data structure: */ 124: memory = (struct tme_posix_memory *) _memory; 125: 126: /* run the cycle: */ 127: tme_bus_cycle_xfer_memory(cycle, 128: ((cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE 129: && memory->tme_posix_memory_type == TME_POSIX_MEMORY_ROM) 130: ? NULL 131: : memory->tme_posix_memory_contents), 132: memory->tme_posix_memory_device.tme_bus_device_address_last); 133: 134: /* no faults: */ 135: return (TME_OK); 136: } 137: 1.1.1.4 ! root 138: /* this invalidates all outstanding TLBs. it must be called with the ! 139: mutex held: */ ! 140: static void ! 141: _tme_posix_memory_tlbs_invalidate(struct tme_posix_memory *memory) ! 142: { ! 143: signed long tlb_i; ! 144: struct tme_token **tlb_tokens; ! 145: struct tme_token *tlb_token; ! 146: ! 147: /* invalidate all writable TLBS: */ ! 148: tlb_i = TME_MEMORY_POSIX_TLBS_SIZE - 1; ! 149: tlb_tokens = memory->tme_posix_memory_tlb_tokens; ! 150: do { ! 151: tlb_token = tlb_tokens[tlb_i]; ! 152: if (tlb_token != NULL) { ! 153: tlb_tokens[tlb_i] = NULL; ! 154: tme_token_invalidate(tlb_token); ! 155: } ! 156: } while (--tlb_i >= 0); ! 157: } ! 158: 1.1 root 159: /* the memory TLB filler: */ 160: static int 161: _tme_posix_memory_tlb_fill(void *_memory, struct tme_bus_tlb *tlb, 1.1.1.4 ! root 162: tme_bus_addr_t address_wider, ! 163: unsigned int cycles) 1.1 root 164: { 165: struct tme_posix_memory *memory; 1.1.1.4 ! root 166: unsigned long address; ! 167: unsigned long memory_address_last; ! 168: struct tme_token *tlb_token; ! 169: struct tme_token **_tlb_token; ! 170: struct tme_token *tlb_token_other; ! 171: struct tme_posix_memory_valids *valids; ! 172: unsigned long page_index; ! 173: tme_uint32_t tlb_size; 1.1 root 174: 175: /* recover our data structure: */ 176: memory = (struct tme_posix_memory *) _memory; 177: 1.1.1.4 ! root 178: /* get the normal-width address: */ ! 179: address = address_wider; ! 180: assert(address == address_wider); ! 181: 1.1 root 182: /* the address must be within range: */ 183: memory_address_last = memory->tme_posix_memory_device.tme_bus_device_address_last; 1.1.1.4 ! root 184: assert(memory_address_last == memory->tme_posix_memory_device.tme_bus_device_address_last); 1.1 root 185: assert(address <= memory_address_last); 186: 187: /* initialize the TLB entry: */ 188: tme_bus_tlb_initialize(tlb); 189: 190: /* all memory devices allow fast reading. all memory devices except 191: ROMs allow fast writing: */ 192: tlb->tme_bus_tlb_emulator_off_read = memory->tme_posix_memory_contents; 193: if (memory->tme_posix_memory_type != TME_POSIX_MEMORY_ROM) { 194: tlb->tme_bus_tlb_emulator_off_write = memory->tme_posix_memory_contents; 195: } 196: tlb->tme_bus_tlb_rwlock = &memory->tme_posix_memory_rwlock; 197: 198: /* our bus cycle handler: */ 199: tlb->tme_bus_tlb_cycle_private = memory; 200: tlb->tme_bus_tlb_cycle = _tme_posix_memory_bus_cycle; 201: 1.1.1.4 ! root 202: /* if this device is cacheable: */ ! 203: if (__tme_predict_true(memory->tme_posix_memory_tlb_tokens != NULL)) { ! 204: ! 205: /* this TLB entry is for cacheable memory: */ ! 206: tlb->tme_bus_tlb_cacheable = &memory->tme_posix_memory_cacheable; ! 207: ! 208: /* if this TLB entry is for writing: */ ! 209: if (cycles & TME_BUS_CYCLE_WRITE) { ! 210: ! 211: /* lock our mutex: */ ! 212: tme_mutex_lock(&memory->tme_posix_memory_mutex); ! 213: ! 214: /* get the backing TLB entry: */ ! 215: tlb_token = tlb->tme_bus_tlb_token; ! 216: ! 217: /* hash the TLB entry into our writable TLB entry set: */ ! 218: _tlb_token ! 219: = (((tme_hash_data_to_ulong(tlb_token) ! 220: / sizeof(struct tme_token)) ! 221: % TME_MEMORY_POSIX_TLBS_SIZE) ! 222: + memory->tme_posix_memory_tlb_tokens); ! 223: ! 224: /* if there is a different TLB entry already at this position in ! 225: the writable TLB entry set: */ ! 226: tlb_token_other = *_tlb_token; ! 227: if (__tme_predict_true(tlb_token_other != NULL)) { ! 228: if (tlb_token_other != tlb_token) { ! 229: ! 230: /* invalidate this other TLB entry: */ ! 231: tme_token_invalidate(tlb_token_other); ! 232: } ! 233: } ! 234: ! 235: /* save the TLB entry into the writable TLB entry set: */ ! 236: *_tlb_token = tlb->tme_bus_tlb_token; ! 237: ! 238: /* loop over the valids bitmasks: */ ! 239: for (valids = memory->tme_posix_memory_valids; ! 240: valids != NULL; ! 241: valids = valids->tme_posix_memory_valids_next) { ! 242: ! 243: /* clear the bit for this address' page in this valids ! 244: bitmask: */ ! 245: page_index = (address >> valids->tme_posix_memory_valids_page_size_log2); ! 246: *(valids->tme_posix_memory_valids_bitmask ! 247: + (page_index / 8)) ! 248: &= ~(1 << (page_index % 8)); ! 249: } ! 250: ! 251: /* this TLB entry allows reading and writing: */ ! 252: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 253: ! 254: /* this TLB entry only covers the current TLB size: */ ! 255: tlb_size = memory->tme_posix_memory_tlb_size; ! 256: address &= 0 - (unsigned long) tlb_size; ! 257: tlb->tme_bus_tlb_addr_first = address; ! 258: tlb->tme_bus_tlb_addr_last = TME_MIN(address | (tlb_size - 1), memory_address_last); ! 259: ! 260: /* unlock our mutex: */ ! 261: tme_mutex_unlock(&memory->tme_posix_memory_mutex); ! 262: ! 263: return (TME_OK); ! 264: } ! 265: ! 266: /* this TLB entry only allows reading: */ ! 267: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ; ! 268: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF; ! 269: } ! 270: ! 271: /* otherwise, this device is not cacheable: */ ! 272: else { ! 273: ! 274: /* all memory devices allow reading and writing: */ ! 275: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 276: } ! 277: ! 278: /* this TLB entry can cover the whole device: */ ! 279: tlb->tme_bus_tlb_addr_first = 0; ! 280: tlb->tme_bus_tlb_addr_last = memory_address_last; ! 281: 1.1 root 282: return (TME_OK); 283: } 284: 1.1.1.4 ! root 285: /* this function allocates a new valids bitmask: */ ! 286: static tme_shared tme_uint8_t * ! 287: _tme_posix_memory_valids_new(void *_memory, ! 288: tme_uint32_t page_size_log2) ! 289: { ! 290: struct tme_posix_memory *memory; ! 291: tme_uint32_t page_size; ! 292: unsigned long page_count; ! 293: struct tme_posix_memory_valids *valids; ! 294: ! 295: /* recover our data structure: */ ! 296: memory = (struct tme_posix_memory *) _memory; ! 297: ! 298: /* lock our mutex: */ ! 299: tme_mutex_lock(&memory->tme_posix_memory_mutex); ! 300: ! 301: /* get the page size for this valids bitmask: */ ! 302: assert (page_size_log2 < (sizeof(page_size) * 8 - 1)); ! 303: page_size = 1; ! 304: page_size <<= page_size_log2; ! 305: ! 306: /* update the current writable TLB size: */ ! 307: memory->tme_posix_memory_tlb_size ! 308: = TME_MIN(memory->tme_posix_memory_tlb_size, page_size); ! 309: ! 310: /* get the page count for this valids bitmask: */ ! 311: page_count ! 312: = ((memory->tme_posix_memory_cacheable.tme_bus_cacheable_size ! 313: + (page_size - 1)) ! 314: >> page_size_log2); ! 315: ! 316: /* allocate and initialize a new valids bitmask: */ ! 317: valids ! 318: = ((struct tme_posix_memory_valids *) ! 319: tme_malloc(sizeof(struct tme_posix_memory_valids) ! 320: + ((page_count + 7) / 8))); ! 321: valids->tme_posix_memory_valids_page_size_log2 = page_size_log2; ! 322: memset((tme_uint8_t *) valids->tme_posix_memory_valids_bitmask + 0, ! 323: 0xff, ! 324: ((page_count + 7) / 8)); ! 325: ! 326: /* add this new valids bitmask to the list: */ ! 327: valids->tme_posix_memory_valids_next = memory->tme_posix_memory_valids; ! 328: memory->tme_posix_memory_valids = valids; ! 329: ! 330: /* invalidate all outstanding TLB entries: */ ! 331: _tme_posix_memory_tlbs_invalidate(memory); ! 332: ! 333: /* unlock our mutex: */ ! 334: tme_mutex_unlock(&memory->tme_posix_memory_mutex); ! 335: ! 336: /* return the bitmask: */ ! 337: return (valids->tme_posix_memory_valids_bitmask); ! 338: } ! 339: ! 340: /* this function sets a bit in the valids bitmask: */ ! 341: static void ! 342: _tme_posix_memory_valids_set(void *_memory, ! 343: tme_shared tme_uint8_t *valids_bitmask, ! 344: unsigned long page_index) ! 345: { ! 346: struct tme_posix_memory *memory; ! 347: ! 348: /* recover our data structure: */ ! 349: memory = (struct tme_posix_memory *) _memory; ! 350: ! 351: /* lock our mutex: */ ! 352: tme_mutex_lock(&memory->tme_posix_memory_mutex); ! 353: ! 354: /* set the bit for this page in the valids bitmask: */ ! 355: *(valids_bitmask ! 356: + (page_index / 8)) ! 357: |= TME_BIT(page_index % 8); ! 358: ! 359: /* invalidate all outstanding TLB entries: */ ! 360: _tme_posix_memory_tlbs_invalidate(memory); ! 361: ! 362: /* unlock our mutex: */ ! 363: tme_mutex_unlock(&memory->tme_posix_memory_mutex); ! 364: } ! 365: 1.1 root 366: /* the new memory function: */ 367: TME_ELEMENT_SUB_NEW_DECL(tme_host_posix,memory) { 368: unsigned int memory_type; 369: unsigned long memory_size; 370: const char *filename; 371: int fd; 372: struct stat statbuf; 373: struct tme_posix_memory *memory; 1.1.1.4 ! root 374: struct tme_bus_cacheable *cacheable; 1.1 root 375: ssize_t bytes_read; 376: int arg_i; 377: int usage; 378: 379: /* assume we have no backing file: */ 380: filename = NULL; 381: memory_type = -1; 382: memory_size = 0; 383: arg_i = 1; 384: usage = FALSE; 385: 386: /* we are regular RAM if our arguments are: 387: 388: ram SIZE 389: 390: */ 391: if (TME_ARG_IS(args[arg_i + 0], "ram") 392: && (memory_size = tme_bus_addr_parse(args[arg_i + 1], 0)) > 0) { 393: memory_type = TME_POSIX_MEMORY_RAM; 394: arg_i += 2; 395: } 396: 397: /* we are ROM if our arguments are: 398: 399: rom FILE 400: 401: */ 402: else if (TME_ARG_IS(args[arg_i + 0], "rom") 403: && (filename = args[arg_i + 1]) != NULL) { 404: memory_type = TME_POSIX_MEMORY_ROM; 405: arg_i += 2; 406: } 407: 1.1.1.2 root 408: /* we are persistent storage if our arguments are: 1.1 root 409: 1.1.1.2 root 410: persistent FILE 1.1 root 411: 412: */ 413: else if (TME_ARG_IS(args[arg_i + 0], "persistent") 414: && (filename = args[arg_i + 1]) != NULL) { 415: memory_type = TME_POSIX_MEMORY_PERSISTENT; 416: arg_i += 2; 417: } 418: 419: else { 420: usage = TRUE; 421: } 422: 423: if (args[arg_i + 0] != NULL) { 424: tme_output_append_error(_output, 425: "%s %s", 426: args[arg_i], 427: _("unexpected")); 428: usage = TRUE; 429: } 430: 431: if (usage) { 432: tme_output_append_error(_output, 433: "%s %s { rom %s | ram %s | persistent %s }", 434: _("usage:"), 435: args[0], 436: _("ROM-FILE"), 437: _("SIZE"), 438: _("PERSISTENT-FILE")); 439: return (-1); 440: } 441: 442: /* start the memory structure: */ 443: memory = tme_new0(struct tme_posix_memory, 1); 444: memory->tme_posix_memory_type = memory_type; 445: 446: /* if we have a backing file: */ 447: fd = -1; 448: if (filename != NULL) { 449: 450: /* open the file for reading: */ 451: fd = open(filename, (memory_type == TME_POSIX_MEMORY_ROM 452: ? O_RDONLY 453: : O_RDWR)); 454: if (fd < 0) { 455: tme_output_append_error(_output, 456: "%s", 457: filename); 458: tme_free(memory); 459: return (errno); 460: } 461: 462: /* stat the file: */ 463: if (fstat(fd, &statbuf) < 0) { 464: tme_output_append_error(_output, 465: "%s", 466: filename); 467: close(fd); 468: tme_free(memory); 469: return (errno); 470: } 471: memory_size = statbuf.st_size; 472: if (memory_size == 0) { 473: tme_output_append_error(_output, 474: "%s", 475: filename); 476: close(fd); 477: tme_free(memory); 478: return (EINVAL); 479: } 480: 481: #ifdef HAVE_MMAP 482: /* try to mmap the file: */ 483: memory->tme_posix_memory_contents = 484: mmap(NULL, 485: statbuf.st_size, 486: PROT_READ 487: | (memory_type != TME_POSIX_MEMORY_ROM 488: ? PROT_WRITE 489: : 0), 490: MAP_SHARED, 491: fd, 492: 0); 493: if (memory->tme_posix_memory_contents != MAP_FAILED) { 494: memory->tme_posix_memory_mapped = TRUE; 495: } 496: #endif /* HAVE_MMAP */ 497: } 498: 499: /* if we have to, allocate memory space: */ 500: if (!memory->tme_posix_memory_mapped) { 501: memory->tme_posix_memory_contents = tme_new0(tme_uint8_t, memory_size); 502: 503: /* if we have to, read in the backing file: */ 504: if (fd >= 0) { 505: bytes_read = read(fd, memory->tme_posix_memory_contents, memory_size); 506: if (bytes_read < 0 507: || memory_size != (unsigned long) bytes_read) { 508: /* XXX diagnostic: */ 509: close(fd); 510: tme_free(memory->tme_posix_memory_contents); 511: tme_free(memory); 512: return (-1); 513: } 514: 515: /* if this is a ROM, we can close the file now: */ 516: if (memory_type == TME_POSIX_MEMORY_ROM) { 517: close(fd); 518: fd = -1; 519: } 520: } 521: } 522: 523: /* remember any backing fd: */ 524: memory->tme_posix_memory_fd = fd; 525: 526: /* initialize our rwlock: */ 527: tme_rwlock_init(&memory->tme_posix_memory_rwlock); 528: 1.1.1.4 ! root 529: /* initialize our mutex: */ ! 530: tme_mutex_init(&memory->tme_posix_memory_mutex); ! 531: ! 532: /* assume that this memory won't be cacheable: */ ! 533: memory->tme_posix_memory_tlb_tokens = NULL; ! 534: ! 535: /* if we are regular RAM or ROM over a threshold size: */ ! 536: if ((memory_type == TME_POSIX_MEMORY_RAM ! 537: && memory_size >= TME_MEMORY_POSIX_CACHEABLE_SIZE_RAM) ! 538: || (memory_type == TME_POSIX_MEMORY_ROM ! 539: && memory_size >= TME_MEMORY_POSIX_CACHEABLE_SIZE_ROM)) { ! 540: ! 541: /* allocate the writable TLB entry set: */ ! 542: memory->tme_posix_memory_tlb_tokens ! 543: = tme_new0(struct tme_token *, ! 544: TME_MEMORY_POSIX_TLBS_SIZE); ! 545: ! 546: /* initialize the valids list: */ ! 547: memory->tme_posix_memory_valids = NULL; ! 548: ! 549: /* initialize the current writable TLB size: */ ! 550: memory->tme_posix_memory_tlb_size = ((tme_uint32_t) 1) << 31; ! 551: ! 552: /* initialize the bus cacheable structure: */ ! 553: cacheable = &memory->tme_posix_memory_cacheable; ! 554: cacheable->tme_bus_cacheable_contents = memory->tme_posix_memory_contents; ! 555: cacheable->tme_bus_cacheable_size = memory_size; ! 556: cacheable->tme_bus_cacheable_private = memory; ! 557: cacheable->tme_bus_cacheable_valids_new = _tme_posix_memory_valids_new; ! 558: cacheable->tme_bus_cacheable_valids_set = _tme_posix_memory_valids_set; ! 559: } ! 560: 1.1 root 561: /* initialize our simple bus device descriptor: */ 562: memory->tme_posix_memory_device.tme_bus_device_tlb_fill = _tme_posix_memory_tlb_fill; 563: memory->tme_posix_memory_device.tme_bus_device_address_last = (memory_size - 1); 564: 565: /* fill the element: */ 566: element->tme_element_private = memory; 567: element->tme_element_connections_new = tme_bus_device_connections_new; 568: 569: return (0); 570: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.