25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory_rw.c,v 1.82 2005/12/31 15:48:32 debug Exp $ |
* $Id: memory_rw.c,v 1.95 2006/07/25 21:49:14 debug Exp $ |
29 |
* |
* |
30 |
* Generic memory_rw(), with special hacks for specific CPU families. |
* Generic memory_rw(), with special hacks for specific CPU families. |
31 |
* |
* |
53 |
* If the address indicates access to a memory mapped device, that device' |
* If the address indicates access to a memory mapped device, that device' |
54 |
* read/write access function is called. |
* read/write access function is called. |
55 |
* |
* |
|
* If instruction latency/delay support is enabled, then |
|
|
* cpu->instruction_delay is increased by the number of instruction to |
|
|
* delay execution. |
|
|
* |
|
56 |
* This function should not be called with cpu == NULL. |
* This function should not be called with cpu == NULL. |
57 |
* |
* |
58 |
* Returns one of the following: |
* Returns one of the following: |
76 |
uint64_t paddr; |
uint64_t paddr; |
77 |
int cache, no_exceptions, offset; |
int cache, no_exceptions, offset; |
78 |
unsigned char *memblock; |
unsigned char *memblock; |
|
#ifdef MEM_MIPS |
|
|
int bintrans_cached = cpu->machine->bintrans_enable; |
|
|
#endif |
|
79 |
int dyntrans_device_danger = 0; |
int dyntrans_device_danger = 0; |
80 |
|
|
81 |
no_exceptions = misc_flags & NO_EXCEPTIONS; |
no_exceptions = misc_flags & NO_EXCEPTIONS; |
143 |
} |
} |
144 |
#endif /* X86 */ |
#endif /* X86 */ |
145 |
|
|
|
#ifdef MEM_MIPS |
|
|
if (bintrans_cached) { |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_bintrans_host_4kpage = NULL; |
|
|
cpu->cd.mips.pc_bintrans_paddr_valid = 0; |
|
|
} |
|
|
} |
|
|
#endif /* MEM_MIPS */ |
|
146 |
|
|
147 |
#ifdef MEM_USERLAND |
#ifdef MEM_USERLAND |
148 |
#ifdef MEM_ALPHA |
#ifdef MEM_ALPHA |
150 |
#else |
#else |
151 |
paddr = vaddr & 0x7fffffff; |
paddr = vaddr & 0x7fffffff; |
152 |
#endif |
#endif |
153 |
goto have_paddr; |
#else /* !MEM_USERLAND */ |
154 |
#endif |
if (misc_flags & PHYSICAL || cpu->translate_v2p == NULL) { |
|
|
|
|
#ifndef MEM_USERLAND |
|
|
#ifdef MEM_MIPS |
|
|
/* |
|
|
* For instruction fetch, are we on the same page as the last |
|
|
* instruction we fetched? |
|
|
* |
|
|
* NOTE: There's no need to check this stuff here if this address |
|
|
* is known to be in host ram, as it's done at instruction fetch |
|
|
* time in cpu.c! Only check if _host_4k_page == NULL. |
|
|
*/ |
|
|
if (cache == CACHE_INSTRUCTION && |
|
|
cpu->cd.mips.pc_last_host_4k_page == NULL && |
|
|
(vaddr & ~0xfff) == cpu->cd.mips.pc_last_virtual_page) { |
|
|
paddr = cpu->cd.mips.pc_last_physical_page | (vaddr & 0xfff); |
|
|
goto have_paddr; |
|
|
} |
|
|
#endif /* MEM_MIPS */ |
|
|
|
|
|
if (misc_flags & PHYSICAL || cpu->translate_address == NULL) { |
|
155 |
paddr = vaddr; |
paddr = vaddr; |
|
#ifdef MEM_ALPHA |
|
|
/* paddr &= 0x1fffffff; For testalpha */ |
|
|
paddr &= 0x000003ffffffffffULL; |
|
|
#endif |
|
156 |
} else { |
} else { |
157 |
ok = cpu->translate_address(cpu, vaddr, &paddr, |
ok = cpu->translate_v2p(cpu, vaddr, &paddr, |
158 |
(writeflag? FLAG_WRITEFLAG : 0) + |
(writeflag? FLAG_WRITEFLAG : 0) + |
159 |
(no_exceptions? FLAG_NOEXCEPTIONS : 0) |
(no_exceptions? FLAG_NOEXCEPTIONS : 0) |
160 |
#ifdef MEM_X86 |
#ifdef MEM_X86 |
187 |
#endif |
#endif |
188 |
} |
} |
189 |
#endif |
#endif |
190 |
|
#endif /* !MEM_USERLAND */ |
|
#ifdef MEM_MIPS |
|
|
/* |
|
|
* If correct cache emulation is enabled, and we need to simluate |
|
|
* cache misses even from the instruction cache, we can't run directly |
|
|
* from a host page. :-/ |
|
|
*/ |
|
|
#if defined(ENABLE_CACHE_EMULATION) && defined(ENABLE_INSTRUCTION_DELAYS) |
|
|
#else |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_last_virtual_page = vaddr & ~0xfff; |
|
|
cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff; |
|
|
cpu->cd.mips.pc_last_host_4k_page = NULL; |
|
|
|
|
|
/* _last_host_4k_page will be set to 1 further down, |
|
|
if the page is actually in host ram */ |
|
|
} |
|
|
#endif |
|
|
#endif /* MEM_MIPS */ |
|
|
#endif /* ifndef MEM_USERLAND */ |
|
|
|
|
|
|
|
|
#if defined(MEM_MIPS) || defined(MEM_USERLAND) |
|
|
have_paddr: |
|
|
#endif |
|
|
|
|
|
|
|
|
#ifdef MEM_MIPS |
|
|
/* TODO: How about bintrans vs cache emulation? */ |
|
|
if (bintrans_cached) { |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_bintrans_paddr_valid = 1; |
|
|
cpu->cd.mips.pc_bintrans_paddr = paddr; |
|
|
} |
|
|
} |
|
|
#endif /* MEM_MIPS */ |
|
|
|
|
191 |
|
|
192 |
|
|
193 |
#ifndef MEM_USERLAND |
#ifndef MEM_USERLAND |
280 |
uint64_t p = orig_paddr - *pp; |
uint64_t p = orig_paddr - *pp; |
281 |
host_addr = |
host_addr = |
282 |
memory_paddr_to_hostaddr( |
memory_paddr_to_hostaddr( |
283 |
mem, p, MEM_WRITE) |
mem, p & ~offset_mask, |
284 |
+ (p & ~offset_mask |
MEM_WRITE); |
|
& ((1 << |
|
|
BITS_PER_MEMBLOCK) - 1)); |
|
285 |
} else { |
} else { |
286 |
host_addr = |
host_addr = |
287 |
mem->dev_dyntrans_data[i] + |
mem->dev_dyntrans_data[i] + |
288 |
(paddr & ~offset_mask); |
(paddr & ~offset_mask); |
289 |
} |
} |
290 |
|
|
291 |
cpu->update_translation_table(cpu, |
cpu->update_translation_table(cpu, |
292 |
vaddr & ~offset_mask, host_addr, |
vaddr & ~offset_mask, host_addr, |
293 |
wf, orig_paddr & ~offset_mask); |
wf, orig_paddr & ~offset_mask); |
300 |
data, len, writeflag, |
data, len, writeflag, |
301 |
mem->dev_extra[i]); |
mem->dev_extra[i]); |
302 |
|
|
|
#ifdef ENABLE_INSTRUCTION_DELAYS |
|
303 |
if (res == 0) |
if (res == 0) |
304 |
res = -1; |
res = -1; |
305 |
|
|
|
#ifdef MEM_MIPS |
|
|
cpu->cd.mips.instruction_delay += |
|
|
( (abs(res) - 1) * |
|
|
cpu->cd.mips.cpu_type.instrs_per_cycle ); |
|
|
#endif |
|
|
#endif |
|
|
|
|
306 |
#ifndef MEM_X86 |
#ifndef MEM_X86 |
307 |
/* |
/* |
308 |
* If accessing the memory mapped device |
* If accessing the memory mapped device |
371 |
#endif /* MIPS */ |
#endif /* MIPS */ |
372 |
{ |
{ |
373 |
if (paddr >= mem->physical_max) { |
if (paddr >= mem->physical_max) { |
374 |
|
uint64_t offset, old_pc = cpu->pc; |
375 |
char *symbol; |
char *symbol; |
|
uint64_t offset; |
|
|
#ifdef MEM_MIPS |
|
|
uint64_t old_pc = cpu->cd.mips.pc_last; |
|
|
#else |
|
|
uint64_t old_pc = cpu->pc; |
|
|
#endif |
|
376 |
|
|
377 |
/* This allows for example OS kernels to probe |
/* This allows for example OS kernels to probe |
378 |
memory a few KBs past the end of memory, |
memory a few KBs past the end of memory, |
419 |
fatal(" <%s> ]\n", |
fatal(" <%s> ]\n", |
420 |
symbol? symbol : " no symbol "); |
symbol? symbol : " no symbol "); |
421 |
} |
} |
|
|
|
|
if (cpu->machine->single_step_on_bad_addr) { |
|
|
fatal("[ unimplemented access to " |
|
|
"0x%llx, pc=0x",(long long)paddr); |
|
|
if (cpu->is_32bit) |
|
|
fatal("%08x ]\n", |
|
|
(int)old_pc); |
|
|
else |
|
|
fatal("%016llx ]\n", |
|
|
(long long)old_pc); |
|
|
single_step = 1; |
|
|
} |
|
422 |
} |
} |
423 |
|
|
424 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
468 |
* 3) If this was a Write, then invalidate any code translations |
* 3) If this was a Write, then invalidate any code translations |
469 |
* in that page. |
* in that page. |
470 |
*/ |
*/ |
471 |
memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag); |
memblock = memory_paddr_to_hostaddr(mem, paddr & ~offset_mask, |
472 |
|
writeflag); |
473 |
if (memblock == NULL) { |
if (memblock == NULL) { |
474 |
if (writeflag == MEM_READ) |
if (writeflag == MEM_READ) |
475 |
memset(data, 0, len); |
memset(data, 0, len); |
476 |
goto do_return_ok; |
goto do_return_ok; |
477 |
} |
} |
478 |
|
|
479 |
offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1); |
offset = paddr & offset_mask; |
480 |
|
|
481 |
if (cpu->update_translation_table != NULL && !dyntrans_device_danger |
if (cpu->update_translation_table != NULL && !dyntrans_device_danger |
482 |
|
#ifdef MEM_MIPS |
483 |
|
/* Ugly hack for R2000/R3000 caches: */ |
484 |
|
&& (cpu->cd.mips.cpu_type.mmu_model != MMU3K || |
485 |
|
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES)) |
486 |
|
#endif |
487 |
#ifndef MEM_MIPS |
#ifndef MEM_MIPS |
488 |
/* && !(misc_flags & MEMORY_USER_ACCESS) */ |
/* && !(misc_flags & MEMORY_USER_ACCESS) */ |
489 |
#ifndef MEM_USERLAND |
#ifndef MEM_USERLAND |
492 |
#endif |
#endif |
493 |
&& !no_exceptions) |
&& !no_exceptions) |
494 |
cpu->update_translation_table(cpu, vaddr & ~offset_mask, |
cpu->update_translation_table(cpu, vaddr & ~offset_mask, |
495 |
memblock + (offset & ~offset_mask), |
memblock, (misc_flags & MEMORY_USER_ACCESS) | |
|
(misc_flags & MEMORY_USER_ACCESS) | |
|
|
#ifndef MEM_MIPS |
|
|
(cache == CACHE_INSTRUCTION? TLB_CODE : 0) | |
|
|
#endif |
|
496 |
#if !defined(MEM_MIPS) && !defined(MEM_USERLAND) |
#if !defined(MEM_MIPS) && !defined(MEM_USERLAND) |
497 |
(cache == CACHE_INSTRUCTION? |
(cache == CACHE_INSTRUCTION? |
498 |
(writeflag == MEM_WRITE? 1 : 0) : ok - 1), |
(writeflag == MEM_WRITE? 1 : 0) : ok - 1), |
505 |
if (writeflag == MEM_WRITE && cpu->invalidate_code_translation != NULL) |
if (writeflag == MEM_WRITE && cpu->invalidate_code_translation != NULL) |
506 |
cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR); |
cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR); |
507 |
|
|
508 |
|
if ((paddr&((1<<BITS_PER_MEMBLOCK)-1)) + len > (1<<BITS_PER_MEMBLOCK)) { |
509 |
|
printf("Write over memblock boundary?\n"); |
510 |
|
exit(1); |
511 |
|
} |
512 |
|
|
513 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
514 |
/* Ugly optimization, but it works: */ |
/* Ugly optimization, but it works: */ |
515 |
if (len == sizeof(uint32_t) && (offset & 3)==0 |
if (len == sizeof(uint32_t) && (offset & 3)==0 |
528 |
*(uint8_t *)data = *(uint8_t *)(memblock + offset); |
*(uint8_t *)data = *(uint8_t *)(memblock + offset); |
529 |
else |
else |
530 |
memcpy(data, memblock + offset, len); |
memcpy(data, memblock + offset, len); |
|
|
|
|
#ifdef MEM_MIPS |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_last_host_4k_page = memblock |
|
|
+ (offset & ~offset_mask); |
|
|
if (bintrans_cached) { |
|
|
cpu->cd.mips.pc_bintrans_host_4kpage = |
|
|
cpu->cd.mips.pc_last_host_4k_page; |
|
|
} |
|
|
} |
|
|
#endif /* MIPS */ |
|
531 |
} |
} |
532 |
|
|
533 |
|
|