|
|
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:
1.1.1.5 ! root 126: #if 0
! 127: if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
! 128: printf("posix write @ %x\n", (unsigned int)cycle->tme_bus_cycle_address);
! 129: }
! 130: if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {
! 131: printf("posix read @ %x\n", (unsigned int)cycle->tme_bus_cycle_address);
! 132: }
! 133: #endif
! 134:
! 135: #if 1
! 136: if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
! 137: extern int get_sunbw2_copy(void);
! 138: extern int get_sunbw2_copy_addr(void);
! 139: int printf(const char *format, ...);
! 140:
! 141: if (get_sunbw2_copy()) {
! 142: if ((cycle->tme_bus_cycle_address & 0x007e0000) == get_sunbw2_copy_addr()) {
! 143: printf("posix hit! @ %x\n", (unsigned int)cycle->tme_bus_cycle_address);
! 144: }
! 145: }
! 146: }
! 147: #endif
! 148:
1.1 root 149: /* run the cycle: */
150: tme_bus_cycle_xfer_memory(cycle,
151: ((cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
152: && memory->tme_posix_memory_type == TME_POSIX_MEMORY_ROM)
153: ? NULL
154: : memory->tme_posix_memory_contents),
155: memory->tme_posix_memory_device.tme_bus_device_address_last);
156:
157: /* no faults: */
158: return (TME_OK);
159: }
160:
1.1.1.4 root 161: /* this invalidates all outstanding TLBs. it must be called with the
162: mutex held: */
163: static void
164: _tme_posix_memory_tlbs_invalidate(struct tme_posix_memory *memory)
165: {
166: signed long tlb_i;
167: struct tme_token **tlb_tokens;
168: struct tme_token *tlb_token;
169:
170: /* invalidate all writable TLBS: */
171: tlb_i = TME_MEMORY_POSIX_TLBS_SIZE - 1;
172: tlb_tokens = memory->tme_posix_memory_tlb_tokens;
173: do {
174: tlb_token = tlb_tokens[tlb_i];
175: if (tlb_token != NULL) {
176: tlb_tokens[tlb_i] = NULL;
177: tme_token_invalidate(tlb_token);
178: }
179: } while (--tlb_i >= 0);
180: }
181:
1.1 root 182: /* the memory TLB filler: */
183: static int
184: _tme_posix_memory_tlb_fill(void *_memory, struct tme_bus_tlb *tlb,
1.1.1.4 root 185: tme_bus_addr_t address_wider,
186: unsigned int cycles)
1.1 root 187: {
188: struct tme_posix_memory *memory;
1.1.1.4 root 189: unsigned long address;
190: unsigned long memory_address_last;
191: struct tme_token *tlb_token;
192: struct tme_token **_tlb_token;
193: struct tme_token *tlb_token_other;
194: struct tme_posix_memory_valids *valids;
195: unsigned long page_index;
196: tme_uint32_t tlb_size;
1.1 root 197:
198: /* recover our data structure: */
199: memory = (struct tme_posix_memory *) _memory;
200:
1.1.1.4 root 201: /* get the normal-width address: */
202: address = address_wider;
203: assert(address == address_wider);
204:
1.1 root 205: /* the address must be within range: */
206: memory_address_last = memory->tme_posix_memory_device.tme_bus_device_address_last;
1.1.1.4 root 207: assert(memory_address_last == memory->tme_posix_memory_device.tme_bus_device_address_last);
1.1 root 208: assert(address <= memory_address_last);
209:
210: /* initialize the TLB entry: */
211: tme_bus_tlb_initialize(tlb);
212:
213: /* all memory devices allow fast reading. all memory devices except
214: ROMs allow fast writing: */
215: tlb->tme_bus_tlb_emulator_off_read = memory->tme_posix_memory_contents;
216: if (memory->tme_posix_memory_type != TME_POSIX_MEMORY_ROM) {
217: tlb->tme_bus_tlb_emulator_off_write = memory->tme_posix_memory_contents;
218: }
219: tlb->tme_bus_tlb_rwlock = &memory->tme_posix_memory_rwlock;
220:
221: /* our bus cycle handler: */
222: tlb->tme_bus_tlb_cycle_private = memory;
223: tlb->tme_bus_tlb_cycle = _tme_posix_memory_bus_cycle;
224:
1.1.1.4 root 225: /* if this device is cacheable: */
226: if (__tme_predict_true(memory->tme_posix_memory_tlb_tokens != NULL)) {
227:
228: /* this TLB entry is for cacheable memory: */
229: tlb->tme_bus_tlb_cacheable = &memory->tme_posix_memory_cacheable;
230:
231: /* if this TLB entry is for writing: */
232: if (cycles & TME_BUS_CYCLE_WRITE) {
233:
234: /* lock our mutex: */
235: tme_mutex_lock(&memory->tme_posix_memory_mutex);
236:
237: /* get the backing TLB entry: */
238: tlb_token = tlb->tme_bus_tlb_token;
239:
240: /* hash the TLB entry into our writable TLB entry set: */
241: _tlb_token
242: = (((tme_hash_data_to_ulong(tlb_token)
243: / sizeof(struct tme_token))
244: % TME_MEMORY_POSIX_TLBS_SIZE)
245: + memory->tme_posix_memory_tlb_tokens);
246:
247: /* if there is a different TLB entry already at this position in
248: the writable TLB entry set: */
249: tlb_token_other = *_tlb_token;
250: if (__tme_predict_true(tlb_token_other != NULL)) {
251: if (tlb_token_other != tlb_token) {
252:
253: /* invalidate this other TLB entry: */
254: tme_token_invalidate(tlb_token_other);
255: }
256: }
257:
258: /* save the TLB entry into the writable TLB entry set: */
259: *_tlb_token = tlb->tme_bus_tlb_token;
260:
261: /* loop over the valids bitmasks: */
262: for (valids = memory->tme_posix_memory_valids;
263: valids != NULL;
264: valids = valids->tme_posix_memory_valids_next) {
265:
266: /* clear the bit for this address' page in this valids
267: bitmask: */
268: page_index = (address >> valids->tme_posix_memory_valids_page_size_log2);
269: *(valids->tme_posix_memory_valids_bitmask
270: + (page_index / 8))
271: &= ~(1 << (page_index % 8));
272: }
273:
274: /* this TLB entry allows reading and writing: */
275: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
276:
277: /* this TLB entry only covers the current TLB size: */
278: tlb_size = memory->tme_posix_memory_tlb_size;
279: address &= 0 - (unsigned long) tlb_size;
280: tlb->tme_bus_tlb_addr_first = address;
281: tlb->tme_bus_tlb_addr_last = TME_MIN(address | (tlb_size - 1), memory_address_last);
282:
283: /* unlock our mutex: */
284: tme_mutex_unlock(&memory->tme_posix_memory_mutex);
285:
286: return (TME_OK);
287: }
288:
289: /* this TLB entry only allows reading: */
290: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ;
291: tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
292: }
293:
294: /* otherwise, this device is not cacheable: */
295: else {
296:
297: /* all memory devices allow reading and writing: */
298: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
299: }
300:
301: /* this TLB entry can cover the whole device: */
302: tlb->tme_bus_tlb_addr_first = 0;
303: tlb->tme_bus_tlb_addr_last = memory_address_last;
304:
1.1 root 305: return (TME_OK);
306: }
307:
1.1.1.4 root 308: /* this function allocates a new valids bitmask: */
309: static tme_shared tme_uint8_t *
310: _tme_posix_memory_valids_new(void *_memory,
311: tme_uint32_t page_size_log2)
312: {
313: struct tme_posix_memory *memory;
314: tme_uint32_t page_size;
315: unsigned long page_count;
316: struct tme_posix_memory_valids *valids;
317:
318: /* recover our data structure: */
319: memory = (struct tme_posix_memory *) _memory;
320:
321: /* lock our mutex: */
322: tme_mutex_lock(&memory->tme_posix_memory_mutex);
323:
324: /* get the page size for this valids bitmask: */
325: assert (page_size_log2 < (sizeof(page_size) * 8 - 1));
326: page_size = 1;
327: page_size <<= page_size_log2;
328:
329: /* update the current writable TLB size: */
330: memory->tme_posix_memory_tlb_size
331: = TME_MIN(memory->tme_posix_memory_tlb_size, page_size);
332:
333: /* get the page count for this valids bitmask: */
334: page_count
335: = ((memory->tme_posix_memory_cacheable.tme_bus_cacheable_size
336: + (page_size - 1))
337: >> page_size_log2);
338:
339: /* allocate and initialize a new valids bitmask: */
340: valids
341: = ((struct tme_posix_memory_valids *)
342: tme_malloc(sizeof(struct tme_posix_memory_valids)
343: + ((page_count + 7) / 8)));
344: valids->tme_posix_memory_valids_page_size_log2 = page_size_log2;
345: memset((tme_uint8_t *) valids->tme_posix_memory_valids_bitmask + 0,
346: 0xff,
347: ((page_count + 7) / 8));
348:
349: /* add this new valids bitmask to the list: */
350: valids->tme_posix_memory_valids_next = memory->tme_posix_memory_valids;
351: memory->tme_posix_memory_valids = valids;
352:
353: /* invalidate all outstanding TLB entries: */
354: _tme_posix_memory_tlbs_invalidate(memory);
355:
356: /* unlock our mutex: */
357: tme_mutex_unlock(&memory->tme_posix_memory_mutex);
358:
359: /* return the bitmask: */
360: return (valids->tme_posix_memory_valids_bitmask);
361: }
362:
363: /* this function sets a bit in the valids bitmask: */
364: static void
365: _tme_posix_memory_valids_set(void *_memory,
366: tme_shared tme_uint8_t *valids_bitmask,
367: unsigned long page_index)
368: {
369: struct tme_posix_memory *memory;
370:
371: /* recover our data structure: */
372: memory = (struct tme_posix_memory *) _memory;
373:
374: /* lock our mutex: */
375: tme_mutex_lock(&memory->tme_posix_memory_mutex);
376:
377: /* set the bit for this page in the valids bitmask: */
378: *(valids_bitmask
379: + (page_index / 8))
380: |= TME_BIT(page_index % 8);
381:
382: /* invalidate all outstanding TLB entries: */
383: _tme_posix_memory_tlbs_invalidate(memory);
384:
385: /* unlock our mutex: */
386: tme_mutex_unlock(&memory->tme_posix_memory_mutex);
387: }
388:
1.1 root 389: /* the new memory function: */
390: TME_ELEMENT_SUB_NEW_DECL(tme_host_posix,memory) {
391: unsigned int memory_type;
392: unsigned long memory_size;
393: const char *filename;
394: int fd;
395: struct stat statbuf;
396: struct tme_posix_memory *memory;
1.1.1.4 root 397: struct tme_bus_cacheable *cacheable;
1.1 root 398: ssize_t bytes_read;
399: int arg_i;
400: int usage;
401:
402: /* assume we have no backing file: */
403: filename = NULL;
404: memory_type = -1;
405: memory_size = 0;
406: arg_i = 1;
407: usage = FALSE;
408:
409: /* we are regular RAM if our arguments are:
410:
411: ram SIZE
412:
413: */
414: if (TME_ARG_IS(args[arg_i + 0], "ram")
415: && (memory_size = tme_bus_addr_parse(args[arg_i + 1], 0)) > 0) {
416: memory_type = TME_POSIX_MEMORY_RAM;
417: arg_i += 2;
418: }
419:
420: /* we are ROM if our arguments are:
421:
422: rom FILE
423:
424: */
425: else if (TME_ARG_IS(args[arg_i + 0], "rom")
426: && (filename = args[arg_i + 1]) != NULL) {
427: memory_type = TME_POSIX_MEMORY_ROM;
428: arg_i += 2;
429: }
430:
1.1.1.2 root 431: /* we are persistent storage if our arguments are:
1.1 root 432:
1.1.1.2 root 433: persistent FILE
1.1 root 434:
435: */
436: else if (TME_ARG_IS(args[arg_i + 0], "persistent")
437: && (filename = args[arg_i + 1]) != NULL) {
438: memory_type = TME_POSIX_MEMORY_PERSISTENT;
439: arg_i += 2;
440: }
441:
442: else {
443: usage = TRUE;
444: }
445:
446: if (args[arg_i + 0] != NULL) {
447: tme_output_append_error(_output,
448: "%s %s",
449: args[arg_i],
450: _("unexpected"));
451: usage = TRUE;
452: }
453:
454: if (usage) {
455: tme_output_append_error(_output,
456: "%s %s { rom %s | ram %s | persistent %s }",
457: _("usage:"),
458: args[0],
459: _("ROM-FILE"),
460: _("SIZE"),
461: _("PERSISTENT-FILE"));
462: return (-1);
463: }
464:
465: /* start the memory structure: */
466: memory = tme_new0(struct tme_posix_memory, 1);
467: memory->tme_posix_memory_type = memory_type;
468:
469: /* if we have a backing file: */
470: fd = -1;
471: if (filename != NULL) {
472:
473: /* open the file for reading: */
474: fd = open(filename, (memory_type == TME_POSIX_MEMORY_ROM
475: ? O_RDONLY
476: : O_RDWR));
477: if (fd < 0) {
478: tme_output_append_error(_output,
479: "%s",
480: filename);
481: tme_free(memory);
482: return (errno);
483: }
484:
485: /* stat the file: */
486: if (fstat(fd, &statbuf) < 0) {
487: tme_output_append_error(_output,
488: "%s",
489: filename);
490: close(fd);
491: tme_free(memory);
492: return (errno);
493: }
494: memory_size = statbuf.st_size;
495: if (memory_size == 0) {
496: tme_output_append_error(_output,
497: "%s",
498: filename);
499: close(fd);
500: tme_free(memory);
501: return (EINVAL);
502: }
503:
504: #ifdef HAVE_MMAP
505: /* try to mmap the file: */
506: memory->tme_posix_memory_contents =
507: mmap(NULL,
508: statbuf.st_size,
509: PROT_READ
510: | (memory_type != TME_POSIX_MEMORY_ROM
511: ? PROT_WRITE
512: : 0),
513: MAP_SHARED,
514: fd,
515: 0);
516: if (memory->tme_posix_memory_contents != MAP_FAILED) {
517: memory->tme_posix_memory_mapped = TRUE;
518: }
519: #endif /* HAVE_MMAP */
520: }
521:
522: /* if we have to, allocate memory space: */
523: if (!memory->tme_posix_memory_mapped) {
524: memory->tme_posix_memory_contents = tme_new0(tme_uint8_t, memory_size);
525:
526: /* if we have to, read in the backing file: */
527: if (fd >= 0) {
528: bytes_read = read(fd, memory->tme_posix_memory_contents, memory_size);
529: if (bytes_read < 0
530: || memory_size != (unsigned long) bytes_read) {
531: /* XXX diagnostic: */
532: close(fd);
533: tme_free(memory->tme_posix_memory_contents);
534: tme_free(memory);
535: return (-1);
536: }
537:
538: /* if this is a ROM, we can close the file now: */
539: if (memory_type == TME_POSIX_MEMORY_ROM) {
540: close(fd);
541: fd = -1;
542: }
543: }
544: }
545:
546: /* remember any backing fd: */
547: memory->tme_posix_memory_fd = fd;
548:
549: /* initialize our rwlock: */
550: tme_rwlock_init(&memory->tme_posix_memory_rwlock);
551:
1.1.1.4 root 552: /* initialize our mutex: */
553: tme_mutex_init(&memory->tme_posix_memory_mutex);
554:
555: /* assume that this memory won't be cacheable: */
556: memory->tme_posix_memory_tlb_tokens = NULL;
557:
558: /* if we are regular RAM or ROM over a threshold size: */
559: if ((memory_type == TME_POSIX_MEMORY_RAM
560: && memory_size >= TME_MEMORY_POSIX_CACHEABLE_SIZE_RAM)
561: || (memory_type == TME_POSIX_MEMORY_ROM
562: && memory_size >= TME_MEMORY_POSIX_CACHEABLE_SIZE_ROM)) {
563:
564: /* allocate the writable TLB entry set: */
565: memory->tme_posix_memory_tlb_tokens
566: = tme_new0(struct tme_token *,
567: TME_MEMORY_POSIX_TLBS_SIZE);
568:
569: /* initialize the valids list: */
570: memory->tme_posix_memory_valids = NULL;
571:
572: /* initialize the current writable TLB size: */
573: memory->tme_posix_memory_tlb_size = ((tme_uint32_t) 1) << 31;
574:
575: /* initialize the bus cacheable structure: */
576: cacheable = &memory->tme_posix_memory_cacheable;
577: cacheable->tme_bus_cacheable_contents = memory->tme_posix_memory_contents;
578: cacheable->tme_bus_cacheable_size = memory_size;
579: cacheable->tme_bus_cacheable_private = memory;
580: cacheable->tme_bus_cacheable_valids_new = _tme_posix_memory_valids_new;
581: cacheable->tme_bus_cacheable_valids_set = _tme_posix_memory_valids_set;
582: }
583:
1.1 root 584: /* initialize our simple bus device descriptor: */
585: memory->tme_posix_memory_device.tme_bus_device_tlb_fill = _tme_posix_memory_tlb_fill;
586: memory->tme_posix_memory_device.tme_bus_device_address_last = (memory_size - 1);
587:
588: /* fill the element: */
589: element->tme_element_private = memory;
590: element->tme_element_connections_new = tme_bus_device_connections_new;
591:
592: return (0);
593: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.