memory.cc Source File

Back to the index.

memory.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2009 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * Functions for handling the memory of an emulated machine.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/mman.h>
36 
37 #include "cpu.h"
38 #include "machine.h"
39 #include "memory.h"
40 #include "misc.h"
41 
42 
43 extern int verbose;
44 extern int quiet_mode;
45 
46 
47 /*
48  * memory_readmax64():
49  *
50  * Read at most 64 bits of data from a buffer. Length is given by
51  * len, and the byte order by cpu->byte_order.
52  *
53  * This function should not be called with cpu == NULL.
54  */
55 uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
56 {
57  int i, byte_order = cpu->byte_order;
58  uint64_t x = 0;
59 
60  if (len & MEM_PCI_LITTLE_ENDIAN) {
61  len &= ~MEM_PCI_LITTLE_ENDIAN;
62  byte_order = EMUL_LITTLE_ENDIAN;
63  }
64 
65  /* Switch byte order for incoming data, if necessary: */
66  if (byte_order == EMUL_BIG_ENDIAN)
67  for (i=0; i<len; i++) {
68  x <<= 8;
69  x |= buf[i];
70  }
71  else
72  for (i=len-1; i>=0; i--) {
73  x <<= 8;
74  x |= buf[i];
75  }
76 
77  return x;
78 }
79 
80 
81 /*
82  * memory_writemax64():
83  *
84  * Write at most 64 bits of data to a buffer. Length is given by
85  * len, and the byte order by cpu->byte_order.
86  *
87  * This function should not be called with cpu == NULL.
88  */
89 void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len,
90  uint64_t data)
91 {
92  int i, byte_order = cpu->byte_order;
93 
94  if (len & MEM_PCI_LITTLE_ENDIAN) {
95  len &= ~MEM_PCI_LITTLE_ENDIAN;
96  byte_order = EMUL_LITTLE_ENDIAN;
97  }
98 
99  if (byte_order == EMUL_LITTLE_ENDIAN)
100  for (i=0; i<len; i++) {
101  buf[i] = data & 255;
102  data >>= 8;
103  }
104  else
105  for (i=0; i<len; i++) {
106  buf[len - 1 - i] = data & 255;
107  data >>= 8;
108  }
109 }
110 
111 
112 /*
113  * zeroed_alloc():
114  *
115  * Allocates a block of memory using mmap(), and if that fails, try
116  * malloc() + memset(). The returned memory block contains only zeroes.
117  */
118 void *zeroed_alloc(size_t s)
119 {
120  void *p = mmap(NULL, s, PROT_READ | PROT_WRITE,
121  MAP_ANON | MAP_PRIVATE, -1, 0);
122 
123  if (p == NULL) {
124 #if 1
125  fprintf(stderr, "zeroed_alloc(): mmap() failed. This should"
126  " not usually happen. If you can reproduce this, then"
127  " please contact me with details about your run-time"
128  " environment.\n");
129  exit(1);
130 #else
131  CHECK_ALLOCATION(p = malloc(s));
132  memset(p, 0, s);
133 #endif
134  }
135 
136  return p;
137 }
138 
139 
140 /*
141  * memory_new():
142  *
143  * This function creates a new memory object. An emulated machine needs one
144  * of these.
145  */
146 struct memory *memory_new(uint64_t physical_max, int arch)
147 {
148  struct memory *mem;
149  int bits_per_pagetable = BITS_PER_PAGETABLE;
150  int bits_per_memblock = BITS_PER_MEMBLOCK;
151  int entries_per_pagetable = 1 << BITS_PER_PAGETABLE;
152  int max_bits = MAX_BITS;
153  size_t s;
154 
155  CHECK_ALLOCATION(mem = (struct memory *) malloc(sizeof(struct memory)));
156  memset(mem, 0, sizeof(struct memory));
157 
158  /* Check bits_per_pagetable and bits_per_memblock for sanity: */
159  if (bits_per_pagetable + bits_per_memblock != max_bits) {
160  fprintf(stderr, "memory_new(): bits_per_pagetable and "
161  "bits_per_memblock mismatch\n");
162  exit(1);
163  }
164 
165  mem->physical_max = physical_max;
166  mem->dev_dyntrans_alignment = 4095;
167 
168  s = entries_per_pagetable * sizeof(void *);
169 
170  mem->pagetable = (unsigned char *) mmap(NULL, s,
171  PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
172  if (mem->pagetable == NULL) {
173  CHECK_ALLOCATION(mem->pagetable = malloc(s));
174  memset(mem->pagetable, 0, s);
175  }
176 
177  mem->mmap_dev_minaddr = 0xffffffffffffffffULL;
178  mem->mmap_dev_maxaddr = 0;
179 
180  return mem;
181 }
182 
183 
184 /*
185  * memory_points_to_string():
186  *
187  * Returns 1 if there's something string-like in emulated memory at address
188  * addr, otherwise 0.
189  */
190 int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,
191  int min_string_length)
192 {
193  int cur_length = 0;
194  unsigned char c;
195 
196  for (;;) {
197  c = '\0';
198  cpu->memory_rw(cpu, mem, addr+cur_length,
199  &c, sizeof(c), MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
200  if (c=='\n' || c=='\t' || c=='\r' || (c>=' ' && c<127)) {
201  cur_length ++;
202  if (cur_length >= min_string_length)
203  return 1;
204  } else {
205  if (cur_length >= min_string_length)
206  return 1;
207  else
208  return 0;
209  }
210  }
211 }
212 
213 
214 /*
215  * memory_conv_to_string():
216  *
217  * Convert emulated memory contents to a string, placing it in a buffer
218  * provided by the caller.
219  */
220 char *memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,
221  char *buf, int bufsize)
222 {
223  int len = 0;
224  int output_index = 0;
225  unsigned char c, p='\0';
226 
227  while (output_index < bufsize-1) {
228  c = '\0';
229  cpu->memory_rw(cpu, mem, addr+len, &c, sizeof(c), MEM_READ,
231  buf[output_index] = c;
232  if (c>=' ' && c<127) {
233  len ++;
234  output_index ++;
235  } else if (c=='\n' || c=='\r' || c=='\t') {
236  len ++;
237  buf[output_index] = '\\';
238  output_index ++;
239  switch (c) {
240  case '\n': p = 'n'; break;
241  case '\r': p = 'r'; break;
242  case '\t': p = 't'; break;
243  }
244  if (output_index < bufsize-1) {
245  buf[output_index] = p;
246  output_index ++;
247  }
248  } else {
249  buf[output_index] = '\0';
250  return buf;
251  }
252  }
253 
254  buf[bufsize-1] = '\0';
255  return buf;
256 }
257 
258 
259 /*
260  * memory_device_dyntrans_access():
261  *
262  * Get the lowest and highest dyntrans access since last time.
263  */
264 void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem,
265  void *extra, uint64_t *low, uint64_t *high)
266 {
267  size_t s;
268  int i, need_inval = 0;
269 
270  /* TODO: This is O(n), so it might be good to rewrite it some day.
271  For now, it will be enough, as long as this function is not
272  called too often. */
273 
274  for (i=0; i<mem->n_mmapped_devices; i++) {
275  if (mem->devices[i].extra == extra &&
276  mem->devices[i].flags & DM_DYNTRANS_WRITE_OK &&
277  mem->devices[i].dyntrans_data != NULL) {
278  if (mem->devices[i].dyntrans_write_low != (uint64_t) -1)
279  need_inval = 1;
280  if (low != NULL)
281  *low = mem->devices[i].dyntrans_write_low;
282  mem->devices[i].dyntrans_write_low = (uint64_t) -1;
283 
284  if (high != NULL)
285  *high = mem->devices[i].dyntrans_write_high;
286  mem->devices[i].dyntrans_write_high = 0;
287 
288  if (!need_inval)
289  return;
290 
291  /* Invalidate any pages of this device that might
292  be in the dyntrans load/store cache, by marking
293  the pages read-only. */
294  if (cpu->invalidate_translation_caches != NULL) {
295  for (s = *low; s <= *high;
296  s += cpu->machine->arch_pagesize)
298  (cpu, mem->devices[i].baseaddr + s,
300  | INVALIDATE_PADDR);
301  }
302 
303  return;
304  }
305  }
306 }
307 
308 
309 /*
310  * memory_device_update_data():
311  *
312  * Update a device' dyntrans data pointer.
313  *
314  * SUPER-IMPORTANT NOTE: Anyone who changes a dyntrans data pointer while
315  * things are running also needs to invalidate all CPUs' address translation
316  * caches! Otherwise, these may contain old pointers to the old data.
317  */
318 void memory_device_update_data(struct memory *mem, void *extra,
319  unsigned char *data)
320 {
321  int i;
322 
323  for (i=0; i<mem->n_mmapped_devices; i++) {
324  if (mem->devices[i].extra != extra)
325  continue;
326 
327  mem->devices[i].dyntrans_data = data;
328  mem->devices[i].dyntrans_write_low = (uint64_t)-1;
329  mem->devices[i].dyntrans_write_high = 0;
330  }
331 }
332 
333 
334 /*
335  * memory_device_register():
336  *
337  * Register a memory mapped device.
338  */
339 void memory_device_register(struct memory *mem, const char *device_name,
340  uint64_t baseaddr, uint64_t len,
341  int (*f)(struct cpu *,struct memory *,uint64_t,unsigned char *,
342  size_t,int,void *),
343  void *extra, int flags, unsigned char *dyntrans_data)
344 {
345  int i, newi = 0;
346 
347  /*
348  * Figure out at which index to insert this device, and simultaneously
349  * check for collisions:
350  */
351  newi = -1;
352  for (i=0; i<mem->n_mmapped_devices; i++) {
353  if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr)
354  newi = i;
355  if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr &&
356  baseaddr >= mem->devices[i-1].endaddr)
357  newi = i;
358  if (i == mem->n_mmapped_devices - 1 &&
359  baseaddr >= mem->devices[i].endaddr)
360  newi = i + 1;
361 
362  /* If this is not colliding with device i, then continue: */
363  if (baseaddr + len <= mem->devices[i].baseaddr)
364  continue;
365  if (baseaddr >= mem->devices[i].endaddr)
366  continue;
367 
368  fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",
369  device_name, i, mem->devices[i].name);
370  exit(1);
371  }
372  if (mem->n_mmapped_devices == 0)
373  newi = 0;
374  if (newi == -1) {
375  fatal("INTERNAL ERROR\n");
376  exit(1);
377  }
378 
379  if (verbose >= 2) {
380  /* (40 bits of physical address is displayed) */
381  debug("device at 0x%010" PRIx64": %s", (uint64_t) baseaddr,
382  device_name);
383 
384  if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
385  && (baseaddr & mem->dev_dyntrans_alignment) != 0) {
386  fatal("\nWARNING: Device dyntrans access, but unaligned"
387  " baseaddr 0x%" PRIx64".\n", (uint64_t) baseaddr);
388  }
389 
390  if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
391  debug(" (dyntrans %s)",
392  (flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R");
393  }
394  debug("\n");
395  }
396 
397  for (i=0; i<mem->n_mmapped_devices; i++) {
398  if (dyntrans_data == mem->devices[i].dyntrans_data &&
400  && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
401  fatal("ERROR: the data pointer used for dyntrans "
402  "accesses must only be used once!\n");
403  fatal("(%p cannot be used by '%s'; already in use by '"
404  "%s')\n", dyntrans_data, device_name,
405  mem->devices[i].name);
406  exit(1);
407  }
408  }
409 
410  mem->n_mmapped_devices++;
411 
412  CHECK_ALLOCATION(mem->devices = (struct memory_device *) realloc(mem->devices,
413  sizeof(struct memory_device) * mem->n_mmapped_devices));
414 
415  /* Make space for the new entry: */
416  if (newi + 1 != mem->n_mmapped_devices)
417  memmove(&mem->devices[newi+1], &mem->devices[newi],
418  sizeof(struct memory_device)
419  * (mem->n_mmapped_devices - newi - 1));
420 
421  CHECK_ALLOCATION(mem->devices[newi].name = strdup(device_name));
422  mem->devices[newi].baseaddr = baseaddr;
423  mem->devices[newi].endaddr = baseaddr + len;
424  mem->devices[newi].length = len;
425  mem->devices[newi].flags = flags;
426  mem->devices[newi].dyntrans_data = dyntrans_data;
427 
428  if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
429  && !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) {
430  fatal("\nERROR: Device dyntrans access, but dyntrans_data"
431  " = NULL!\n");
432  exit(1);
433  }
434 
435  if ((size_t)dyntrans_data & (sizeof(void *) - 1)) {
436  fprintf(stderr, "memory_device_register():"
437  " dyntrans_data not aligned correctly (%p)\n",
438  dyntrans_data);
439  abort();
440  }
441 
442  mem->devices[newi].dyntrans_write_low = (uint64_t)-1;
443  mem->devices[newi].dyntrans_write_high = 0;
444  mem->devices[newi].f = f;
445  mem->devices[newi].extra = extra;
446 
447  if (baseaddr < mem->mmap_dev_minaddr)
448  mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;
449  if (baseaddr + len > mem->mmap_dev_maxaddr)
450  mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |
451  mem->dev_dyntrans_alignment) + 1;
452 
453  if (newi < mem->last_accessed_device)
454  mem->last_accessed_device ++;
455 }
456 
457 
458 /*
459  * memory_device_remove():
460  *
461  * Unregister a memory mapped device from a memory object.
462  */
463 void memory_device_remove(struct memory *mem, int i)
464 {
465  if (i < 0 || i >= mem->n_mmapped_devices) {
466  fatal("memory_device_remove(): invalid device number %i\n", i);
467  exit(1);
468  }
469 
470  mem->n_mmapped_devices --;
471 
472  if (i == mem->n_mmapped_devices)
473  return;
474 
475  memmove(&mem->devices[i], &mem->devices[i+1],
476  sizeof(struct memory_device) * (mem->n_mmapped_devices - i));
477 
478  if (i <= mem->last_accessed_device)
479  mem->last_accessed_device --;
480  if (mem->last_accessed_device < 0)
481  mem->last_accessed_device = 0;
482 }
483 
484 
485 /*
486  * memory_paddr_to_hostaddr():
487  *
488  * Translate a physical address into a host address. The usual way to call
489  * this function is to make sure that paddr is page aligned, which will result
490  * in the host _page_ corresponding to that address.
491  *
492  * Return value is a pointer to the address in the host, or NULL on failure.
493  * On reads, a NULL return value should be interpreted as reading all zeroes.
494  */
495 unsigned char *memory_paddr_to_hostaddr(struct memory *mem,
496  uint64_t paddr, int writeflag)
497 {
498  void **table;
499  int entry;
500  const int mask = (1 << BITS_PER_PAGETABLE) - 1;
501  const int shrcount = MAX_BITS - BITS_PER_PAGETABLE;
502  unsigned char *hostptr;
503 
504  table = (void **) mem->pagetable;
505  entry = (paddr >> shrcount) & mask;
506 
507  /* printf("memory_paddr_to_hostaddr(): p=%16" PRIx64
508  " w=%i => entry=0x%x\n", (uint64_t) paddr, writeflag, entry); */
509 
510  if (table[entry] == NULL) {
511  size_t alloclen;
512 
513  /*
514  * Special case: reading from a nonexistant memblock
515  * returns all zeroes, and doesn't allocate anything.
516  * (If any intermediate pagetable is nonexistant, then
517  * the same thing happens):
518  */
519  if (writeflag == MEM_READ)
520  return NULL;
521 
522  /* Allocate a memblock: */
523  alloclen = 1 << BITS_PER_MEMBLOCK;
524 
525  /* printf(" allocating for entry %i, len=%i\n",
526  entry, alloclen); */
527 
528  /* Anonymous mmap() should return zero-filled memory,
529  try malloc + memset if mmap failed. */
530  table[entry] = (void *) mmap(NULL, alloclen,
531  PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
532  if (table[entry] == NULL) {
533  CHECK_ALLOCATION(table[entry] = malloc(alloclen));
534  memset(table[entry], 0, alloclen);
535  }
536  }
537 
538  hostptr = (unsigned char *) table[entry];
539 
540  if (hostptr != NULL)
541  hostptr += (paddr & ((1 << BITS_PER_MEMBLOCK) - 1));
542 
543  return hostptr;
544 }
545 
546 
547 #define UPDATE_CHECKSUM(value) { \
548  internal_state -= 0x118c7771c0c0a77fULL; \
549  internal_state = ((internal_state + (value)) << 7) ^ \
550  (checksum >> 11) ^ ((checksum - (value)) << 3) ^ \
551  (internal_state - checksum) ^ ((value) - internal_state); \
552  checksum ^= internal_state; \
553  }
554 
555 
556 /*
557  * memory_checksum():
558  *
559  * Calculate a 64-bit checksum of everything in a struct memory. This is
560  * useful for tracking down bugs; an old (presumably working) version of
561  * the emulator can be compared to a newer (buggy) version.
562  */
563 uint64_t memory_checksum(struct memory *mem)
564 {
565  uint64_t internal_state = 0x80624185376feff2ULL;
566  uint64_t checksum = 0xcb9a87d5c010072cULL;
567  const size_t n_entries = (1 << BITS_PER_PAGETABLE) - 1;
568  const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t);
569  size_t entry, i;
570 
571  for (entry=0; entry<=n_entries; entry++) {
572  uint64_t **table = (uint64_t **) mem->pagetable;
573  uint64_t *memblock = table[entry];
574 
575  if (memblock == NULL) {
576  UPDATE_CHECKSUM(0x1198ab7c8174a76fULL);
577  continue;
578  }
579 
580  for (i=0; i<len; i++)
581  UPDATE_CHECKSUM(memblock[i]);
582  }
583 
584  return checksum;
585 }
586 
587 
588 /*
589  * memory_warn_about_unimplemented_addr():
590  *
591  * Called from memory_rw whenever memory outside of the physical address space
592  * is accessed (and quiet_mode isn't set).
593  */
595  int writeflag, uint64_t paddr, uint8_t *data, size_t len)
596 {
597  uint64_t offset, old_pc = cpu->pc;
598  char *symbol;
599 
600  /*
601  * This allows guest OS kernels to probe memory a few KBs past the
602  * end of memory, without giving too many warnings.
603  */
604  if (paddr < mem->physical_max + 0x40000)
605  return;
606 
608  return;
609 
610  fatal("[ memory_rw(): %s ", writeflag? "write":"read");
611 
612  if (writeflag) {
613  unsigned int i;
614  debug("data={", writeflag);
615  if (len > 16) {
616  int start2 = len-16;
617  for (i=0; i<16; i++)
618  debug("%s%02x", i?",":"", data[i]);
619  debug(" .. ");
620  if (start2 < 16)
621  start2 = 16;
622  for (i=start2; i<len; i++)
623  debug("%s%02x", i?",":"", data[i]);
624  } else
625  for (i=0; i<len; i++)
626  debug("%s%02x", i?",":"", data[i]);
627  debug("} ");
628  }
629 
630  fatal("paddr=0x%" PRIx64" >= physical_max; pc=", paddr);
631  if (cpu->is_32bit)
632  fatal("0x%08" PRIx32, (uint32_t) old_pc);
633  else
634  fatal("0x%016" PRIx64, (uint64_t) old_pc);
636  old_pc, &offset);
637  fatal(" <%s> ]\n", symbol? symbol : " no symbol ");
638 
640  /* TODO: Halt in a nicer way. Not possible with the
641  current dyntrans system... */
642  exit(1);
643  }
644 }
645 
646 
647 /*
648  * dump_mem_string():
649  *
650  * Dump the contents of emulated RAM as readable text. Bytes that aren't
651  * readable are dumped in [xx] notation, where xx is in hexadecimal.
652  * Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating
653  * zero byte is found.
654  */
655 #define DUMP_MEM_STRING_MAX 45
656 void dump_mem_string(struct cpu *cpu, uint64_t addr)
657 {
658  int i;
659  for (i=0; i<DUMP_MEM_STRING_MAX; i++) {
660  unsigned char ch = '\0';
661 
662  cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch),
664  if (ch == '\0')
665  return;
666  if (ch >= ' ' && ch < 126)
667  debug("%c", ch);
668  else
669  debug("[%02x]", ch);
670  }
671 }
672 
673 
674 /*
675  * store_byte():
676  *
677  * Stores a byte in emulated ram. (Helper function.)
678  */
679 void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data)
680 {
681  if ((addr >> 32) == 0)
682  addr = (int64_t)(int32_t)addr;
683  cpu->memory_rw(cpu, cpu->mem,
684  addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA);
685 }
686 
687 
688 /*
689  * store_string():
690  *
691  * Stores chars into emulated RAM until a zero byte (string terminating
692  * character) is found. The zero byte is also copied.
693  * (strcpy()-like helper function, host-RAM-to-emulated-RAM.)
694  */
695 void store_string(struct cpu *cpu, uint64_t addr, const char *s)
696 {
697  do {
698  store_byte(cpu, addr++, *s);
699  } while (*s++);
700 }
701 
702 
703 /*
704  * add_environment_string():
705  *
706  * Like store_string(), but advances the pointer afterwards. The most
707  * obvious use is to place a number of strings (such as environment variable
708  * strings) after one-another in emulated memory.
709  */
710 void add_environment_string(struct cpu *cpu, const char *s, uint64_t *addr)
711 {
712  store_string(cpu, *addr, s);
713  (*addr) += strlen(s) + 1;
714 }
715 
716 
717 /*
718  * add_environment_string_dual():
719  *
720  * Add "dual" environment strings, one for the variable name and one for the
721  * value, and update pointers afterwards.
722  */
724  uint64_t *ptrp, uint64_t *addrp, const char *s1, const char *s2)
725 {
726  uint64_t ptr = *ptrp, addr = *addrp;
727 
728  store_32bit_word(cpu, ptr, addr);
729  ptr += sizeof(uint32_t);
730  if (addr != 0) {
731  store_string(cpu, addr, s1);
732  addr += strlen(s1) + 1;
733  }
734  store_32bit_word(cpu, ptr, addr);
735  ptr += sizeof(uint32_t);
736  if (addr != 0) {
737  store_string(cpu, addr, s2);
738  addr += strlen(s2) + 1;
739  }
740 
741  *ptrp = ptr;
742  *addrp = addr;
743 }
744 
745 
746 /*
747  * store_64bit_word():
748  *
749  * Stores a 64-bit word in emulated RAM. Byte order is taken into account.
750  * Helper function.
751  */
752 int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
753 {
754  unsigned char data[8];
755  if ((addr >> 32) == 0)
756  addr = (int64_t)(int32_t)addr;
757  data[0] = (data64 >> 56) & 255;
758  data[1] = (data64 >> 48) & 255;
759  data[2] = (data64 >> 40) & 255;
760  data[3] = (data64 >> 32) & 255;
761  data[4] = (data64 >> 24) & 255;
762  data[5] = (data64 >> 16) & 255;
763  data[6] = (data64 >> 8) & 255;
764  data[7] = (data64) & 255;
766  int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
767  tmp = data[1]; data[1] = data[6]; data[6] = tmp;
768  tmp = data[2]; data[2] = data[5]; data[5] = tmp;
769  tmp = data[3]; data[3] = data[4]; data[4] = tmp;
770  }
771  return cpu->memory_rw(cpu, cpu->mem,
772  addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
773 }
774 
775 
776 /*
777  * store_32bit_word():
778  *
779  * Stores a 32-bit word in emulated RAM. Byte order is taken into account.
780  * (This function takes a 64-bit word as argument, to suppress some
781  * warnings, but only the lowest 32 bits are used.)
782  */
783 int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
784 {
785  unsigned char data[4];
786 
787  data[0] = (data32 >> 24) & 255;
788  data[1] = (data32 >> 16) & 255;
789  data[2] = (data32 >> 8) & 255;
790  data[3] = (data32) & 255;
792  int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
793  tmp = data[1]; data[1] = data[2]; data[2] = tmp;
794  }
795  return cpu->memory_rw(cpu, cpu->mem,
796  addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
797 }
798 
799 
800 /*
801  * store_16bit_word():
802  *
803  * Stores a 16-bit word in emulated RAM. Byte order is taken into account.
804  * (This function takes a 64-bit word as argument, to suppress some
805  * warnings, but only the lowest 16 bits are used.)
806  */
807 int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16)
808 {
809  unsigned char data[2];
810 
811  data[0] = (data16 >> 8) & 255;
812  data[1] = (data16) & 255;
814  int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
815  }
816  return cpu->memory_rw(cpu, cpu->mem,
817  addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
818 }
819 
820 
821 /*
822  * store_buf():
823  *
824  * memcpy()-like helper function, from host RAM to emulated RAM.
825  */
826 void store_buf(struct cpu *cpu, uint64_t addr, const char *s, size_t len)
827 {
828  size_t psize = 1024; /* 1024 256 64 16 4 1 */
829 
830  while (len != 0) {
831  if ((addr & (psize-1)) == 0) {
832  while (len >= psize) {
833  cpu->memory_rw(cpu, cpu->mem, addr,
834  (unsigned char *)s, psize, MEM_WRITE,
835  CACHE_DATA);
836  addr += psize;
837  s += psize;
838  len -= psize;
839  }
840  }
841  psize >>= 2;
842  }
843 
844  while (len-- != 0)
845  store_byte(cpu, addr++, *s++);
846 }
847 
848 
849 /*
850  * store_pointer_and_advance():
851  *
852  * Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the
853  * target address. (Useful for e.g. ARCBIOS environment initialization.)
854  */
855 void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp,
856  uint64_t data, int flag64)
857 {
858  uint64_t addr = *addrp;
859  if (flag64) {
861  addr += 8;
862  } else {
864  addr += 4;
865  }
866  *addrp = addr;
867 }
868 
869 
870 /*
871  * load_64bit_word():
872  *
873  * Helper function. Emulated byte order is taken into account.
874  */
875 uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr)
876 {
877  unsigned char data[8];
878 
879  cpu->memory_rw(cpu, cpu->mem,
880  addr, data, sizeof(data), MEM_READ, CACHE_DATA);
881 
883  int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
884  tmp = data[1]; data[1] = data[6]; data[6] = tmp;
885  tmp = data[2]; data[2] = data[5]; data[5] = tmp;
886  tmp = data[3]; data[3] = data[4]; data[4] = tmp;
887  }
888 
889  return
890  ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) +
891  ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) +
892  ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) +
893  ((uint64_t)data[6] << 8) + (uint64_t)data[7];
894 }
895 
896 
897 /*
898  * load_32bit_word():
899  *
900  * Helper function. Emulated byte order is taken into account.
901  */
902 uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
903 {
904  unsigned char data[4];
905 
906  cpu->memory_rw(cpu, cpu->mem,
907  addr, data, sizeof(data), MEM_READ, CACHE_DATA);
908 
910  int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
911  tmp = data[1]; data[1] = data[2]; data[2] = tmp;
912  }
913 
914  return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
915 }
916 
917 
918 /*
919  * load_16bit_word():
920  *
921  * Helper function. Emulated byte order is taken into account.
922  */
923 uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
924 {
925  unsigned char data[2];
926 
927  cpu->memory_rw(cpu, cpu->mem,
928  addr, data, sizeof(data), MEM_READ, CACHE_DATA);
929 
931  int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
932  }
933 
934  return (data[0] << 8) + data[1];
935 }
936 
937 
938 /*
939  * store_64bit_word_in_host():
940  *
941  * Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken
942  * into account. This is useful when building structs in the host's RAM
943  * which will later be copied into emulated RAM.
944  */
946  unsigned char *data, uint64_t data64)
947 {
948  data[0] = (data64 >> 56) & 255;
949  data[1] = (data64 >> 48) & 255;
950  data[2] = (data64 >> 40) & 255;
951  data[3] = (data64 >> 32) & 255;
952  data[4] = (data64 >> 24) & 255;
953  data[5] = (data64 >> 16) & 255;
954  data[6] = (data64 >> 8) & 255;
955  data[7] = (data64) & 255;
957  int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
958  tmp = data[1]; data[1] = data[6]; data[6] = tmp;
959  tmp = data[2]; data[2] = data[5]; data[5] = tmp;
960  tmp = data[3]; data[3] = data[4]; data[4] = tmp;
961  }
962 }
963 
964 
965 /*
966  * store_32bit_word_in_host():
967  *
968  * See comment for store_64bit_word_in_host().
969  *
970  * (Note: The data32 parameter is a uint64_t. This is done to suppress
971  * some warnings.)
972  */
974  unsigned char *data, uint64_t data32)
975 {
976  data[0] = (data32 >> 24) & 255;
977  data[1] = (data32 >> 16) & 255;
978  data[2] = (data32 >> 8) & 255;
979  data[3] = (data32) & 255;
981  int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
982  tmp = data[1]; data[1] = data[2]; data[2] = tmp;
983  }
984 }
985 
986 
987 /*
988  * store_16bit_word_in_host():
989  *
990  * See comment for store_64bit_word_in_host().
991  */
993  unsigned char *data, uint16_t data16)
994 {
995  data[0] = (data16 >> 8) & 255;
996  data[1] = (data16) & 255;
998  int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
999  }
1000 }
1001 
memory::n_mmapped_devices
int n_mmapped_devices
Definition: memory.h:81
DM_EMULATED_RAM
#define DM_EMULATED_RAM
Definition: memory.h:134
data
u_short data
Definition: siireg.h:79
store_16bit_word
int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16)
Definition: memory.cc:807
memory_device::name
const char * name
Definition: memory.h:54
machine::arch_pagesize
int arch_pagesize
Definition: machine.h:151
f
void f(int s, int func, int only_name)
Definition: generate_arm_r.c:45
memory_device::dyntrans_write_low
uint64_t dyntrans_write_low
Definition: memory.h:62
store_64bit_word
int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
Definition: memory.cc:752
load_16bit_word
uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
Definition: memory.cc:923
machine::symbol_context
struct symbol_context symbol_context
Definition: machine.h:144
memory_device::extra
void * extra
Definition: memory.h:58
memory
Definition: memory.h:75
debug
#define debug
Definition: dev_adb.cc:57
store_pointer_and_advance
void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp, uint64_t data, int flag64)
Definition: memory.cc:855
memory_readmax64
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
store_byte
void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data)
Definition: memory.cc:679
dump_mem_string
void dump_mem_string(struct cpu *cpu, uint64_t addr)
Definition: memory.cc:656
get_symbol_name
char * get_symbol_name(struct symbol_context *, uint64_t addr, uint64_t *offset)
Definition: symbol.cc:188
load_32bit_word
uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
Definition: memory.cc:902
add_environment_string
void add_environment_string(struct cpu *cpu, const char *s, uint64_t *addr)
Definition: memory.cc:710
memory_paddr_to_hostaddr
unsigned char * memory_paddr_to_hostaddr(struct memory *mem, uint64_t paddr, int writeflag)
Definition: memory.cc:495
if
addr & if(addr >=0x24 &&page !=NULL)
Definition: tmp_arm_multi.cc:56
memory_device::f
int(* f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *)
Definition: memory.h:56
memory::pagetable
void * pagetable
Definition: memory.h:77
MEM_READ
#define MEM_READ
Definition: memory.h:116
cpu::byte_order
uint8_t byte_order
Definition: cpu.h:347
memory_device_remove
void memory_device_remove(struct memory *mem, int i)
Definition: memory.cc:463
memory_checksum
uint64_t memory_checksum(struct memory *mem)
Definition: memory.cc:563
EMUL_BIG_ENDIAN
#define EMUL_BIG_ENDIAN
Definition: misc.h:165
addr
uint32_t addr
Definition: tmp_arm_multi.cc:52
memory_device::length
uint64_t length
Definition: memory.h:51
memory_device::baseaddr
uint64_t baseaddr
Definition: memory.h:49
add_environment_string_dual
void add_environment_string_dual(struct cpu *cpu, uint64_t *ptrp, uint64_t *addrp, const char *s1, const char *s2)
Definition: memory.cc:723
memory_device_dyntrans_access
void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem, void *extra, uint64_t *low, uint64_t *high)
Definition: memory.cc:264
memory_device::endaddr
uint64_t endaddr
Definition: memory.h:50
MEM_WRITE
#define MEM_WRITE
Definition: memory.h:117
memory::devices
struct memory_device * devices
Definition: memory.h:88
DM_DYNTRANS_WRITE_OK
#define DM_DYNTRANS_WRITE_OK
Definition: memory.h:132
strlen
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2333
fatal
void fatal(const char *fmt,...)
Definition: main.cc:152
memory::mmap_dev_maxaddr
uint64_t mmap_dev_maxaddr
Definition: memory.h:86
misc.h
CACHE_NONE
#define CACHE_NONE
Definition: memory.h:123
machine::halt_on_nonexistant_memaccess
int halt_on_nonexistant_memaccess
Definition: machine.h:161
machine.h
memory::mmap_dev_minaddr
uint64_t mmap_dev_minaddr
Definition: memory.h:85
memory_writemax64
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
UPDATE_CHECKSUM
#define UPDATE_CHECKSUM(value)
Definition: memory.cc:547
memory_device_update_data
void memory_device_update_data(struct memory *mem, void *extra, unsigned char *data)
Definition: memory.cc:318
CACHE_DATA
#define CACHE_DATA
Definition: memory.h:121
MAX_BITS
#define MAX_BITS
Definition: memory.h:93
cpu::invalidate_translation_caches
void(* invalidate_translation_caches)(struct cpu *, uint64_t paddr, int flags)
Definition: cpu.h:374
BITS_PER_MEMBLOCK
#define BITS_PER_MEMBLOCK
Definition: memory.h:92
verbose
int verbose
Definition: main.cc:77
cpu::is_32bit
uint8_t is_32bit
Definition: cpu.h:350
memory_device::dyntrans_data
unsigned char * dyntrans_data
Definition: memory.h:60
store_string
void store_string(struct cpu *cpu, uint64_t addr, const char *s)
Definition: memory.cc:695
cpu.h
memory_new
struct memory * memory_new(uint64_t physical_max, int arch)
Definition: memory.cc:146
store_buf
void store_buf(struct cpu *cpu, uint64_t addr, const char *s, size_t len)
Definition: memory.cc:826
memory_device::dyntrans_write_high
uint64_t dyntrans_write_high
Definition: memory.h:63
cpu::mem
struct memory * mem
Definition: cpu.h:362
BITS_PER_PAGETABLE
#define BITS_PER_PAGETABLE
Definition: memory.h:91
EMUL_LITTLE_ENDIAN
#define EMUL_LITTLE_ENDIAN
Definition: misc.h:164
memory_device
Definition: memory.h:48
cpu::machine
struct machine * machine
Definition: cpu.h:328
store_16bit_word_in_host
void store_16bit_word_in_host(struct cpu *cpu, unsigned char *data, uint16_t data16)
Definition: memory.cc:992
store_32bit_word
int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
Definition: memory.cc:783
memory::last_accessed_device
int last_accessed_device
Definition: memory.h:82
memory_conv_to_string
char * memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, char *buf, int bufsize)
Definition: memory.cc:220
NO_EXCEPTIONS
#define NO_EXCEPTIONS
Definition: memory.h:125
symbol
Definition: symbol.h:37
load_64bit_word
uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr)
Definition: memory.cc:875
zeroed_alloc
void * zeroed_alloc(size_t s)
Definition: memory.cc:118
store_32bit_word_in_host
void store_32bit_word_in_host(struct cpu *cpu, unsigned char *data, uint64_t data32)
Definition: memory.cc:973
DUMP_MEM_STRING_MAX
#define DUMP_MEM_STRING_MAX
Definition: memory.cc:655
memory::physical_max
uint64_t physical_max
Definition: memory.h:76
memory_warn_about_unimplemented_addr
void memory_warn_about_unimplemented_addr(struct cpu *cpu, struct memory *mem, int writeflag, uint64_t paddr, uint8_t *data, size_t len)
Definition: memory.cc:594
MEM_PCI_LITTLE_ENDIAN
#define MEM_PCI_LITTLE_ENDIAN
Definition: memory.h:97
memory_points_to_string
int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, int min_string_length)
Definition: memory.cc:190
memory::dev_dyntrans_alignment
int dev_dyntrans_alignment
Definition: memory.h:79
INVALIDATE_PADDR
#define INVALIDATE_PADDR
Definition: cpu.h:479
memory_device_register
void memory_device_register(struct memory *mem, const char *device_name, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
store_64bit_word_in_host
void store_64bit_word_in_host(struct cpu *cpu, unsigned char *data, uint64_t data64)
Definition: memory.cc:945
cpu
Definition: cpu.h:326
DM_DYNTRANS_OK
#define DM_DYNTRANS_OK
Definition: memory.h:131
cpu::memory_rw
int(* memory_rw)(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags)
Definition: cpu.h:365
quiet_mode
int quiet_mode
Definition: main.cc:78
cpu::pc
uint64_t pc
Definition: cpu.h:383
memory.h
JUST_MARK_AS_NON_WRITABLE
#define JUST_MARK_AS_NON_WRITABLE
Definition: cpu.h:477
CHECK_ALLOCATION
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
memory_device::flags
int flags
Definition: memory.h:52

Generated on Tue Mar 24 2020 14:04:48 for GXemul by doxygen 1.8.17