25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory.c,v 1.164 2005/04/09 21:10:54 debug Exp $ |
* $Id: memory.c,v 1.182 2005/11/22 16:26:36 debug Exp $ |
29 |
* |
* |
30 |
* Functions for handling the memory of an emulated machine. |
* Functions for handling the memory of an emulated machine. |
31 |
*/ |
*/ |
59 |
*/ |
*/ |
60 |
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len) |
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len) |
61 |
{ |
{ |
62 |
int i; |
int i, byte_order = cpu->byte_order; |
63 |
uint64_t x = 0; |
uint64_t x = 0; |
64 |
|
|
65 |
|
if (len & MEM_PCI_LITTLE_ENDIAN) { |
66 |
|
len &= ~MEM_PCI_LITTLE_ENDIAN; |
67 |
|
byte_order = EMUL_LITTLE_ENDIAN; |
68 |
|
} |
69 |
|
|
70 |
/* Switch byte order for incoming data, if necessary: */ |
/* Switch byte order for incoming data, if necessary: */ |
71 |
if (cpu->byte_order == EMUL_BIG_ENDIAN) |
if (byte_order == EMUL_BIG_ENDIAN) |
72 |
for (i=0; i<len; i++) { |
for (i=0; i<len; i++) { |
73 |
x <<= 8; |
x <<= 8; |
74 |
x |= buf[i]; |
x |= buf[i]; |
94 |
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, |
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, |
95 |
uint64_t data) |
uint64_t data) |
96 |
{ |
{ |
97 |
int i; |
int i, byte_order = cpu->byte_order; |
98 |
|
|
99 |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
if (len & MEM_PCI_LITTLE_ENDIAN) { |
100 |
|
len &= ~MEM_PCI_LITTLE_ENDIAN; |
101 |
|
byte_order = EMUL_LITTLE_ENDIAN; |
102 |
|
} |
103 |
|
|
104 |
|
if (byte_order == EMUL_LITTLE_ENDIAN) |
105 |
for (i=0; i<len; i++) { |
for (i=0; i<len; i++) { |
106 |
buf[i] = data & 255; |
buf[i] = data & 255; |
107 |
data >>= 8; |
data >>= 8; |
118 |
* zeroed_alloc(): |
* zeroed_alloc(): |
119 |
* |
* |
120 |
* Allocates a block of memory using mmap(), and if that fails, try |
* Allocates a block of memory using mmap(), and if that fails, try |
121 |
* malloc() + memset(). |
* malloc() + memset(). The returned memory block contains only zeroes. |
122 |
*/ |
*/ |
123 |
void *zeroed_alloc(size_t s) |
void *zeroed_alloc(size_t s) |
124 |
{ |
{ |
142 |
* This function creates a new memory object. An emulated machine needs one |
* This function creates a new memory object. An emulated machine needs one |
143 |
* of these. |
* of these. |
144 |
*/ |
*/ |
145 |
struct memory *memory_new(uint64_t physical_max) |
struct memory *memory_new(uint64_t physical_max, int arch) |
146 |
{ |
{ |
147 |
struct memory *mem; |
struct memory *mem; |
148 |
int bits_per_pagetable = BITS_PER_PAGETABLE; |
int bits_per_pagetable = BITS_PER_PAGETABLE; |
167 |
} |
} |
168 |
|
|
169 |
mem->physical_max = physical_max; |
mem->physical_max = physical_max; |
170 |
|
mem->dev_dyntrans_alignment = 4095; |
171 |
|
if (arch == ARCH_ALPHA) |
172 |
|
mem->dev_dyntrans_alignment = 8191; |
173 |
|
|
174 |
s = entries_per_pagetable * sizeof(void *); |
s = entries_per_pagetable * sizeof(void *); |
175 |
|
|
266 |
|
|
267 |
|
|
268 |
/* |
/* |
269 |
* memory_device_bintrans_access(): |
* memory_device_dyntrans_access(): |
270 |
* |
* |
271 |
* Get the lowest and highest bintrans access since last time. |
* Get the lowest and highest dyntrans (or bintrans) access since last time. |
272 |
*/ |
*/ |
273 |
void memory_device_bintrans_access(struct cpu *cpu, struct memory *mem, |
void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem, |
274 |
void *extra, uint64_t *low, uint64_t *high) |
void *extra, uint64_t *low, uint64_t *high) |
275 |
{ |
{ |
|
#ifdef BINTRANS |
|
276 |
int i, j; |
int i, j; |
277 |
size_t s; |
size_t s; |
278 |
int need_inval = 0; |
int need_inval = 0; |
283 |
|
|
284 |
for (i=0; i<mem->n_mmapped_devices; i++) { |
for (i=0; i<mem->n_mmapped_devices; i++) { |
285 |
if (mem->dev_extra[i] == extra && |
if (mem->dev_extra[i] == extra && |
286 |
mem->dev_bintrans_data[i] != NULL) { |
mem->dev_dyntrans_data[i] != NULL) { |
287 |
if (mem->dev_bintrans_write_low[i] != (uint64_t) -1) |
if (mem->dev_dyntrans_write_low[i] != (uint64_t) -1) |
288 |
need_inval = 1; |
need_inval = 1; |
289 |
if (low != NULL) |
if (low != NULL) |
290 |
*low = mem->dev_bintrans_write_low[i]; |
*low = mem->dev_dyntrans_write_low[i]; |
291 |
mem->dev_bintrans_write_low[i] = (uint64_t) -1; |
mem->dev_dyntrans_write_low[i] = (uint64_t) -1; |
292 |
|
|
293 |
if (high != NULL) |
if (high != NULL) |
294 |
*high = mem->dev_bintrans_write_high[i]; |
*high = mem->dev_dyntrans_write_high[i]; |
295 |
mem->dev_bintrans_write_high[i] = 0; |
mem->dev_dyntrans_write_high[i] = 0; |
296 |
|
|
297 |
if (!need_inval) |
if (!need_inval) |
298 |
return; |
return; |
299 |
|
|
|
if (cpu->machine->arch != ARCH_MIPS) { |
|
|
/* TODO! */ |
|
|
|
|
|
return; |
|
|
} |
|
|
|
|
300 |
/* Invalidate any pages of this device that might |
/* Invalidate any pages of this device that might |
301 |
be in the bintrans load/store cache, by marking |
be in the dyntrans load/store cache, by marking |
302 |
the pages read-only. */ |
the pages read-only. */ |
303 |
|
if (cpu->invalidate_translation_caches != NULL) { |
304 |
for (s=0; s<mem->dev_length[i]; s+=4096) { |
for (s=0; s<mem->dev_length[i]; |
305 |
mips_invalidate_translation_caches_paddr( |
s+=cpu->machine->arch_pagesize) |
306 |
cpu, mem->dev_baseaddr[i] + s); |
cpu->invalidate_translation_caches |
307 |
|
(cpu, mem->dev_baseaddr[i] + s, |
308 |
|
JUST_MARK_AS_NON_WRITABLE |
309 |
|
| INVALIDATE_PADDR); |
310 |
} |
} |
311 |
|
|
312 |
/* ... and invalidate the "fast_vaddr_to_hostaddr" |
if (cpu->machine->arch == ARCH_MIPS) { |
313 |
cache entries that contain pointers to this |
/* |
314 |
device: (NOTE: Device i, cache entry j) */ |
* ... and invalidate the "fast_vaddr_to_ |
315 |
for (j=0; j<N_BINTRANS_VADDR_TO_HOST; j++) { |
* hostaddr" cache entries that contain |
316 |
if (cpu->cd.mips.bintrans_data_hostpage[j] >= |
* pointers to this device: (NOTE: Device i, |
317 |
mem->dev_bintrans_data[i] && |
* cache entry j) |
318 |
cpu->cd.mips.bintrans_data_hostpage[j] < |
*/ |
319 |
mem->dev_bintrans_data[i] + |
for (j=0; j<N_BINTRANS_VADDR_TO_HOST; j++) { |
320 |
mem->dev_length[i]) |
if (cpu->cd. |
321 |
cpu->cd.mips. |
mips.bintrans_data_hostpage[j] >= |
322 |
bintrans_data_hostpage[j] = NULL; |
mem->dev_dyntrans_data[i] && |
323 |
|
cpu->cd.mips. |
324 |
|
bintrans_data_hostpage[j] < |
325 |
|
mem->dev_dyntrans_data[i] + |
326 |
|
mem->dev_length[i]) |
327 |
|
cpu->cd.mips. |
328 |
|
bintrans_data_hostpage[j] |
329 |
|
= NULL; |
330 |
|
} |
331 |
} |
} |
|
|
|
332 |
return; |
return; |
333 |
} |
} |
334 |
} |
} |
|
#endif |
|
335 |
} |
} |
336 |
|
|
337 |
|
|
371 |
uint64_t baseaddr, uint64_t len, |
uint64_t baseaddr, uint64_t len, |
372 |
int (*f)(struct cpu *,struct memory *,uint64_t,unsigned char *, |
int (*f)(struct cpu *,struct memory *,uint64_t,unsigned char *, |
373 |
size_t,int,void *), |
size_t,int,void *), |
374 |
void *extra, int flags, unsigned char *bintrans_data) |
void *extra, int flags, unsigned char *dyntrans_data) |
375 |
{ |
{ |
376 |
int i; |
int i; |
377 |
|
|
398 |
debug("device %2i at 0x%010llx: %s", |
debug("device %2i at 0x%010llx: %s", |
399 |
mem->n_mmapped_devices, (long long)baseaddr, device_name); |
mem->n_mmapped_devices, (long long)baseaddr, device_name); |
400 |
|
|
401 |
#ifdef BINTRANS |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) |
402 |
if (flags & (MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK) |
&& (baseaddr & mem->dev_dyntrans_alignment) != 0) { |
403 |
&& (baseaddr & 0xfff) != 0) { |
fatal("\nWARNING: Device dyntrans access, but unaligned" |
|
fatal("\nWARNING: Device bintrans access, but unaligned" |
|
404 |
" baseaddr 0x%llx.\n", (long long)baseaddr); |
" baseaddr 0x%llx.\n", (long long)baseaddr); |
405 |
} |
} |
406 |
|
|
407 |
if (flags & (MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK)) { |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) { |
408 |
debug(" (bintrans %s)", |
debug(" (dyntrans %s)", |
409 |
(flags & MEM_BINTRANS_WRITE_OK)? "R/W" : "R"); |
(flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R"); |
410 |
} |
} |
|
#endif |
|
411 |
debug("\n"); |
debug("\n"); |
412 |
|
|
413 |
mem->dev_name[mem->n_mmapped_devices] = strdup(device_name); |
mem->dev_name[mem->n_mmapped_devices] = strdup(device_name); |
414 |
mem->dev_baseaddr[mem->n_mmapped_devices] = baseaddr; |
mem->dev_baseaddr[mem->n_mmapped_devices] = baseaddr; |
415 |
|
mem->dev_endaddr[mem->n_mmapped_devices] = baseaddr + len; |
416 |
mem->dev_length[mem->n_mmapped_devices] = len; |
mem->dev_length[mem->n_mmapped_devices] = len; |
417 |
mem->dev_flags[mem->n_mmapped_devices] = flags; |
mem->dev_flags[mem->n_mmapped_devices] = flags; |
418 |
mem->dev_bintrans_data[mem->n_mmapped_devices] = bintrans_data; |
mem->dev_dyntrans_data[mem->n_mmapped_devices] = dyntrans_data; |
419 |
|
|
420 |
if (mem->dev_name[mem->n_mmapped_devices] == NULL) { |
if (mem->dev_name[mem->n_mmapped_devices] == NULL) { |
421 |
fprintf(stderr, "out of memory\n"); |
fprintf(stderr, "out of memory\n"); |
422 |
exit(1); |
exit(1); |
423 |
} |
} |
424 |
|
|
425 |
if ((size_t)bintrans_data & 1) { |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) |
426 |
|
&& !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) { |
427 |
|
fatal("\nERROR: Device dyntrans access, but dyntrans_data" |
428 |
|
" = NULL!\n"); |
429 |
|
exit(1); |
430 |
|
} |
431 |
|
|
432 |
|
if ((size_t)dyntrans_data & (sizeof(void *) - 1)) { |
433 |
fprintf(stderr, "memory_device_register():" |
fprintf(stderr, "memory_device_register():" |
434 |
" bintrans_data not aligned correctly\n"); |
" dyntrans_data not aligned correctly (%p)\n", |
435 |
|
dyntrans_data); |
436 |
exit(1); |
exit(1); |
437 |
} |
} |
438 |
|
|
439 |
#ifdef BINTRANS |
mem->dev_dyntrans_write_low[mem->n_mmapped_devices] = (uint64_t)-1; |
440 |
mem->dev_bintrans_write_low[mem->n_mmapped_devices] = (uint64_t)-1; |
mem->dev_dyntrans_write_high[mem->n_mmapped_devices] = 0; |
|
mem->dev_bintrans_write_high[mem->n_mmapped_devices] = 0; |
|
|
#endif |
|
441 |
mem->dev_f[mem->n_mmapped_devices] = f; |
mem->dev_f[mem->n_mmapped_devices] = f; |
442 |
mem->dev_extra[mem->n_mmapped_devices] = extra; |
mem->dev_extra[mem->n_mmapped_devices] = extra; |
443 |
mem->n_mmapped_devices++; |
mem->n_mmapped_devices++; |
444 |
|
|
445 |
if (baseaddr < mem->mmap_dev_minaddr) |
if (baseaddr < mem->mmap_dev_minaddr) |
446 |
mem->mmap_dev_minaddr = baseaddr & ~0xfff; |
mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment; |
447 |
if (baseaddr + len > mem->mmap_dev_maxaddr) |
if (baseaddr + len > mem->mmap_dev_maxaddr) |
448 |
mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) | 0xfff) + 1; |
mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) | |
449 |
|
mem->dev_dyntrans_alignment) + 1; |
450 |
} |
} |
451 |
|
|
452 |
|
|
485 |
(MAX_DEVICES - i - 1)); |
(MAX_DEVICES - i - 1)); |
486 |
memmove(&mem->dev_f_state[i], &mem->dev_f_state[i+1], sizeof(void *) * |
memmove(&mem->dev_f_state[i], &mem->dev_f_state[i+1], sizeof(void *) * |
487 |
(MAX_DEVICES - i - 1)); |
(MAX_DEVICES - i - 1)); |
488 |
memmove(&mem->dev_bintrans_data[i], &mem->dev_bintrans_data[i+1], |
memmove(&mem->dev_dyntrans_data[i], &mem->dev_dyntrans_data[i+1], |
489 |
sizeof(void *) * (MAX_DEVICES - i - 1)); |
sizeof(void *) * (MAX_DEVICES - i - 1)); |
490 |
#ifdef BINTRANS |
memmove(&mem->dev_dyntrans_write_low[i], &mem->dev_dyntrans_write_low |
|
memmove(&mem->dev_bintrans_write_low[i], &mem->dev_bintrans_write_low |
|
491 |
[i+1], sizeof(void *) * (MAX_DEVICES - i - 1)); |
[i+1], sizeof(void *) * (MAX_DEVICES - i - 1)); |
492 |
memmove(&mem->dev_bintrans_write_high[i], &mem->dev_bintrans_write_high |
memmove(&mem->dev_dyntrans_write_high[i], &mem->dev_dyntrans_write_high |
493 |
[i+1], sizeof(void *) * (MAX_DEVICES - i - 1)); |
[i+1], sizeof(void *) * (MAX_DEVICES - i - 1)); |
|
#endif |
|
494 |
} |
} |
495 |
|
|
496 |
|
|
520 |
table = mem->pagetable; |
table = mem->pagetable; |
521 |
entry = (paddr >> shrcount) & mask; |
entry = (paddr >> shrcount) & mask; |
522 |
|
|
523 |
/* printf(" entry = %x\n", entry); */ |
/* printf("memory_paddr_to_hostaddr(): p=%16llx w=%i => entry=0x%x\n", |
524 |
|
(long long)paddr, writeflag, entry); */ |
525 |
|
|
526 |
if (table[entry] == NULL) { |
if (table[entry] == NULL) { |
527 |
size_t alloclen; |
size_t alloclen; |