25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory.c,v 1.187 2006/01/14 12:51:59 debug Exp $ |
* $Id: memory.c,v 1.192 2006/07/14 16:33:27 debug Exp $ |
29 |
* |
* |
30 |
* Functions for handling the memory of an emulated machine. |
* Functions for handling the memory of an emulated machine. |
31 |
*/ |
*/ |
270 |
void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem, |
void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem, |
271 |
void *extra, uint64_t *low, uint64_t *high) |
void *extra, uint64_t *low, uint64_t *high) |
272 |
{ |
{ |
|
int i, j; |
|
273 |
size_t s; |
size_t s; |
274 |
int need_inval = 0; |
int i, need_inval = 0; |
275 |
|
|
276 |
/* 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. |
277 |
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 |
306 |
| INVALIDATE_PADDR); |
| INVALIDATE_PADDR); |
307 |
} |
} |
308 |
|
|
|
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; |
|
|
} |
|
|
} |
|
309 |
return; |
return; |
310 |
} |
} |
311 |
} |
} |
313 |
|
|
314 |
|
|
315 |
/* |
/* |
316 |
|
* memory_device_update_data(): |
317 |
|
* |
318 |
|
* Update a device' dyntrans data pointer. |
319 |
|
* |
320 |
|
* SUPER-IMPORTANT NOTE: Anyone who changes a dyntrans data pointer while |
321 |
|
* things are running also needs to invalidate all CPUs' address translation |
322 |
|
* caches! Otherwise, these may contain old pointers to the old data. |
323 |
|
*/ |
324 |
|
void memory_device_update_data(struct memory *mem, void *extra, |
325 |
|
unsigned char *data) |
326 |
|
{ |
327 |
|
int i; |
328 |
|
|
329 |
|
for (i=0; i<mem->n_mmapped_devices; i++) { |
330 |
|
if (mem->dev_extra[i] != extra) |
331 |
|
continue; |
332 |
|
|
333 |
|
mem->dev_dyntrans_data[i] = data; |
334 |
|
mem->dev_dyntrans_write_low[i] = (uint64_t)-1; |
335 |
|
mem->dev_dyntrans_write_high[i] = 0; |
336 |
|
} |
337 |
|
} |
338 |
|
|
339 |
|
|
340 |
|
/* |
341 |
* memory_device_register(): |
* memory_device_register(): |
342 |
* |
* |
343 |
* Register a (memory mapped) device by adding it to the dev_* fields of a |
* Register a (memory mapped) device by adding it to the dev_* fields of a |
391 |
|
|
392 |
if (verbose >= 2) { |
if (verbose >= 2) { |
393 |
/* (40 bits of physical address is displayed) */ |
/* (40 bits of physical address is displayed) */ |
394 |
debug("device at 0x%010llx: %s", (long long)baseaddr, |
debug("device at 0x%010"PRIx64": %s", (uint64_t) baseaddr, |
395 |
device_name); |
device_name); |
396 |
|
|
397 |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) |
398 |
&& (baseaddr & mem->dev_dyntrans_alignment) != 0) { |
&& (baseaddr & mem->dev_dyntrans_alignment) != 0) { |
399 |
fatal("\nWARNING: Device dyntrans access, but unaligned" |
fatal("\nWARNING: Device dyntrans access, but unaligned" |
400 |
" baseaddr 0x%llx.\n", (long long)baseaddr); |
" baseaddr 0x%"PRIx64".\n", (uint64_t) baseaddr); |
401 |
} |
} |
402 |
|
|
403 |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) { |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) { |
543 |
/* |
/* |
544 |
* memory_paddr_to_hostaddr(): |
* memory_paddr_to_hostaddr(): |
545 |
* |
* |
546 |
* Translate a physical address into a host address. |
* Translate a physical address into a host address. The usual way to call |
547 |
|
* this function is to make sure that paddr is page aligned, which will result |
548 |
|
* in the host _page_ corresponding to that address. |
549 |
* |
* |
550 |
* 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. |
551 |
* 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. |
552 |
*/ |
*/ |
553 |
unsigned char *memory_paddr_to_hostaddr(struct memory *mem, |
unsigned char *memory_paddr_to_hostaddr(struct memory *mem, |
557 |
int entry; |
int entry; |
558 |
const int mask = (1 << BITS_PER_PAGETABLE) - 1; |
const int mask = (1 << BITS_PER_PAGETABLE) - 1; |
559 |
const int shrcount = MAX_BITS - BITS_PER_PAGETABLE; |
const int shrcount = MAX_BITS - BITS_PER_PAGETABLE; |
560 |
|
unsigned char *hostptr; |
561 |
|
|
562 |
table = mem->pagetable; |
table = mem->pagetable; |
563 |
entry = (paddr >> shrcount) & mask; |
entry = (paddr >> shrcount) & mask; |
564 |
|
|
565 |
/* printf("memory_paddr_to_hostaddr(): p=%16llx w=%i => entry=0x%x\n", |
/* printf("memory_paddr_to_hostaddr(): p=%16"PRIx64 |
566 |
(long long)paddr, writeflag, entry); */ |
" w=%i => entry=0x%x\n", (uint64_t) paddr, writeflag, entry); */ |
567 |
|
|
568 |
if (table[entry] == NULL) { |
if (table[entry] == NULL) { |
569 |
size_t alloclen; |
size_t alloclen; |
597 |
} |
} |
598 |
} |
} |
599 |
|
|
600 |
return (unsigned char *) table[entry]; |
hostptr = (unsigned char *) table[entry]; |
601 |
|
|
602 |
|
if (hostptr != NULL) |
603 |
|
hostptr += (paddr & ((1 << BITS_PER_MEMBLOCK) - 1)); |
604 |
|
|
605 |
|
return hostptr; |
606 |
|
} |
607 |
|
|
608 |
|
|
609 |
|
#define UPDATE_CHECKSUM(value) { \ |
610 |
|
internal_state -= 0x118c7771c0c0a77fULL; \ |
611 |
|
internal_state = ((internal_state + (value)) << 7) ^ \ |
612 |
|
(checksum >> 11) ^ ((checksum - (value)) << 3) ^ \ |
613 |
|
(internal_state - checksum) ^ ((value) - internal_state); \ |
614 |
|
checksum ^= internal_state; \ |
615 |
|
} |
616 |
|
|
617 |
|
|
618 |
|
/* |
619 |
|
* memory_checksum(): |
620 |
|
* |
621 |
|
* Calculate a 64-bit checksum of everything in a struct memory. This is |
622 |
|
* useful for tracking down bugs; an old (presumably working) version of |
623 |
|
* the emulator can be compared to a newer (buggy) version. |
624 |
|
*/ |
625 |
|
uint64_t memory_checksum(struct memory *mem) |
626 |
|
{ |
627 |
|
uint64_t internal_state = 0x80624185376feff2ULL; |
628 |
|
uint64_t checksum = 0xcb9a87d5c010072cULL; |
629 |
|
const int n_entries = (1 << BITS_PER_PAGETABLE) - 1; |
630 |
|
const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t); |
631 |
|
size_t entry, i; |
632 |
|
|
633 |
|
for (entry=0; entry<=n_entries; entry++) { |
634 |
|
uint64_t **table = mem->pagetable; |
635 |
|
uint64_t *memblock = table[entry]; |
636 |
|
|
637 |
|
if (memblock == NULL) { |
638 |
|
UPDATE_CHECKSUM(0x1198ab7c8174a76fULL); |
639 |
|
continue; |
640 |
|
} |
641 |
|
|
642 |
|
for (i=0; i<len; i++) |
643 |
|
UPDATE_CHECKSUM(memblock[i]); |
644 |
|
} |
645 |
|
|
646 |
|
return checksum; |
647 |
} |
} |
648 |
|
|