/[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 20 by dpavlin, Mon Oct 8 16:19:23 2007 UTC revision 40 by dpavlin, Mon Oct 8 16:22:11 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  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.182 2005/11/22 16:26:36 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 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 verbose;
46  extern int quiet_mode;  extern int quiet_mode;
 extern volatile int single_step;  
47    
48    
49  /*  /*
# Line 124  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 194  struct memory *memory_new(uint64_t physi Line 201  struct memory *memory_new(uint64_t physi
201  /*  /*
202   *  memory_points_to_string():   *  memory_points_to_string():
203   *   *
204   *  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
205     *  addr, otherwise 0.
206   */   */
207  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,
208          int min_string_length)          int min_string_length)
# Line 223  int memory_points_to_string(struct cpu * Line 231  int memory_points_to_string(struct cpu *
231  /*  /*
232   *  memory_conv_to_string():   *  memory_conv_to_string():
233   *   *
234   *  Convert virtual memory contents to a string, placing it in a   *  Convert emulated memory contents to a string, placing it in a buffer
235   *  buffer provided by the caller.   *  provided by the caller.
236   */   */
237  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,
238          char *buf, int bufsize)          char *buf, int bufsize)
# Line 268  char *memory_conv_to_string(struct cpu * Line 276  char *memory_conv_to_string(struct cpu *
276  /*  /*
277   *  memory_device_dyntrans_access():   *  memory_device_dyntrans_access():
278   *   *
279   *  Get the lowest and highest dyntrans (or bintrans) access since last time.   *  Get the lowest and highest dyntrans access since last time.
280   */   */
281  void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem,  void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem,
282          void *extra, uint64_t *low, uint64_t *high)          void *extra, uint64_t *low, uint64_t *high)
283  {  {
         int i, j;  
284          size_t s;          size_t s;
285          int need_inval = 0;          int i, need_inval = 0;
286    
287          /*  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.
288              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
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_dyntrans_data[i] != NULL) {                      mem->devices[i].flags & DM_DYNTRANS_WRITE_OK &&
294                          if (mem->dev_dyntrans_write_low[i] != (uint64_t) -1)                      mem->devices[i].dyntrans_data != NULL) {
295                            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 301  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                          }                          }
319    
                         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;  
                                 }  
                         }  
320                          return;                          return;
321                  }                  }
322          }          }
# Line 336  void memory_device_dyntrans_access(struc Line 324  void memory_device_dyntrans_access(struc
324    
325    
326  /*  /*
327   *  memory_device_register_statefunction():   *  memory_device_update_data():
328     *
329     *  Update a device' dyntrans data pointer.
330   *   *
331   *  TODO: Hm. This is semi-ugly. Should probably be rewritten/redesigned   *  SUPER-IMPORTANT NOTE: Anyone who changes a dyntrans data pointer while
332   *  some day.   *  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_register_statefunction(  void memory_device_update_data(struct memory *mem, void *extra,
336          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))  
337  {  {
338          int i;          int i;
339    
340          for (i=0; i<mem->n_mmapped_devices; i++)          for (i=0; i<mem->n_mmapped_devices; i++) {
341                  if (mem->dev_extra[i] == extra) {                  if (mem->devices[i].extra != extra)
342                          mem->dev_f_state[i] = dev_f_state;                          continue;
                         return;  
                 }  
343    
344          printf("memory_device_register_statefunction(): "                  mem->devices[i].dyntrans_data = data;
345              "couldn't find the device\n");                  mem->devices[i].dyntrans_write_low = (uint64_t)-1;
346          exit(1);                  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 373  void memory_device_register(struct memor Line 359  void memory_device_register(struct memor
359                  size_t,int,void *),                  size_t,int,void *),
360          void *extra, int flags, unsigned char *dyntrans_data)          void *extra, int flags, unsigned char *dyntrans_data)
361  {  {
362          int i;          int i, newi = 0;
363    
364          if (mem->n_mmapped_devices >= MAX_DEVICES) {          /*
365                  fprintf(stderr, "memory_device_register(): too many "           *  Figure out at which index to insert this device, and simultaneously
366                      "devices registered, cannot register '%s'\n", device_name);           *  check for collisions:
367                  exit(1);           */
368          }          newi = -1;
   
         /*  Check for collisions:  */  
369          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
370                  /*  If we are not colliding with device i, then continue:  */                  if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr)
371                  if (baseaddr + len <= mem->dev_baseaddr[i])                          newi = i;
372                    if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr &&
373                        baseaddr >= mem->devices[i-1].endaddr)
374                            newi = i;
375                    if (i == mem->n_mmapped_devices - 1 &&
376                        baseaddr >= mem->devices[i].endaddr)
377                            newi = i + 1;
378    
379                    /*  If this is not colliding with device i, then continue:  */
380                    if (baseaddr + len <= mem->devices[i].baseaddr)
381                          continue;                          continue;
382                  if (baseaddr >= mem->dev_baseaddr[i] + mem->dev_length[i])                  if (baseaddr >= mem->devices[i].endaddr)
383                          continue;                          continue;
384    
385                  fatal("\nWARNING! \"%s\" collides with device %i (\"%s\")!\n"                  fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",
386                      "         Run-time behaviour will be undefined!\n\n",                      device_name, i, mem->devices[i].name);
387                      device_name, i, mem->dev_name[i]);                  exit(1);
388            }
389            if (mem->n_mmapped_devices == 0)
390                    newi = 0;
391            if (newi == -1) {
392                    fatal("INTERNAL ERROR\n");
393                    exit(1);
394          }          }
395    
396          /*  (40 bits of physical address is displayed)  */          if (verbose >= 2) {
397          debug("device %2i at 0x%010llx: %s",                  /*  (40 bits of physical address is displayed)  */
398              mem->n_mmapped_devices, (long long)baseaddr, device_name);                  debug("device at 0x%010"PRIx64": %s", (uint64_t) baseaddr,
399                        device_name);
400    
401                    if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
402                        && (baseaddr & mem->dev_dyntrans_alignment) != 0) {
403                            fatal("\nWARNING: Device dyntrans access, but unaligned"
404                                " baseaddr 0x%"PRIx64".\n", (uint64_t) baseaddr);
405                    }
406    
407                    if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
408                            debug(" (dyntrans %s)",
409                                (flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R");
410                    }
411                    debug("\n");
412            }
413    
414          if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)          for (i=0; i<mem->n_mmapped_devices; i++) {
415              && (baseaddr & mem->dev_dyntrans_alignment) != 0) {                  if (dyntrans_data == mem->devices[i].dyntrans_data &&
416                  fatal("\nWARNING: Device dyntrans access, but unaligned"                      mem->devices[i].flags&(DM_DYNTRANS_OK|DM_DYNTRANS_WRITE_OK)
417                      " baseaddr 0x%llx.\n", (long long)baseaddr);                      && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
418                            fatal("ERROR: the data pointer used for dyntrans "
419                                "accesses must only be used once!\n");
420                            fatal("(%p cannot be used by '%s'; already in use by '"
421                                "%s')\n", dyntrans_data, device_name,
422                                mem->devices[i].name);
423                            exit(1);
424                    }
425          }          }
426    
427          if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {          mem->n_mmapped_devices++;
428                  debug(" (dyntrans %s)",  
429                      (flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R");          mem->devices = realloc(mem->devices, sizeof(struct memory_device)
430                * mem->n_mmapped_devices);
431            if (mem->devices == NULL) {
432                    fprintf(stderr, "out of memory\n");
433                    exit(1);
434          }          }
         debug("\n");  
435    
436          mem->dev_name[mem->n_mmapped_devices] = strdup(device_name);          /*  Make space for the new entry:  */
437          mem->dev_baseaddr[mem->n_mmapped_devices] = baseaddr;          if (newi + 1 != mem->n_mmapped_devices)
438          mem->dev_endaddr[mem->n_mmapped_devices] = baseaddr + len;                  memmove(&mem->devices[newi+1], &mem->devices[newi],
439          mem->dev_length[mem->n_mmapped_devices] = len;                      sizeof(struct memory_device)
440          mem->dev_flags[mem->n_mmapped_devices] = flags;                      * (mem->n_mmapped_devices - newi - 1));
441          mem->dev_dyntrans_data[mem->n_mmapped_devices] = dyntrans_data;  
442            mem->devices[newi].name = strdup(device_name);
443            mem->devices[newi].baseaddr = baseaddr;
444            mem->devices[newi].endaddr = baseaddr + len;
445            mem->devices[newi].length = len;
446            mem->devices[newi].flags = flags;
447            mem->devices[newi].dyntrans_data = dyntrans_data;
448    
449          if (mem->dev_name[mem->n_mmapped_devices] == 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 436  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[mem->n_mmapped_devices] = (uint64_t)-1;          mem->devices[newi].dyntrans_write_low = (uint64_t)-1;
469          mem->dev_dyntrans_write_high[mem->n_mmapped_devices] = 0;          mem->devices[newi].dyntrans_write_high = 0;
470          mem->dev_f[mem->n_mmapped_devices] = f;          mem->devices[newi].f = f;
471          mem->dev_extra[mem->n_mmapped_devices] = extra;          mem->devices[newi].extra = extra;
         mem->n_mmapped_devices++;  
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 467  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_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));  
508  }  }
509    
510    
# Line 504  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 516  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;
539    
540          /*  printf("memory_paddr_to_hostaddr(): p=%16llx w=%i => entry=0x%x\n",          /*  printf("memory_paddr_to_hostaddr(): p=%16"PRIx64
541              (long long)paddr, writeflag, entry);  */              " w=%i => entry=0x%x\n", (uint64_t) paddr, writeflag, entry);  */
542    
543          if (table[entry] == NULL) {          if (table[entry] == NULL) {
544                  size_t alloclen;                  size_t alloclen;
# Line 544  unsigned char *memory_paddr_to_hostaddr( Line 561  unsigned char *memory_paddr_to_hostaddr(
561                  /*  Anonymous mmap() should return zero-filled memory,                  /*  Anonymous mmap() should return zero-filled memory,
562                      try malloc + memset if mmap failed.  */                      try malloc + memset if mmap failed.  */
563                  table[entry] = (void *) mmap(NULL, alloclen,                  table[entry] = (void *) mmap(NULL, alloclen,
564                      PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,                      PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
                     -1, 0);  
565                  if (table[entry] == NULL) {                  if (table[entry] == NULL) {
566                          table[entry] = malloc(alloclen);                          table[entry] = malloc(alloclen);
567                          if (table[entry] == NULL) {                          if (table[entry] == NULL) {
# Line 556  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    
584    #define UPDATE_CHECKSUM(value) {                                        \
585                    internal_state -= 0x118c7771c0c0a77fULL;                \
586                    internal_state = ((internal_state + (value)) << 7) ^    \
587                        (checksum >> 11) ^ ((checksum - (value)) << 3) ^    \
588                        (internal_state - checksum) ^ ((value) - internal_state); \
589                    checksum ^= internal_state;                             \
590            }
591    
592    
593    /*
594     *  memory_checksum():
595     *
596     *  Calculate a 64-bit checksum of everything in a struct memory. This is
597     *  useful for tracking down bugs; an old (presumably working) version of
598     *  the emulator can be compared to a newer (buggy) version.
599     */
600    uint64_t memory_checksum(struct memory *mem)
601    {
602            uint64_t internal_state = 0x80624185376feff2ULL;
603            uint64_t checksum = 0xcb9a87d5c010072cULL;
604            const size_t n_entries = (1 << BITS_PER_PAGETABLE) - 1;
605            const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t);
606            size_t entry, i;
607    
608            for (entry=0; entry<=n_entries; entry++) {
609                    uint64_t **table = mem->pagetable;
610                    uint64_t *memblock = table[entry];
611    
612                    if (memblock == NULL) {
613                            UPDATE_CHECKSUM(0x1198ab7c8174a76fULL);
614                            continue;
615                    }
616    
617                    for (i=0; i<len; i++)
618                            UPDATE_CHECKSUM(memblock[i]);
619            }
620    
621            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.20  
changed lines
  Added in v.40

  ViewVC Help
Powered by ViewVC 1.1.26