/[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 28 by dpavlin, Mon Oct 8 16:20:26 2007 UTC revision 42 by dpavlin, Mon Oct 8 16:22:32 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.192 2006/07/14 16:33:27 debug Exp $   *  $Id: memory.c,v 1.204 2007/06/15 17:02:38 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                  p = malloc(s);  #if 1
127                  if (p == NULL) {                  fprintf(stderr, "zeroed_alloc(): mmap() failed. This should"
128                          fprintf(stderr, "out of memory\n");                      " not usually happen. If you can reproduce this, then"
129                          exit(1);                      " please contact me with details about your run-time"
130                  }                      " environment.\n");
131                    exit(1);
132    #else
133                    CHECK_ALLOCATION(p = malloc(s));
134                  memset(p, 0, s);                  memset(p, 0, s);
135    #endif
136          }          }
137    
138          return p;          return p;
139  }  }
140    
# Line 147  struct memory *memory_new(uint64_t physi Line 154  struct memory *memory_new(uint64_t physi
154          int max_bits = MAX_BITS;          int max_bits = MAX_BITS;
155          size_t s;          size_t s;
156    
157          mem = malloc(sizeof(struct memory));          CHECK_ALLOCATION(mem = malloc(sizeof(struct memory)));
         if (mem == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
   
158          memset(mem, 0, sizeof(struct memory));          memset(mem, 0, sizeof(struct memory));
159    
160          /*  Check bits_per_pagetable and bits_per_memblock for sanity:  */          /*  Check bits_per_pagetable and bits_per_memblock for sanity:  */
# Line 172  struct memory *memory_new(uint64_t physi Line 174  struct memory *memory_new(uint64_t physi
174          mem->pagetable = (unsigned char *) mmap(NULL, s,          mem->pagetable = (unsigned char *) mmap(NULL, s,
175              PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);              PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
176          if (mem->pagetable == NULL) {          if (mem->pagetable == NULL) {
177                  mem->pagetable = malloc(s);                  CHECK_ALLOCATION(mem->pagetable = malloc(s));
                 if (mem->pagetable == NULL) {  
                         fprintf(stderr, "out of memory\n");  
                         exit(1);  
                 }  
178                  memset(mem->pagetable, 0, s);                  memset(mem->pagetable, 0, s);
179          }          }
180    
# Line 278  void memory_device_dyntrans_access(struc Line 276  void memory_device_dyntrans_access(struc
276              called too often.  */              called too often.  */
277    
278          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
279                  if (mem->dev_extra[i] == extra &&                  if (mem->devices[i].extra == extra &&
280                      mem->dev_flags[i] & DM_DYNTRANS_WRITE_OK &&                      mem->devices[i].flags & DM_DYNTRANS_WRITE_OK &&
281                      mem->dev_dyntrans_data[i] != NULL) {                      mem->devices[i].dyntrans_data != NULL) {
282                          if (mem->dev_dyntrans_write_low[i] != (uint64_t) -1)                          if (mem->devices[i].dyntrans_write_low != (uint64_t) -1)
283                                  need_inval = 1;                                  need_inval = 1;
284                          if (low != NULL)                          if (low != NULL)
285                                  *low = mem->dev_dyntrans_write_low[i];                                  *low = mem->devices[i].dyntrans_write_low;
286                          mem->dev_dyntrans_write_low[i] = (uint64_t) -1;                          mem->devices[i].dyntrans_write_low = (uint64_t) -1;
287    
288                          if (high != NULL)                          if (high != NULL)
289                                  *high = mem->dev_dyntrans_write_high[i];                                  *high = mem->devices[i].dyntrans_write_high;
290                          mem->dev_dyntrans_write_high[i] = 0;                          mem->devices[i].dyntrans_write_high = 0;
291    
292                          if (!need_inval)                          if (!need_inval)
293                                  return;                                  return;
# Line 298  void memory_device_dyntrans_access(struc Line 296  void memory_device_dyntrans_access(struc
296                              be in the dyntrans load/store cache, by marking                              be in the dyntrans load/store cache, by marking
297                              the pages read-only.  */                              the pages read-only.  */
298                          if (cpu->invalidate_translation_caches != NULL) {                          if (cpu->invalidate_translation_caches != NULL) {
299                                  for (s=0; s<mem->dev_length[i];                                  for (s = *low; s <= *high;
300                                      s+=cpu->machine->arch_pagesize)                                      s += cpu->machine->arch_pagesize)
301                                          cpu->invalidate_translation_caches                                          cpu->invalidate_translation_caches
302                                              (cpu, mem->dev_baseaddr[i] + s,                                              (cpu, mem->devices[i].baseaddr + s,
303                                              JUST_MARK_AS_NON_WRITABLE                                              JUST_MARK_AS_NON_WRITABLE
304                                              | INVALIDATE_PADDR);                                              | INVALIDATE_PADDR);
305                          }                          }
# Line 327  void memory_device_update_data(struct me Line 325  void memory_device_update_data(struct me
325          int i;          int i;
326    
327          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
328                  if (mem->dev_extra[i] != extra)                  if (mem->devices[i].extra != extra)
329                          continue;                          continue;
330    
331                  mem->dev_dyntrans_data[i] = data;                  mem->devices[i].dyntrans_data = data;
332                  mem->dev_dyntrans_write_low[i] = (uint64_t)-1;                  mem->devices[i].dyntrans_write_low = (uint64_t)-1;
333                  mem->dev_dyntrans_write_high[i] = 0;                  mem->devices[i].dyntrans_write_high = 0;
334          }          }
335  }  }
336    
# Line 340  void memory_device_update_data(struct me Line 338  void memory_device_update_data(struct me
338  /*  /*
339   *  memory_device_register():   *  memory_device_register():
340   *   *
341   *  Register a (memory mapped) device by adding it to the dev_* fields of a   *  Register a memory mapped device.
  *  memory struct.  
342   */   */
343  void memory_device_register(struct memory *mem, const char *device_name,  void memory_device_register(struct memory *mem, const char *device_name,
344          uint64_t baseaddr, uint64_t len,          uint64_t baseaddr, uint64_t len,
# Line 351  void memory_device_register(struct memor Line 348  void memory_device_register(struct memor
348  {  {
349          int i, newi = 0;          int i, newi = 0;
350    
         if (mem->n_mmapped_devices >= MAX_DEVICES) {  
                 fprintf(stderr, "memory_device_register(): too many "  
                     "devices registered, cannot register '%s'\n", device_name);  
                 exit(1);  
         }  
   
351          /*          /*
352           *  Figure out at which index to insert this device, and simultaneously           *  Figure out at which index to insert this device, and simultaneously
353           *  check for collisions:           *  check for collisions:
354           */           */
355          newi = -1;          newi = -1;
356          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
357                  if (i == 0 && baseaddr + len <= mem->dev_baseaddr[i])                  if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr)
358                          newi = i;                          newi = i;
359                  if (i > 0 && baseaddr + len <= mem->dev_baseaddr[i] &&                  if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr &&
360                      baseaddr >= mem->dev_endaddr[i-1])                      baseaddr >= mem->devices[i-1].endaddr)
361                          newi = i;                          newi = i;
362                  if (i == mem->n_mmapped_devices - 1 &&                  if (i == mem->n_mmapped_devices - 1 &&
363                      baseaddr >= mem->dev_endaddr[i])                      baseaddr >= mem->devices[i].endaddr)
364                          newi = i + 1;                          newi = i + 1;
365    
366                  /*  If we are not colliding with device i, then continue:  */                  /*  If this is not colliding with device i, then continue:  */
367                  if (baseaddr + len <= mem->dev_baseaddr[i])                  if (baseaddr + len <= mem->devices[i].baseaddr)
368                          continue;                          continue;
369                  if (baseaddr >= mem->dev_endaddr[i])                  if (baseaddr >= mem->devices[i].endaddr)
370                          continue;                          continue;
371    
372                  fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",                  fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",
373                      device_name, i, mem->dev_name[i]);                      device_name, i, mem->devices[i].name);
374                  exit(1);                  exit(1);
375          }          }
376          if (mem->n_mmapped_devices == 0)          if (mem->n_mmapped_devices == 0)
# Line 408  void memory_device_register(struct memor Line 399  void memory_device_register(struct memor
399          }          }
400    
401          for (i=0; i<mem->n_mmapped_devices; i++) {          for (i=0; i<mem->n_mmapped_devices; i++) {
402                  if (dyntrans_data == mem->dev_dyntrans_data[i] &&                  if (dyntrans_data == mem->devices[i].dyntrans_data &&
403                      mem->dev_flags[i] & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)                      mem->devices[i].flags&(DM_DYNTRANS_OK|DM_DYNTRANS_WRITE_OK)
404                      && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {                      && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
405                          fatal("ERROR: the data pointer used for dyntrans "                          fatal("ERROR: the data pointer used for dyntrans "
406                              "accesses must only be used once!\n");                              "accesses must only be used once!\n");
407                          fatal("(%p cannot be used by '%s'; already in use by '"                          fatal("(%p cannot be used by '%s'; already in use by '"
408                              "%s')\n", dyntrans_data, device_name,                              "%s')\n", dyntrans_data, device_name,
409                              mem->dev_name[i]);                              mem->devices[i].name);
410                          exit(1);                          exit(1);
411                  }                  }
412          }          }
413    
414          mem->n_mmapped_devices++;          mem->n_mmapped_devices++;
415    
416          /*          CHECK_ALLOCATION(mem->devices = realloc(mem->devices,
417           *  YUCK! This is ugly. TODO: fix              sizeof(struct memory_device) * mem->n_mmapped_devices));
          */  
         /*  Make space for the new entry:  */  
         memmove(&mem->dev_name[newi+1], &mem->dev_name[newi], sizeof(char *) *  
             (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_baseaddr[newi+1], &mem->dev_baseaddr[newi],  
             sizeof(uint64_t) * (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_endaddr[newi+1], &mem->dev_endaddr[newi],  
             sizeof(uint64_t) * (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_length[newi+1], &mem->dev_length[newi],  
             sizeof(uint64_t) * (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_flags[newi+1], &mem->dev_flags[newi], sizeof(int) *  
             (MAX_DEVICES - newi - 1));  
         memmove(&mem->dev_extra[newi+1], &mem->dev_extra[newi], sizeof(void *) *  
             (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;  
418    
419          if (mem->dev_name[newi] == NULL) {          /*  Make space for the new entry:  */
420                  fprintf(stderr, "out of memory\n");          if (newi + 1 != mem->n_mmapped_devices)
421                  exit(1);                  memmove(&mem->devices[newi+1], &mem->devices[newi],
422          }                      sizeof(struct memory_device)
423                        * (mem->n_mmapped_devices - newi - 1));
424    
425            CHECK_ALLOCATION(mem->devices[newi].name = strdup(device_name));
426            mem->devices[newi].baseaddr = baseaddr;
427            mem->devices[newi].endaddr = baseaddr + len;
428            mem->devices[newi].length = len;
429            mem->devices[newi].flags = flags;
430            mem->devices[newi].dyntrans_data = dyntrans_data;
431    
432          if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)          if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
433              && !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) {              && !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) {
# Line 476  void memory_device_register(struct memor Line 443  void memory_device_register(struct memor
443                  exit(1);                  exit(1);
444          }          }
445    
446          mem->dev_dyntrans_write_low[newi] = (uint64_t)-1;          mem->devices[newi].dyntrans_write_low = (uint64_t)-1;
447          mem->dev_dyntrans_write_high[newi] = 0;          mem->devices[newi].dyntrans_write_high = 0;
448          mem->dev_f[newi] = f;          mem->devices[newi].f = f;
449          mem->dev_extra[newi] = extra;          mem->devices[newi].extra = extra;
450    
451          if (baseaddr < mem->mmap_dev_minaddr)          if (baseaddr < mem->mmap_dev_minaddr)
452                  mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;                  mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;
453          if (baseaddr + len > mem->mmap_dev_maxaddr)          if (baseaddr + len > mem->mmap_dev_maxaddr)
454                  mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |                  mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |
455                      mem->dev_dyntrans_alignment) + 1;                      mem->dev_dyntrans_alignment) + 1;
456    
457            if (newi < mem->last_accessed_device)
458                    mem->last_accessed_device ++;
459  }  }
460    
461    
462  /*  /*
463   *  memory_device_remove():   *  memory_device_remove():
464   *   *
465   *  Unregister a (memory mapped) device from a memory struct.   *  Unregister a memory mapped device from a memory object.
466   */   */
467  void memory_device_remove(struct memory *mem, int i)  void memory_device_remove(struct memory *mem, int i)
468  {  {
469          if (i < 0 || i >= mem->n_mmapped_devices) {          if (i < 0 || i >= mem->n_mmapped_devices) {
470                  fatal("memory_device_remove(): invalid device number %i\n", i);                  fatal("memory_device_remove(): invalid device number %i\n", i);
471                  return;                  exit(1);
472          }          }
473    
474          mem->n_mmapped_devices --;          mem->n_mmapped_devices --;
# Line 506  void memory_device_remove(struct memory Line 476  void memory_device_remove(struct memory
476          if (i == mem->n_mmapped_devices)          if (i == mem->n_mmapped_devices)
477                  return;                  return;
478    
479          /*          memmove(&mem->devices[i], &mem->devices[i+1],
480           *  YUCK! This is ugly. TODO: fix              sizeof(struct memory_device) * (mem->n_mmapped_devices - i));
          */  
481    
482          memmove(&mem->dev_name[i], &mem->dev_name[i+1], sizeof(char *) *          if (i <= mem->last_accessed_device)
483              (MAX_DEVICES - i - 1));                  mem->last_accessed_device --;
484          memmove(&mem->dev_baseaddr[i], &mem->dev_baseaddr[i+1],          if (mem->last_accessed_device < 0)
485              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));  
486  }  }
487    
488    
# Line 588  unsigned char *memory_paddr_to_hostaddr( Line 541  unsigned char *memory_paddr_to_hostaddr(
541                  table[entry] = (void *) mmap(NULL, alloclen,                  table[entry] = (void *) mmap(NULL, alloclen,
542                      PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);                      PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
543                  if (table[entry] == NULL) {                  if (table[entry] == NULL) {
544                          table[entry] = malloc(alloclen);                          CHECK_ALLOCATION(table[entry] = malloc(alloclen));
                         if (table[entry] == NULL) {  
                                 fatal("out of memory\n");  
                                 exit(1);  
                         }  
545                          memset(table[entry], 0, alloclen);                          memset(table[entry], 0, alloclen);
546                  }                  }
547          }          }
# Line 626  uint64_t memory_checksum(struct memory * Line 575  uint64_t memory_checksum(struct memory *
575  {  {
576          uint64_t internal_state = 0x80624185376feff2ULL;          uint64_t internal_state = 0x80624185376feff2ULL;
577          uint64_t checksum = 0xcb9a87d5c010072cULL;          uint64_t checksum = 0xcb9a87d5c010072cULL;
578          const int n_entries = (1 << BITS_PER_PAGETABLE) - 1;          const size_t n_entries = (1 << BITS_PER_PAGETABLE) - 1;
579          const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t);          const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t);
580          size_t entry, i;          size_t entry, i;
581    
# Line 646  uint64_t memory_checksum(struct memory * Line 595  uint64_t memory_checksum(struct memory *
595          return checksum;          return checksum;
596  }  }
597    
598    
599    /*
600     *  memory_warn_about_unimplemented_addr():
601     *
602     *  Called from memory_rw whenever memory outside of the physical address space
603     *  is accessed (and quiet_mode isn't set).
604     */
605    void memory_warn_about_unimplemented_addr(struct cpu *cpu, struct memory *mem,
606            int writeflag, uint64_t paddr, uint8_t *data, size_t len)
607    {
608            uint64_t offset, old_pc = cpu->pc;
609            char *symbol;
610    
611            /*
612             *  This allows guest OS kernels to probe memory a few KBs past the
613             *  end of memory, without giving too many warnings.
614             */
615            if (paddr < mem->physical_max + 0x40000)
616                    return;
617    
618            if (!cpu->machine->halt_on_nonexistant_memaccess && quiet_mode)
619                    return;
620    
621            fatal("[ memory_rw(): %s ", writeflag? "write":"read");
622    
623            if (writeflag) {
624                    unsigned int i;
625                    debug("data={", writeflag);
626                    if (len > 16) {
627                            int start2 = len-16;
628                            for (i=0; i<16; i++)
629                                    debug("%s%02x", i?",":"", data[i]);
630                            debug(" .. ");
631                            if (start2 < 16)
632                                    start2 = 16;
633                            for (i=start2; i<len; i++)
634                                    debug("%s%02x", i?",":"", data[i]);
635                    } else
636                            for (i=0; i<len; i++)
637                                    debug("%s%02x", i?",":"", data[i]);
638                    debug("} ");
639            }
640    
641            fatal("paddr=0x%llx >= physical_max; pc=", (long long)paddr);
642            if (cpu->is_32bit)
643                    fatal("0x%08"PRIx32, (uint32_t) old_pc);
644            else
645                    fatal("0x%016"PRIx64, (uint64_t) old_pc);
646            symbol = get_symbol_name(&cpu->machine->symbol_context,
647                old_pc, &offset);
648            fatal(" <%s> ]\n", symbol? symbol : " no symbol ");
649    
650            if (cpu->machine->halt_on_nonexistant_memaccess) {
651                    /*  TODO: Halt in a nicer way. Not possible with the
652                        current dyntrans system...  */
653                    exit(1);
654            }
655    }
656    
657    
658    /*
659     *  dump_mem_string():
660     *
661     *  Dump the contents of emulated RAM as readable text.  Bytes that aren't
662     *  readable are dumped in [xx] notation, where xx is in hexadecimal.
663     *  Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating
664     *  zero byte is found.
665     */
666    #define DUMP_MEM_STRING_MAX     45
667    void dump_mem_string(struct cpu *cpu, uint64_t addr)
668    {
669            int i;
670            for (i=0; i<DUMP_MEM_STRING_MAX; i++) {
671                    unsigned char ch = '\0';
672    
673                    cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch),
674                        MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
675                    if (ch == '\0')
676                            return;
677                    if (ch >= ' ' && ch < 126)
678                            debug("%c", ch);  
679                    else
680                            debug("[%02x]", ch);
681            }
682    }
683    
684    
685    /*
686     *  store_byte():
687     *
688     *  Stores a byte in emulated ram. (Helper function.)
689     */
690    void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data)
691    {
692            if ((addr >> 32) == 0)
693                    addr = (int64_t)(int32_t)addr;
694            cpu->memory_rw(cpu, cpu->mem,
695                addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA);
696    }
697    
698    
699    /*
700     *  store_string():
701     *
702     *  Stores chars into emulated RAM until a zero byte (string terminating
703     *  character) is found. The zero byte is also copied.
704     *  (strcpy()-like helper function, host-RAM-to-emulated-RAM.)
705     */
706    void store_string(struct cpu *cpu, uint64_t addr, char *s)
707    {
708            do {
709                    store_byte(cpu, addr++, *s);
710            } while (*s++);
711    }
712    
713    
714    /*
715     *  add_environment_string():
716     *
717     *  Like store_string(), but advances the pointer afterwards. The most
718     *  obvious use is to place a number of strings (such as environment variable
719     *  strings) after one-another in emulated memory.
720     */
721    void add_environment_string(struct cpu *cpu, char *s, uint64_t *addr)
722    {
723            store_string(cpu, *addr, s);
724            (*addr) += strlen(s) + 1;
725    }
726    
727    
728    /*
729     *  add_environment_string_dual():
730     *
731     *  Add "dual" environment strings, one for the variable name and one for the
732     *  value, and update pointers afterwards.
733     */
734    void add_environment_string_dual(struct cpu *cpu,
735            uint64_t *ptrp, uint64_t *addrp, char *s1, char *s2)
736    {
737            uint64_t ptr = *ptrp, addr = *addrp;
738    
739            store_32bit_word(cpu, ptr, addr);
740            ptr += sizeof(uint32_t);
741            if (addr != 0) {
742                    store_string(cpu, addr, s1);
743                    addr += strlen(s1) + 1;
744            }
745            store_32bit_word(cpu, ptr, addr);
746            ptr += sizeof(uint32_t);
747            if (addr != 0) {
748                    store_string(cpu, addr, s2);
749                    addr += strlen(s2) + 1;
750            }
751    
752            *ptrp = ptr;
753            *addrp = addr;
754    }
755    
756    
757    /*
758     *  store_64bit_word():
759     *
760     *  Stores a 64-bit word in emulated RAM.  Byte order is taken into account.
761     *  Helper function.
762     */
763    int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
764    {
765            unsigned char data[8];
766            if ((addr >> 32) == 0)
767                    addr = (int64_t)(int32_t)addr;
768            data[0] = (data64 >> 56) & 255;
769            data[1] = (data64 >> 48) & 255;
770            data[2] = (data64 >> 40) & 255;
771            data[3] = (data64 >> 32) & 255;
772            data[4] = (data64 >> 24) & 255;
773            data[5] = (data64 >> 16) & 255;
774            data[6] = (data64 >> 8) & 255;
775            data[7] = (data64) & 255;
776            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
777                    int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
778                    tmp = data[1]; data[1] = data[6]; data[6] = tmp;
779                    tmp = data[2]; data[2] = data[5]; data[5] = tmp;
780                    tmp = data[3]; data[3] = data[4]; data[4] = tmp;
781            }
782            return cpu->memory_rw(cpu, cpu->mem,
783                addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
784    }
785    
786    
787    /*
788     *  store_32bit_word():
789     *
790     *  Stores a 32-bit word in emulated RAM.  Byte order is taken into account.
791     *  (This function takes a 64-bit word as argument, to suppress some
792     *  warnings, but only the lowest 32 bits are used.)
793     */
794    int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
795    {
796            unsigned char data[4];
797    
798            data[0] = (data32 >> 24) & 255;
799            data[1] = (data32 >> 16) & 255;
800            data[2] = (data32 >> 8) & 255;
801            data[3] = (data32) & 255;
802            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
803                    int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
804                    tmp = data[1]; data[1] = data[2]; data[2] = tmp;
805            }
806            return cpu->memory_rw(cpu, cpu->mem,
807                addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
808    }
809    
810    
811    /*
812     *  store_16bit_word():
813     *
814     *  Stores a 16-bit word in emulated RAM.  Byte order is taken into account.
815     *  (This function takes a 64-bit word as argument, to suppress some
816     *  warnings, but only the lowest 16 bits are used.)
817     */
818    int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16)
819    {
820            unsigned char data[2];
821    
822            data[0] = (data16 >> 8) & 255;
823            data[1] = (data16) & 255;
824            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
825                    int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
826            }
827            return cpu->memory_rw(cpu, cpu->mem,
828                addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
829    }
830    
831    
832    /*
833     *  store_buf():
834     *
835     *  memcpy()-like helper function, from host RAM to emulated RAM.
836     */
837    void store_buf(struct cpu *cpu, uint64_t addr, char *s, size_t len)
838    {
839            size_t psize = 1024;    /*  1024 256 64 16 4 1  */
840    
841            while (len != 0) {
842                    if ((addr & (psize-1)) == 0) {
843                            while (len >= psize) {
844                                    cpu->memory_rw(cpu, cpu->mem, addr,
845                                        (unsigned char *)s, psize, MEM_WRITE,
846                                        CACHE_DATA);
847                                    addr += psize;
848                                    s += psize;
849                                    len -= psize;
850                            }
851                    }
852                    psize >>= 2;
853            }
854    
855            while (len-- != 0)
856                    store_byte(cpu, addr++, *s++);
857    }
858    
859    
860    /*
861     *  store_pointer_and_advance():
862     *
863     *  Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the
864     *  target address. (Useful for e.g. ARCBIOS environment initialization.)
865     */
866    void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp,
867            uint64_t data, int flag64)
868    {
869            uint64_t addr = *addrp;
870            if (flag64) {
871                    store_64bit_word(cpu, addr, data);
872                    addr += 8;
873            } else {
874                    store_32bit_word(cpu, addr, data);
875                    addr += 4;
876            }
877            *addrp = addr;
878    }
879    
880    
881    /*
882     *  load_64bit_word():
883     *
884     *  Helper function. Emulated byte order is taken into account.
885     */
886    uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr)
887    {
888            unsigned char data[8];
889    
890            cpu->memory_rw(cpu, cpu->mem,
891                addr, data, sizeof(data), MEM_READ, CACHE_DATA);
892    
893            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
894                    int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
895                    tmp = data[1]; data[1] = data[6]; data[6] = tmp;
896                    tmp = data[2]; data[2] = data[5]; data[5] = tmp;
897                    tmp = data[3]; data[3] = data[4]; data[4] = tmp;
898            }
899    
900            return
901                ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) +
902                ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) +
903                ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) +
904                ((uint64_t)data[6] << 8) + (uint64_t)data[7];
905    }
906    
907    
908    /*
909     *  load_32bit_word():
910     *
911     *  Helper function. Emulated byte order is taken into account.
912     */
913    uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
914    {
915            unsigned char data[4];
916    
917            cpu->memory_rw(cpu, cpu->mem,
918                addr, data, sizeof(data), MEM_READ, CACHE_DATA);
919    
920            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
921                    int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
922                    tmp = data[1]; data[1] = data[2]; data[2] = tmp;
923            }
924    
925            return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
926    }
927    
928    
929    /*
930     *  load_16bit_word():
931     *
932     *  Helper function. Emulated byte order is taken into account.
933     */
934    uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
935    {
936            unsigned char data[2];
937    
938            cpu->memory_rw(cpu, cpu->mem,
939                addr, data, sizeof(data), MEM_READ, CACHE_DATA);
940    
941            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
942                    int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
943            }
944    
945            return (data[0] << 8) + data[1];
946    }
947    
948    
949    /*
950     *  store_64bit_word_in_host():
951     *
952     *  Stores a 64-bit word in the _host's_ RAM.  Emulated byte order is taken
953     *  into account.  This is useful when building structs in the host's RAM
954     *  which will later be copied into emulated RAM.
955     */
956    void store_64bit_word_in_host(struct cpu *cpu,
957            unsigned char *data, uint64_t data64)
958    {
959            data[0] = (data64 >> 56) & 255;
960            data[1] = (data64 >> 48) & 255;
961            data[2] = (data64 >> 40) & 255;
962            data[3] = (data64 >> 32) & 255;
963            data[4] = (data64 >> 24) & 255;
964            data[5] = (data64 >> 16) & 255;
965            data[6] = (data64 >> 8) & 255;
966            data[7] = (data64) & 255;
967            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
968                    int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
969                    tmp = data[1]; data[1] = data[6]; data[6] = tmp;
970                    tmp = data[2]; data[2] = data[5]; data[5] = tmp;
971                    tmp = data[3]; data[3] = data[4]; data[4] = tmp;
972            }
973    }
974    
975    
976    /*
977     *  store_32bit_word_in_host():
978     *
979     *  See comment for store_64bit_word_in_host().
980     *
981     *  (Note:  The data32 parameter is a uint64_t. This is done to suppress
982     *  some warnings.)
983     */
984    void store_32bit_word_in_host(struct cpu *cpu,
985            unsigned char *data, uint64_t data32)
986    {
987            data[0] = (data32 >> 24) & 255;
988            data[1] = (data32 >> 16) & 255;
989            data[2] = (data32 >> 8) & 255;
990            data[3] = (data32) & 255;
991            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
992                    int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
993                    tmp = data[1]; data[1] = data[2]; data[2] = tmp;
994            }
995    }
996    
997    
998    /*
999     *  store_16bit_word_in_host():
1000     *
1001     *  See comment for store_64bit_word_in_host().
1002     */
1003    void store_16bit_word_in_host(struct cpu *cpu,
1004            unsigned char *data, uint16_t data16)
1005    {
1006            data[0] = (data16 >> 8) & 255;
1007            data[1] = (data16) & 255;
1008            if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1009                    int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
1010            }
1011    }
1012    

Legend:
Removed from v.28  
changed lines
  Added in v.42

  ViewVC Help
Powered by ViewVC 1.1.26