/[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 12 by dpavlin, Mon Oct 8 16:18:38 2007 UTC revision 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  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.175 2005/08/14 15:47:36 debug Exp $   *  $Id: memory.c,v 1.199 2006/10/24 09:32:48 debug Exp $
29   *   *
30   *  Functions for handling the memory of an emulated machine.   *  Functions for handling the memory of an emulated machine.
31   */   */
# Line 36  Line 36 
36  #include <sys/types.h>  #include <sys/types.h>
37  #include <sys/mman.h>  #include <sys/mman.h>
38    
 #include "bintrans.h"  
 #include "cop0.h"  
39  #include "cpu.h"  #include "cpu.h"
40  #include "machine.h"  #include "machine.h"
41  #include "memory.h"  #include "memory.h"
 #include "mips_cpu_types.h"  
42  #include "misc.h"  #include "misc.h"
43    
44    
45  extern int quiet_mode;  extern int verbose;
 extern volatile int single_step;  
46    
47    
48  /*  /*
# Line 59  extern volatile int single_step; Line 55  extern volatile int single_step;
55   */   */
56  uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)  uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
57  {  {
58          int i;          int i, byte_order = cpu->byte_order;
59          uint64_t x = 0;          uint64_t x = 0;
60    
61            if (len & MEM_PCI_LITTLE_ENDIAN) {
62                    len &= ~MEM_PCI_LITTLE_ENDIAN;
63                    byte_order = EMUL_LITTLE_ENDIAN;
64            }
65    
66          /*  Switch byte order for incoming data, if necessary:  */          /*  Switch byte order for incoming data, if necessary:  */
67          if (cpu->byte_order == EMUL_BIG_ENDIAN)          if (byte_order == EMUL_BIG_ENDIAN)
68                  for (i=0; i<len; i++) {                  for (i=0; i<len; i++) {
69                          x <<= 8;                          x <<= 8;
70                          x |= buf[i];                          x |= buf[i];
# Line 89  uint64_t memory_readmax64(struct cpu *cp Line 90  uint64_t memory_readmax64(struct cpu *cp
90  void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len,  void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len,
91          uint64_t data)          uint64_t data)
92  {  {
93          int i;          int i, byte_order = cpu->byte_order;
94    
95          if (cpu->byte_order == EMUL_LITTLE_ENDIAN)          if (len & MEM_PCI_LITTLE_ENDIAN) {
96                    len &= ~MEM_PCI_LITTLE_ENDIAN;
97                    byte_order = EMUL_LITTLE_ENDIAN;
98            }
99    
100            if (byte_order == EMUL_LITTLE_ENDIAN)
101                  for (i=0; i<len; i++) {                  for (i=0; i<len; i++) {
102                          buf[i] = data & 255;                          buf[i] = data & 255;
103                          data >>= 8;                          data >>= 8;
# Line 114  void *zeroed_alloc(size_t s) Line 120  void *zeroed_alloc(size_t s)
120  {  {
121          void *p = mmap(NULL, s, PROT_READ | PROT_WRITE,          void *p = mmap(NULL, s, PROT_READ | PROT_WRITE,
122              MAP_ANON | MAP_PRIVATE, -1, 0);              MAP_ANON | MAP_PRIVATE, -1, 0);
123    
124          if (p == NULL) {          if (p == NULL) {
125    #if 1
126                    fprintf(stderr, "zeroed_alloc(): mmap() failed. This should"
127                        " not usually happen. If you can reproduce this, then"
128                        " please contact me with details about your run-time"
129                        " environment.\n");
130                    exit(1);
131    #else
132                  p = malloc(s);                  p = malloc(s);
133                  if (p == NULL) {                  if (p == NULL) {
134                          fprintf(stderr, "out of memory\n");                          fprintf(stderr, "out of memory\n");
135                          exit(1);                          exit(1);
136                  }                  }
137                  memset(p, 0, s);                  memset(p, 0, s);
138    #endif
139          }          }
140    
141          return p;          return p;
142  }  }
143    
# Line 184  struct memory *memory_new(uint64_t physi Line 200  struct memory *memory_new(uint64_t physi
200  /*  /*
201   *  memory_points_to_string():   *  memory_points_to_string():
202   *   *
203   *  Returns 1 if there's something string-like at addr, otherwise 0.   *  Returns 1 if there's something string-like in emulated memory at address
204     *  addr, otherwise 0.
205   */   */
206  int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,  int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,
207          int min_string_length)          int min_string_length)
# Line 213  int memory_points_to_string(struct cpu * Line 230  int memory_points_to_string(struct cpu *
230  /*  /*
231   *  memory_conv_to_string():   *  memory_conv_to_string():
232   *   *
233   *  Convert virtual memory contents to a string, placing it in a   *  Convert emulated memory contents to a string, placing it in a buffer
234   *  buffer provided by the caller.   *  provided by the caller.
235   */   */
236  char *memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,  char *memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,
237          char *buf, int bufsize)          char *buf, int bufsize)
# Line 258  char *memory_conv_to_string(struct cpu * Line 275  char *memory_conv_to_string(struct cpu *
275  /*  /*
276   *  memory_device_dyntrans_access():   *  memory_device_dyntrans_access():
277   *   *
278   *  Get the lowest and highest dyntrans (or bintrans) access since last time.   *  Get the lowest and highest dyntrans access since last time.
279   */   */
280  void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem,  void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem,
281          void *extra, uint64_t *low, uint64_t *high)          void *extra, uint64_t *low, uint64_t *high)
282  {  {
         int i, j;  
283          size_t s;          size_t s;
284          int need_inval = 0;          int i, need_inval = 0;
285    
286          /*  TODO: This is O(n), so it might be good to rewrite it some day.          /*  TODO: This is O(n), so it might be good to rewrite it some day.
287              For now, it will be enough, as long as this function is not              For now, it will be enough, as long as this function is not
288              called too often.  */              called too often.  */
289    
290          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
291                  if (mem->dev_extra[i] == extra &&                  if (mem->devices[i].extra == extra &&
292                      mem->dev_dyntrans_data[i] != NULL) {                      mem->devices[i].flags & DM_DYNTRANS_WRITE_OK &&
293                          if (mem->dev_dyntrans_write_low[i] != (uint64_t) -1)                      mem->devices[i].dyntrans_data != NULL) {
294                            if (mem->devices[i].dyntrans_write_low != (uint64_t) -1)
295                                  need_inval = 1;                                  need_inval = 1;
296                          if (low != NULL)                          if (low != NULL)
297                                  *low = mem->dev_dyntrans_write_low[i];                                  *low = mem->devices[i].dyntrans_write_low;
298                          mem->dev_dyntrans_write_low[i] = (uint64_t) -1;                          mem->devices[i].dyntrans_write_low = (uint64_t) -1;
299    
300                          if (high != NULL)                          if (high != NULL)
301                                  *high = mem->dev_dyntrans_write_high[i];                                  *high = mem->devices[i].dyntrans_write_high;
302                          mem->dev_dyntrans_write_high[i] = 0;                          mem->devices[i].dyntrans_write_high = 0;
303    
304                          if (!need_inval)                          if (!need_inval)
305                                  return;                                  return;
# Line 290  void memory_device_dyntrans_access(struc Line 307  void memory_device_dyntrans_access(struc
307                          /*  Invalidate any pages of this device that might                          /*  Invalidate any pages of this device that might
308                              be in the dyntrans load/store cache, by marking                              be in the dyntrans load/store cache, by marking
309                              the pages read-only.  */                              the pages read-only.  */
310                          if (cpu->invalidate_translation_caches_paddr != NULL) {                          if (cpu->invalidate_translation_caches != NULL) {
311                                  for (s=0; s<mem->dev_length[i];                                  for (s = *low; s <= *high;
312                                      s+=cpu->machine->arch_pagesize)                                      s += cpu->machine->arch_pagesize)
313                                          cpu->invalidate_translation_caches_paddr                                          cpu->invalidate_translation_caches
314                                              (cpu, mem->dev_baseaddr[i] + s);                                              (cpu, mem->devices[i].baseaddr + s,
315                                                JUST_MARK_AS_NON_WRITABLE
316                                                | INVALIDATE_PADDR);
317                          }                          }
318    
                         if (cpu->machine->arch == ARCH_MIPS) {  
                                 /*  
                                  *  ... and invalidate the "fast_vaddr_to_  
                                  *  hostaddr" cache entries that contain  
                                  *  pointers to this device:  (NOTE: Device i,  
                                  *  cache entry j)  
                                  */  
                                 for (j=0; j<N_BINTRANS_VADDR_TO_HOST; j++) {  
                                         if (cpu->cd.  
                                             mips.bintrans_data_hostpage[j] >=  
                                             mem->dev_dyntrans_data[i] &&  
                                             cpu->cd.mips.  
                                             bintrans_data_hostpage[j] <  
                                             mem->dev_dyntrans_data[i] +  
                                             mem->dev_length[i])  
                                                 cpu->cd.mips.  
                                                     bintrans_data_hostpage[j]  
                                                     = NULL;  
                                 }  
                         }  
319                          return;                          return;
320                  }                  }
321          }          }
# Line 324  void memory_device_dyntrans_access(struc Line 323  void memory_device_dyntrans_access(struc
323    
324    
325  /*  /*
326   *  memory_device_register_statefunction():   *  memory_device_update_data():
327   *   *
328   *  TODO: Hm. This is semi-ugly. Should probably be rewritten/redesigned   *  Update a device' dyntrans data pointer.
329   *  some day.   *
330     *  SUPER-IMPORTANT NOTE: Anyone who changes a dyntrans data pointer while
331     *  things are running also needs to invalidate all CPUs' address translation
332     *  caches!  Otherwise, these may contain old pointers to the old data.
333   */   */
334  void memory_device_register_statefunction(  void memory_device_update_data(struct memory *mem, void *extra,
335          struct memory *mem, void *extra,          unsigned char *data)
         int (*dev_f_state)(struct cpu *,  
             struct memory *, void *extra, int wf, int nr,  
             int *type, char **namep, void **data, size_t *len))  
336  {  {
337          int i;          int i;
338    
339          for (i=0; i<mem->n_mmapped_devices; i++)          for (i=0; i<mem->n_mmapped_devices; i++) {
340                  if (mem->dev_extra[i] == extra) {                  if (mem->devices[i].extra != extra)
341                          mem->dev_f_state[i] = dev_f_state;                          continue;
                         return;  
                 }  
342    
343          printf("memory_device_register_statefunction(): "                  mem->devices[i].dyntrans_data = data;
344              "couldn't find the device\n");                  mem->devices[i].dyntrans_write_low = (uint64_t)-1;
345          exit(1);                  mem->devices[i].dyntrans_write_high = 0;
346            }
347  }  }
348    
349    
350  /*  /*
351   *  memory_device_register():   *  memory_device_register():
352   *   *
353   *  Register a (memory mapped) device by adding it to the dev_* fields of a   *  Register a memory mapped device.
  *  memory struct.  
354   */   */
355  void memory_device_register(struct memory *mem, const char *device_name,  void memory_device_register(struct memory *mem, const char *device_name,
356          uint64_t baseaddr, uint64_t len,          uint64_t baseaddr, uint64_t len,
# Line 361  void memory_device_register(struct memor Line 358  void memory_device_register(struct memor
358                  size_t,int,void *),                  size_t,int,void *),
359          void *extra, int flags, unsigned char *dyntrans_data)          void *extra, int flags, unsigned char *dyntrans_data)
360  {  {
361          int i;          int i, newi = 0;
   
         if (mem->n_mmapped_devices >= MAX_DEVICES) {  
                 fprintf(stderr, "memory_device_register(): too many "  
                     "devices registered, cannot register '%s'\n", device_name);  
                 exit(1);  
         }  
362    
363          /*  Check for collisions:  */          /*
364             *  Figure out at which index to insert this device, and simultaneously
365             *  check for collisions:
366             */
367            newi = -1;
368          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
369                  /*  If we are not colliding with device i, then continue:  */                  if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr)
370                  if (baseaddr + len <= mem->dev_baseaddr[i])                          newi = i;
371                    if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr &&
372                        baseaddr >= mem->devices[i-1].endaddr)
373                            newi = i;
374                    if (i == mem->n_mmapped_devices - 1 &&
375                        baseaddr >= mem->devices[i].endaddr)
376                            newi = i + 1;
377    
378                    /*  If this is not colliding with device i, then continue:  */
379                    if (baseaddr + len <= mem->devices[i].baseaddr)
380                          continue;                          continue;
381                  if (baseaddr >= mem->dev_baseaddr[i] + mem->dev_length[i])                  if (baseaddr >= mem->devices[i].endaddr)
382                          continue;                          continue;
383    
384                  fatal("\nWARNING! \"%s\" collides with device %i (\"%s\")!\n"                  fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",
385                      "         Run-time behaviour will be undefined!\n\n",                      device_name, i, mem->devices[i].name);
386                      device_name, i, mem->dev_name[i]);                  exit(1);
387            }
388            if (mem->n_mmapped_devices == 0)
389                    newi = 0;
390            if (newi == -1) {
391                    fatal("INTERNAL ERROR\n");
392                    exit(1);
393          }          }
394    
395          /*  (40 bits of physical address is displayed)  */          if (verbose >= 2) {
396          debug("device %2i at 0x%010llx: %s",                  /*  (40 bits of physical address is displayed)  */
397              mem->n_mmapped_devices, (long long)baseaddr, device_name);                  debug("device at 0x%010"PRIx64": %s", (uint64_t) baseaddr,
398                        device_name);
399    
400                    if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
401                        && (baseaddr & mem->dev_dyntrans_alignment) != 0) {
402                            fatal("\nWARNING: Device dyntrans access, but unaligned"
403                                " baseaddr 0x%"PRIx64".\n", (uint64_t) baseaddr);
404                    }
405    
406                    if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
407                            debug(" (dyntrans %s)",
408                                (flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R");
409                    }
410                    debug("\n");
411            }
412    
413          if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)          for (i=0; i<mem->n_mmapped_devices; i++) {
414              && (baseaddr & mem->dev_dyntrans_alignment) != 0) {                  if (dyntrans_data == mem->devices[i].dyntrans_data &&
415                  fatal("\nWARNING: Device dyntrans access, but unaligned"                      mem->devices[i].flags&(DM_DYNTRANS_OK|DM_DYNTRANS_WRITE_OK)
416                      " baseaddr 0x%llx.\n", (long long)baseaddr);                      && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
417                            fatal("ERROR: the data pointer used for dyntrans "
418                                "accesses must only be used once!\n");
419                            fatal("(%p cannot be used by '%s'; already in use by '"
420                                "%s')\n", dyntrans_data, device_name,
421                                mem->devices[i].name);
422                            exit(1);
423                    }
424          }          }
425    
426          if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)) {          mem->n_mmapped_devices++;
427                  debug(" (dyntrans %s)",  
428                      (flags & MEM_DYNTRANS_WRITE_OK)? "R/W" : "R");          mem->devices = realloc(mem->devices, sizeof(struct memory_device)
429                * mem->n_mmapped_devices);
430            if (mem->devices == NULL) {
431                    fprintf(stderr, "out of memory\n");
432                    exit(1);
433          }          }
         debug("\n");  
434    
435          mem->dev_name[mem->n_mmapped_devices] = strdup(device_name);          /*  Make space for the new entry:  */
436          mem->dev_baseaddr[mem->n_mmapped_devices] = baseaddr;          if (newi + 1 != mem->n_mmapped_devices)
437          mem->dev_length[mem->n_mmapped_devices] = len;                  memmove(&mem->devices[newi+1], &mem->devices[newi],
438          mem->dev_flags[mem->n_mmapped_devices] = flags;                      sizeof(struct memory_device)
439          mem->dev_dyntrans_data[mem->n_mmapped_devices] = dyntrans_data;                      * (mem->n_mmapped_devices - newi - 1));
440    
441            mem->devices[newi].name = strdup(device_name);
442            mem->devices[newi].baseaddr = baseaddr;
443            mem->devices[newi].endaddr = baseaddr + len;
444            mem->devices[newi].length = len;
445            mem->devices[newi].flags = flags;
446            mem->devices[newi].dyntrans_data = dyntrans_data;
447    
448          if (mem->dev_name[mem->n_mmapped_devices] == NULL) {          if (mem->devices[newi].name == NULL) {
449                  fprintf(stderr, "out of memory\n");                  fprintf(stderr, "out of memory\n");
450                  exit(1);                  exit(1);
451          }          }
452    
453          if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)          if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
454              && dyntrans_data == NULL) {              && !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) {
455                  fatal("\nERROR: Device dyntrans access, but dyntrans_data"                  fatal("\nERROR: Device dyntrans access, but dyntrans_data"
456                      " = NULL!\n");                      " = NULL!\n");
457                  exit(1);                  exit(1);
458          }          }
459    
460          if ((size_t)dyntrans_data & 7) {          if ((size_t)dyntrans_data & (sizeof(void *) - 1)) {
461                  fprintf(stderr, "memory_device_register():"                  fprintf(stderr, "memory_device_register():"
462                      " dyntrans_data not aligned correctly (%p)\n",                      " dyntrans_data not aligned correctly (%p)\n",
463                      dyntrans_data);                      dyntrans_data);
464                  exit(1);                  exit(1);
465          }          }
466    
467          mem->dev_dyntrans_write_low[mem->n_mmapped_devices] = (uint64_t)-1;          mem->devices[newi].dyntrans_write_low = (uint64_t)-1;
468          mem->dev_dyntrans_write_high[mem->n_mmapped_devices] = 0;          mem->devices[newi].dyntrans_write_high = 0;
469          mem->dev_f[mem->n_mmapped_devices] = f;          mem->devices[newi].f = f;
470          mem->dev_extra[mem->n_mmapped_devices] = extra;          mem->devices[newi].extra = extra;
         mem->n_mmapped_devices++;  
471    
472          if (baseaddr < mem->mmap_dev_minaddr)          if (baseaddr < mem->mmap_dev_minaddr)
473                  mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;                  mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;
474          if (baseaddr + len > mem->mmap_dev_maxaddr)          if (baseaddr + len > mem->mmap_dev_maxaddr)
475                  mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |                  mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |
476                      mem->dev_dyntrans_alignment) + 1;                      mem->dev_dyntrans_alignment) + 1;
477    
478            if (newi < mem->last_accessed_device)
479                    mem->last_accessed_device ++;
480  }  }
481    
482    
483  /*  /*
484   *  memory_device_remove():   *  memory_device_remove():
485   *   *
486   *  Unregister a (memory mapped) device from a memory struct.   *  Unregister a memory mapped device from a memory object.
487   */   */
488  void memory_device_remove(struct memory *mem, int i)  void memory_device_remove(struct memory *mem, int i)
489  {  {
490          if (i < 0 || i >= mem->n_mmapped_devices) {          if (i < 0 || i >= mem->n_mmapped_devices) {
491                  fatal("memory_device_remove(): invalid device number %i\n", i);                  fatal("memory_device_remove(): invalid device number %i\n", i);
492                  return;                  exit(1);
493          }          }
494    
495          mem->n_mmapped_devices --;          mem->n_mmapped_devices --;
# Line 454  void memory_device_remove(struct memory Line 497  void memory_device_remove(struct memory
497          if (i == mem->n_mmapped_devices)          if (i == mem->n_mmapped_devices)
498                  return;                  return;
499    
500          /*          memmove(&mem->devices[i], &mem->devices[i+1],
501           *  YUCK! This is ugly. TODO: fix              sizeof(struct memory_device) * (mem->n_mmapped_devices - i));
          */  
502    
503          memmove(&mem->dev_name[i], &mem->dev_name[i+1], sizeof(char *) *          if (i <= mem->last_accessed_device)
504              (MAX_DEVICES - i - 1));                  mem->last_accessed_device --;
505          memmove(&mem->dev_baseaddr[i], &mem->dev_baseaddr[i+1],          if (mem->last_accessed_device < 0)
506              sizeof(uint64_t) * (MAX_DEVICES - i - 1));                  mem->last_accessed_device = 0;
         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_f_state[i], &mem->dev_f_state[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(void *) * (MAX_DEVICES - i - 1));  
         memmove(&mem->dev_dyntrans_write_high[i], &mem->dev_dyntrans_write_high  
             [i+1], sizeof(void *) * (MAX_DEVICES - i - 1));  
507  }  }
508    
509    
# Line 491  void memory_device_remove(struct memory Line 517  void memory_device_remove(struct memory
517  /*  /*
518   *  memory_paddr_to_hostaddr():   *  memory_paddr_to_hostaddr():
519   *   *
520   *  Translate a physical address into a host address.   *  Translate a physical address into a host address. The usual way to call
521     *  this function is to make sure that paddr is page aligned, which will result
522     *  in the host _page_ corresponding to that address.
523   *   *
524   *  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.
525   *  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.
526   */   */
527  unsigned char *memory_paddr_to_hostaddr(struct memory *mem,  unsigned char *memory_paddr_to_hostaddr(struct memory *mem,
# Line 503  unsigned char *memory_paddr_to_hostaddr( Line 531  unsigned char *memory_paddr_to_hostaddr(
531          int entry;          int entry;
532          const int mask = (1 << BITS_PER_PAGETABLE) - 1;          const int mask = (1 << BITS_PER_PAGETABLE) - 1;
533          const int shrcount = MAX_BITS - BITS_PER_PAGETABLE;          const int shrcount = MAX_BITS - BITS_PER_PAGETABLE;
534            unsigned char *hostptr;
535    
536          table = mem->pagetable;          table = mem->pagetable;
537          entry = (paddr >> shrcount) & mask;          entry = (paddr >> shrcount) & mask;
538    
539          /*  printf("memory_paddr_to_hostaddr(): p=%16llx w=%i => entry=0x%x\n",          /*  printf("memory_paddr_to_hostaddr(): p=%16"PRIx64
540              (long long)paddr, writeflag, entry);  */              " w=%i => entry=0x%x\n", (uint64_t) paddr, writeflag, entry);  */
541    
542          if (table[entry] == NULL) {          if (table[entry] == NULL) {
543                  size_t alloclen;                  size_t alloclen;
# Line 531  unsigned char *memory_paddr_to_hostaddr( Line 560  unsigned char *memory_paddr_to_hostaddr(
560                  /*  Anonymous mmap() should return zero-filled memory,                  /*  Anonymous mmap() should return zero-filled memory,
561                      try malloc + memset if mmap failed.  */                      try malloc + memset if mmap failed.  */
562                  table[entry] = (void *) mmap(NULL, alloclen,                  table[entry] = (void *) mmap(NULL, alloclen,
563                      PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,                      PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
                     -1, 0);  
564                  if (table[entry] == NULL) {                  if (table[entry] == NULL) {
565                          table[entry] = malloc(alloclen);                          table[entry] = malloc(alloclen);
566                          if (table[entry] == NULL) {                          if (table[entry] == NULL) {
# Line 543  unsigned char *memory_paddr_to_hostaddr( Line 571  unsigned char *memory_paddr_to_hostaddr(
571                  }                  }
572          }          }
573    
574          return (unsigned char *) table[entry];          hostptr = (unsigned char *) table[entry];
575    
576            if (hostptr != NULL)
577                    hostptr += (paddr & ((1 << BITS_PER_MEMBLOCK) - 1));
578    
579            return hostptr;
580    }
581    
582    
583    #define UPDATE_CHECKSUM(value) {                                        \
584                    internal_state -= 0x118c7771c0c0a77fULL;                \
585                    internal_state = ((internal_state + (value)) << 7) ^    \
586                        (checksum >> 11) ^ ((checksum - (value)) << 3) ^    \
587                        (internal_state - checksum) ^ ((value) - internal_state); \
588                    checksum ^= internal_state;                             \
589            }
590    
591    
592    /*
593     *  memory_checksum():
594     *
595     *  Calculate a 64-bit checksum of everything in a struct memory. This is
596     *  useful for tracking down bugs; an old (presumably working) version of
597     *  the emulator can be compared to a newer (buggy) version.
598     */
599    uint64_t memory_checksum(struct memory *mem)
600    {
601            uint64_t internal_state = 0x80624185376feff2ULL;
602            uint64_t checksum = 0xcb9a87d5c010072cULL;
603            const int n_entries = (1 << BITS_PER_PAGETABLE) - 1;
604            const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t);
605            size_t entry, i;
606    
607            for (entry=0; entry<=n_entries; entry++) {
608                    uint64_t **table = mem->pagetable;
609                    uint64_t *memblock = table[entry];
610    
611                    if (memblock == NULL) {
612                            UPDATE_CHECKSUM(0x1198ab7c8174a76fULL);
613                            continue;
614                    }
615    
616                    for (i=0; i<len; i++)
617                            UPDATE_CHECKSUM(memblock[i]);
618            }
619    
620            return checksum;
621  }  }
622    

Legend:
Removed from v.12  
changed lines
  Added in v.32

  ViewVC Help
Powered by ViewVC 1.1.26