/[gxemul]/trunk/src/memory.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/memory.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 24 by dpavlin, Mon Oct 8 16:19:56 2007 UTC revision 40 by dpavlin, Mon Oct 8 16:22:11 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: memory.c,v 1.190 2006/06/16 18:31:25 debug Exp $   *  $Id: memory.c,v 1.202 2007/04/28 09:19:51 debug Exp $
29   *   *
30   *  Functions for handling the memory of an emulated machine.   *  Functions for handling the memory of an emulated machine.
31   */   */
# Line 43  Line 43 
43    
44    
45  extern int verbose;  extern int verbose;
46    extern int quiet_mode;
47    
48    
49  /*  /*
# Line 120  void *zeroed_alloc(size_t s) Line 121  void *zeroed_alloc(size_t s)
121  {  {
122          void *p = mmap(NULL, s, PROT_READ | PROT_WRITE,          void *p = mmap(NULL, s, PROT_READ | PROT_WRITE,
123              MAP_ANON | MAP_PRIVATE, -1, 0);              MAP_ANON | MAP_PRIVATE, -1, 0);
124    
125          if (p == NULL) {          if (p == NULL) {
126    #if 1
127                    fprintf(stderr, "zeroed_alloc(): mmap() failed. This should"
128                        " not usually happen. If you can reproduce this, then"
129                        " please contact me with details about your run-time"
130                        " environment.\n");
131                    exit(1);
132    #else
133                  p = malloc(s);                  p = malloc(s);
134                  if (p == NULL) {                  if (p == NULL) {
135                          fprintf(stderr, "out of memory\n");                          fprintf(stderr, "out of memory\n");
136                          exit(1);                          exit(1);
137                  }                  }
138                  memset(p, 0, s);                  memset(p, 0, s);
139    #endif
140          }          }
141    
142          return p;          return p;
143  }  }
144    
# Line 278  void memory_device_dyntrans_access(struc Line 289  void memory_device_dyntrans_access(struc
289              called too often.  */              called too often.  */
290    
291          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
292                  if (mem->dev_extra[i] == extra &&                  if (mem->devices[i].extra == extra &&
293                      mem->dev_flags[i] & DM_DYNTRANS_WRITE_OK &&                      mem->devices[i].flags & DM_DYNTRANS_WRITE_OK &&
294                      mem->dev_dyntrans_data[i] != NULL) {                      mem->devices[i].dyntrans_data != NULL) {
295                          if (mem->dev_dyntrans_write_low[i] != (uint64_t) -1)                          if (mem->devices[i].dyntrans_write_low != (uint64_t) -1)
296                                  need_inval = 1;                                  need_inval = 1;
297                          if (low != NULL)                          if (low != NULL)
298                                  *low = mem->dev_dyntrans_write_low[i];                                  *low = mem->devices[i].dyntrans_write_low;
299                          mem->dev_dyntrans_write_low[i] = (uint64_t) -1;                          mem->devices[i].dyntrans_write_low = (uint64_t) -1;
300    
301                          if (high != NULL)                          if (high != NULL)
302                                  *high = mem->dev_dyntrans_write_high[i];                                  *high = mem->devices[i].dyntrans_write_high;
303                          mem->dev_dyntrans_write_high[i] = 0;                          mem->devices[i].dyntrans_write_high = 0;
304    
305                          if (!need_inval)                          if (!need_inval)
306                                  return;                                  return;
# Line 298  void memory_device_dyntrans_access(struc Line 309  void memory_device_dyntrans_access(struc
309                              be in the dyntrans load/store cache, by marking                              be in the dyntrans load/store cache, by marking
310                              the pages read-only.  */                              the pages read-only.  */
311                          if (cpu->invalidate_translation_caches != NULL) {                          if (cpu->invalidate_translation_caches != NULL) {
312                                  for (s=0; s<mem->dev_length[i];                                  for (s = *low; s <= *high;
313                                      s+=cpu->machine->arch_pagesize)                                      s += cpu->machine->arch_pagesize)
314                                          cpu->invalidate_translation_caches                                          cpu->invalidate_translation_caches
315                                              (cpu, mem->dev_baseaddr[i] + s,                                              (cpu, mem->devices[i].baseaddr + s,
316                                              JUST_MARK_AS_NON_WRITABLE                                              JUST_MARK_AS_NON_WRITABLE
317                                              | INVALIDATE_PADDR);                                              | INVALIDATE_PADDR);
318                          }                          }
# Line 313  void memory_device_dyntrans_access(struc Line 324  void memory_device_dyntrans_access(struc
324    
325    
326  /*  /*
327     *  memory_device_update_data():
328     *
329     *  Update a device' dyntrans data pointer.
330     *
331     *  SUPER-IMPORTANT NOTE: Anyone who changes a dyntrans data pointer while
332     *  things are running also needs to invalidate all CPUs' address translation
333     *  caches!  Otherwise, these may contain old pointers to the old data.
334     */
335    void memory_device_update_data(struct memory *mem, void *extra,
336            unsigned char *data)
337    {
338            int i;
339    
340            for (i=0; i<mem->n_mmapped_devices; i++) {
341                    if (mem->devices[i].extra != extra)
342                            continue;
343    
344                    mem->devices[i].dyntrans_data = data;
345                    mem->devices[i].dyntrans_write_low = (uint64_t)-1;
346                    mem->devices[i].dyntrans_write_high = 0;
347            }
348    }
349    
350    
351    /*
352   *  memory_device_register():   *  memory_device_register():
353   *   *
354   *  Register a (memory mapped) device by adding it to the dev_* fields of a   *  Register a memory mapped device.
  *  memory struct.  
355   */   */
356  void memory_device_register(struct memory *mem, const char *device_name,  void memory_device_register(struct memory *mem, const char *device_name,
357          uint64_t baseaddr, uint64_t len,          uint64_t baseaddr, uint64_t len,
# Line 326  void memory_device_register(struct memor Line 361  void memory_device_register(struct memor
361  {  {
362          int i, newi = 0;          int i, newi = 0;
363    
         if (mem->n_mmapped_devices >= MAX_DEVICES) {  
                 fprintf(stderr, "memory_device_register(): too many "  
                     "devices registered, cannot register '%s'\n", device_name);  
                 exit(1);  
         }  
   
364          /*          /*
365           *  Figure out at which index to insert this device, and simultaneously           *  Figure out at which index to insert this device, and simultaneously
366           *  check for collisions:           *  check for collisions:
367           */           */
368          newi = -1;          newi = -1;
369          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
370                  if (i == 0 && baseaddr + len <= mem->dev_baseaddr[i])                  if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr)
371                          newi = i;                          newi = i;
372                  if (i > 0 && baseaddr + len <= mem->dev_baseaddr[i] &&                  if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr &&
373                      baseaddr >= mem->dev_endaddr[i-1])                      baseaddr >= mem->devices[i-1].endaddr)
374                          newi = i;                          newi = i;
375                  if (i == mem->n_mmapped_devices - 1 &&                  if (i == mem->n_mmapped_devices - 1 &&
376                      baseaddr >= mem->dev_endaddr[i])                      baseaddr >= mem->devices[i].endaddr)
377                          newi = i + 1;                          newi = i + 1;
378    
379                  /*  If we are not colliding with device i, then continue:  */                  /*  If this is not colliding with device i, then continue:  */
380                  if (baseaddr + len <= mem->dev_baseaddr[i])                  if (baseaddr + len <= mem->devices[i].baseaddr)
381                          continue;                          continue;
382                  if (baseaddr >= mem->dev_endaddr[i])                  if (baseaddr >= mem->devices[i].endaddr)
383                          continue;                          continue;
384    
385                  fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",                  fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",
386                      device_name, i, mem->dev_name[i]);                      device_name, i, mem->devices[i].name);
387                  exit(1);                  exit(1);
388          }          }
389          if (mem->n_mmapped_devices == 0)          if (mem->n_mmapped_devices == 0)
# Line 383  void memory_device_register(struct memor Line 412  void memory_device_register(struct memor
412          }          }
413    
414          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
415                  if (dyntrans_data == mem->dev_dyntrans_data[i] &&                  if (dyntrans_data == mem->devices[i].dyntrans_data &&
416                      mem->dev_flags[i] & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)                      mem->devices[i].flags&(DM_DYNTRANS_OK|DM_DYNTRANS_WRITE_OK)
417                      && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {                      && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
418                          fatal("ERROR: the data pointer used for dyntrans "                          fatal("ERROR: the data pointer used for dyntrans "
419                              "accesses must only be used once!\n");                              "accesses must only be used once!\n");
420                          fatal("(%p cannot be used by '%s'; already in use by '"                          fatal("(%p cannot be used by '%s'; already in use by '"
421                              "%s')\n", dyntrans_data, device_name,                              "%s')\n", dyntrans_data, device_name,
422                              mem->dev_name[i]);                              mem->devices[i].name);
423                          exit(1);                          exit(1);
424                  }                  }
425          }          }
426    
427          mem->n_mmapped_devices++;          mem->n_mmapped_devices++;
428    
429          /*          mem->devices = realloc(mem->devices, sizeof(struct memory_device)
430           *  YUCK! This is ugly. TODO: fix              * mem->n_mmapped_devices);
431           */          if (mem->devices == NULL) {
432                    fprintf(stderr, "out of memory\n");
433                    exit(1);
434            }
435    
436          /*  Make space for the new entry:  */          /*  Make space for the new entry:  */
437          memmove(&mem->dev_name[newi+1], &mem->dev_name[newi], sizeof(char *) *          if (newi + 1 != mem->n_mmapped_devices)
438              (MAX_DEVICES - newi - 1));                  memmove(&mem->devices[newi+1], &mem->devices[newi],
439          memmove(&mem->dev_baseaddr[newi+1], &mem->dev_baseaddr[newi],                      sizeof(struct memory_device)
440              sizeof(uint64_t) * (MAX_DEVICES - newi - 1));                      * (mem->n_mmapped_devices - newi - 1));
441          memmove(&mem->dev_endaddr[newi+1], &mem->dev_endaddr[newi],  
442              sizeof(uint64_t) * (MAX_DEVICES - newi - 1));          mem->devices[newi].name = strdup(device_name);
443          memmove(&mem->dev_length[newi+1], &mem->dev_length[newi],          mem->devices[newi].baseaddr = baseaddr;
444              sizeof(uint64_t) * (MAX_DEVICES - newi - 1));          mem->devices[newi].endaddr = baseaddr + len;
445          memmove(&mem->dev_flags[newi+1], &mem->dev_flags[newi], sizeof(int) *          mem->devices[newi].length = len;
446              (MAX_DEVICES - newi - 1));          mem->devices[newi].flags = flags;
447          memmove(&mem->dev_extra[newi+1], &mem->dev_extra[newi], sizeof(void *) *          mem->devices[newi].dyntrans_data = dyntrans_data;
             (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_f[newi+1], &mem->dev_f[newi], sizeof(void *) *  
             (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_dyntrans_data[newi+1], &mem->dev_dyntrans_data[newi],  
             sizeof(void *) * (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_dyntrans_write_low[newi+1],  
             &mem->dev_dyntrans_write_low[newi],  
             sizeof(uint64_t) * (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_dyntrans_write_high[newi+1],  
             &mem->dev_dyntrans_write_high[newi],  
             sizeof(uint64_t) * (MAX_DEVICES - newi - 1));  
   
   
         mem->dev_name[newi] = strdup(device_name);  
         mem->dev_baseaddr[newi] = baseaddr;  
         mem->dev_endaddr[newi] = baseaddr + len;  
         mem->dev_length[newi] = len;  
         mem->dev_flags[newi] = flags;  
         mem->dev_dyntrans_data[newi] = dyntrans_data;  
448    
449          if (mem->dev_name[newi] == NULL) {          if (mem->devices[newi].name == NULL) {
450                  fprintf(stderr, "out of memory\n");                  fprintf(stderr, "out of memory\n");
451                  exit(1);                  exit(1);
452          }          }
# Line 451  void memory_device_register(struct memor Line 465  void memory_device_register(struct memor
465                  exit(1);                  exit(1);
466          }          }
467    
468          mem->dev_dyntrans_write_low[newi] = (uint64_t)-1;          mem->devices[newi].dyntrans_write_low = (uint64_t)-1;
469          mem->dev_dyntrans_write_high[newi] = 0;          mem->devices[newi].dyntrans_write_high = 0;
470          mem->dev_f[newi] = f;          mem->devices[newi].f = f;
471          mem->dev_extra[newi] = extra;          mem->devices[newi].extra = extra;
472    
473          if (baseaddr < mem->mmap_dev_minaddr)          if (baseaddr < mem->mmap_dev_minaddr)
474                  mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;                  mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;
475          if (baseaddr + len > mem->mmap_dev_maxaddr)          if (baseaddr + len > mem->mmap_dev_maxaddr)
476                  mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |                  mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |
477                      mem->dev_dyntrans_alignment) + 1;                      mem->dev_dyntrans_alignment) + 1;
478    
479            if (newi < mem->last_accessed_device)
480                    mem->last_accessed_device ++;
481  }  }
482    
483    
484  /*  /*
485   *  memory_device_remove():   *  memory_device_remove():
486   *   *
487   *  Unregister a (memory mapped) device from a memory struct.   *  Unregister a memory mapped device from a memory object.
488   */   */
489  void memory_device_remove(struct memory *mem, int i)  void memory_device_remove(struct memory *mem, int i)
490  {  {
491          if (i < 0 || i >= mem->n_mmapped_devices) {          if (i < 0 || i >= mem->n_mmapped_devices) {
492                  fatal("memory_device_remove(): invalid device number %i\n", i);                  fatal("memory_device_remove(): invalid device number %i\n", i);
493                  return;                  exit(1);
494          }          }
495    
496          mem->n_mmapped_devices --;          mem->n_mmapped_devices --;
# Line 481  void memory_device_remove(struct memory Line 498  void memory_device_remove(struct memory
498          if (i == mem->n_mmapped_devices)          if (i == mem->n_mmapped_devices)
499                  return;                  return;
500    
501          /*          memmove(&mem->devices[i], &mem->devices[i+1],
502           *  YUCK! This is ugly. TODO: fix              sizeof(struct memory_device) * (mem->n_mmapped_devices - i));
          */  
503    
504          memmove(&mem->dev_name[i], &mem->dev_name[i+1], sizeof(char *) *          if (i <= mem->last_accessed_device)
505              (MAX_DEVICES - i - 1));                  mem->last_accessed_device --;
506          memmove(&mem->dev_baseaddr[i], &mem->dev_baseaddr[i+1],          if (mem->last_accessed_device < 0)
507              sizeof(uint64_t) * (MAX_DEVICES - i - 1));                  mem->last_accessed_device = 0;
         memmove(&mem->dev_endaddr[i], &mem->dev_endaddr[i+1],  
             sizeof(uint64_t) * (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_length[i], &mem->dev_length[i+1], sizeof(uint64_t) *  
             (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_flags[i], &mem->dev_flags[i+1], sizeof(int) *  
             (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_extra[i], &mem->dev_extra[i+1], sizeof(void *) *  
             (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_f[i], &mem->dev_f[i+1], sizeof(void *) *  
             (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_dyntrans_data[i], &mem->dev_dyntrans_data[i+1],  
             sizeof(void *) * (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_dyntrans_write_low[i], &mem->dev_dyntrans_write_low  
             [i+1], sizeof(uint64_t) * (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_dyntrans_write_high[i], &mem->dev_dyntrans_write_high  
             [i+1], sizeof(uint64_t) * (MAX_DEVICES - i - 1));  
508  }  }
509    
510    
# Line 518  void memory_device_remove(struct memory Line 518  void memory_device_remove(struct memory
518  /*  /*
519   *  memory_paddr_to_hostaddr():   *  memory_paddr_to_hostaddr():
520   *   *
521   *  Translate a physical address into a host address.   *  Translate a physical address into a host address. The usual way to call
522     *  this function is to make sure that paddr is page aligned, which will result
523     *  in the host _page_ corresponding to that address.
524   *   *
525   *  Return value is a pointer to a host memblock, or NULL on failure.   *  Return value is a pointer to the address in the host, or NULL on failure.
526   *  On reads, a NULL return value should be interpreted as reading all zeroes.   *  On reads, a NULL return value should be interpreted as reading all zeroes.
527   */   */
528  unsigned char *memory_paddr_to_hostaddr(struct memory *mem,  unsigned char *memory_paddr_to_hostaddr(struct memory *mem,
# Line 530  unsigned char *memory_paddr_to_hostaddr( Line 532  unsigned char *memory_paddr_to_hostaddr(
532          int entry;          int entry;
533          const int mask = (1 << BITS_PER_PAGETABLE) - 1;          const int mask = (1 << BITS_PER_PAGETABLE) - 1;
534          const int shrcount = MAX_BITS - BITS_PER_PAGETABLE;          const int shrcount = MAX_BITS - BITS_PER_PAGETABLE;
535            unsigned char *hostptr;
536    
537          table = mem->pagetable;          table = mem->pagetable;
538          entry = (paddr >> shrcount) & mask;          entry = (paddr >> shrcount) & mask;
# Line 569  unsigned char *memory_paddr_to_hostaddr( Line 572  unsigned char *memory_paddr_to_hostaddr(
572                  }                  }
573          }          }
574    
575          return (unsigned char *) table[entry];          hostptr = (unsigned char *) table[entry];
576    
577            if (hostptr != NULL)
578                    hostptr += (paddr & ((1 << BITS_PER_MEMBLOCK) - 1));
579    
580            return hostptr;
581  }  }
582    
583    
# Line 593  uint64_t memory_checksum(struct memory * Line 601  uint64_t memory_checksum(struct memory *
601  {  {
602          uint64_t internal_state = 0x80624185376feff2ULL;          uint64_t internal_state = 0x80624185376feff2ULL;
603          uint64_t checksum = 0xcb9a87d5c010072cULL;          uint64_t checksum = 0xcb9a87d5c010072cULL;
604          const int n_entries = (1 << BITS_PER_PAGETABLE) - 1;          const size_t n_entries = (1 << BITS_PER_PAGETABLE) - 1;
605          const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t);          const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t);
606          size_t entry, i;          size_t entry, i;
607    
# Line 613  uint64_t memory_checksum(struct memory * Line 621  uint64_t memory_checksum(struct memory *
621          return checksum;          return checksum;
622  }  }
623    
624    
625    /*
626     *  memory_warn_about_unimplemented_addr():
627     *
628     *  Called from memory_rw whenever memory outside of the physical address space
629     *  is accessed (and quiet_mode isn't set).
630     */
631    void memory_warn_about_unimplemented_addr(struct cpu *cpu, struct memory *mem,
632            int writeflag, uint64_t paddr, uint8_t *data, size_t len)
633    {
634            uint64_t offset, old_pc = cpu->pc;
635            char *symbol;
636    
637            /*
638             *  This allows guest OS kernels to probe memory a few KBs past the
639             *  end of memory, without giving too many warnings.
640             */
641            if (paddr < mem->physical_max + 0x40000)
642                    return;
643    
644            if (!cpu->machine->halt_on_nonexistant_memaccess && quiet_mode)
645                    return;
646    
647            fatal("[ memory_rw(): %s ", writeflag? "write":"read");
648    
649            if (writeflag) {
650                    unsigned int i;
651                    debug("data={", writeflag);
652                    if (len > 16) {
653                            int start2 = len-16;
654                            for (i=0; i<16; i++)
655                                    debug("%s%02x", i?",":"", data[i]);
656                            debug(" .. ");
657                            if (start2 < 16)
658                                    start2 = 16;
659                            for (i=start2; i<len; i++)
660                                    debug("%s%02x", i?",":"", data[i]);
661                    } else
662                            for (i=0; i<len; i++)
663                                    debug("%s%02x", i?",":"", data[i]);
664                    debug("} ");
665            }
666    
667            fatal("paddr=0x%llx >= physical_max; pc=", (long long)paddr);
668            if (cpu->is_32bit)
669                    fatal("0x%08"PRIx32, (uint32_t) old_pc);
670            else
671                    fatal("0x%016"PRIx64, (uint64_t) old_pc);
672            symbol = get_symbol_name(&cpu->machine->symbol_context,
673                old_pc, &offset);
674            fatal(" <%s> ]\n", symbol? symbol : " no symbol ");
675    
676            if (cpu->machine->halt_on_nonexistant_memaccess) {
677                    /*  TODO: Halt in a nicer way. Not possible with the
678                        current dyntrans system...  */
679                    exit(1);
680            }
681    }
682    

Legend:
Removed from v.24  
changed lines
  Added in v.40

  ViewVC Help
Powered by ViewVC 1.1.26