17 |
* License along with this library; if not, write to the Free Software |
* License along with this library; if not, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
*/ |
*/ |
20 |
#include "exec.h" |
#include <stdarg.h> |
21 |
|
#include <stdlib.h> |
22 |
|
#include <stdio.h> |
23 |
|
#include <string.h> |
24 |
|
#include <inttypes.h> |
25 |
|
#include <signal.h> |
26 |
|
#include <assert.h> |
27 |
|
|
28 |
|
#include "cpu.h" |
29 |
|
#include "exec-all.h" |
30 |
|
|
31 |
//#define DEBUG_MMU |
//#define DEBUG_MMU |
32 |
//#define DEBUG_BATS |
//#define DEBUG_BATS |
33 |
//#define DEBUG_EXCEPTIONS |
//#define DEBUG_EXCEPTIONS |
34 |
|
//#define FLUSH_ALL_TLBS |
35 |
|
|
36 |
/*****************************************************************************/ |
/*****************************************************************************/ |
37 |
/* PowerPC MMU emulation */ |
/* PowerPC MMU emulation */ |
404 |
} |
} |
405 |
#endif |
#endif |
406 |
|
|
|
#if !defined(CONFIG_USER_ONLY) |
|
|
|
|
|
#define MMUSUFFIX _mmu |
|
|
#define GETPC() (__builtin_return_address(0)) |
|
|
|
|
|
#define SHIFT 0 |
|
|
#include "softmmu_template.h" |
|
|
|
|
|
#define SHIFT 1 |
|
|
#include "softmmu_template.h" |
|
|
|
|
|
#define SHIFT 2 |
|
|
#include "softmmu_template.h" |
|
|
|
|
|
#define SHIFT 3 |
|
|
#include "softmmu_template.h" |
|
|
|
|
|
/* try to fill the TLB and return an exception if error. If retaddr is |
|
|
NULL, it means that the function was called in C code (i.e. not |
|
|
from generated code or from helper.c) */ |
|
|
/* XXX: fix it to restore all registers */ |
|
|
void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) |
|
|
{ |
|
|
TranslationBlock *tb; |
|
|
CPUState *saved_env; |
|
|
unsigned long pc; |
|
|
int ret; |
|
|
|
|
|
/* XXX: hack to restore env in all cases, even if not called from |
|
|
generated code */ |
|
|
saved_env = env; |
|
|
env = cpu_single_env; |
|
|
#if 0 |
|
|
{ |
|
|
unsigned long tlb_addrr, tlb_addrw; |
|
|
int index; |
|
|
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
|
|
tlb_addrr = env->tlb_read[is_user][index].address; |
|
|
tlb_addrw = env->tlb_write[is_user][index].address; |
|
|
if (loglevel) { |
|
|
fprintf(logfile, |
|
|
"%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " |
|
|
"(0x%08lx 0x%08lx)\n", __func__, env, |
|
|
&env->tlb_read[is_user][index], index, addr, |
|
|
tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, |
|
|
tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); |
|
|
} |
|
|
} |
|
|
#endif |
|
|
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); |
|
|
if (ret) { |
|
|
if (retaddr) { |
|
|
/* now we have a real cpu fault */ |
|
|
pc = (unsigned long)retaddr; |
|
|
tb = tb_find_pc(pc); |
|
|
if (tb) { |
|
|
/* the PC is inside the translated code. It means that we have |
|
|
a virtual CPU fault */ |
|
|
cpu_restore_state(tb, env, pc, NULL); |
|
|
} |
|
|
} |
|
|
do_raise_exception_err(env->exception_index, env->error_code); |
|
|
} |
|
|
#if 0 |
|
|
{ |
|
|
unsigned long tlb_addrr, tlb_addrw; |
|
|
int index; |
|
|
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
|
|
tlb_addrr = env->tlb_read[is_user][index].address; |
|
|
tlb_addrw = env->tlb_write[is_user][index].address; |
|
|
printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " |
|
|
"(0x%08lx 0x%08lx)\n", __func__, env, |
|
|
&env->tlb_read[is_user][index], index, addr, |
|
|
tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, |
|
|
tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); |
|
|
} |
|
|
#endif |
|
|
env = saved_env; |
|
|
} |
|
|
|
|
|
void cpu_ppc_init_mmu(CPUState *env) |
|
|
{ |
|
|
/* Nothing to do: all translation are disabled */ |
|
|
} |
|
|
#endif |
|
|
|
|
407 |
/* Perform address translation */ |
/* Perform address translation */ |
408 |
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
409 |
int is_user, int is_softmmu) |
int is_user, int is_softmmu) |
500 |
error_code = EXCP_INVAL | EXCP_INVAL_INVAL; |
error_code = EXCP_INVAL | EXCP_INVAL_INVAL; |
501 |
break; |
break; |
502 |
} |
} |
503 |
|
break; |
504 |
case -5: |
case -5: |
505 |
/* No match in segment table */ |
/* No match in segment table */ |
506 |
exception = EXCP_DSEG; |
exception = EXCP_DSEG; |
507 |
error_code = 0; |
error_code = 0; |
508 |
break; |
break; |
509 |
} |
} |
510 |
if (rw) |
if (exception == EXCP_DSI && rw == 1) |
511 |
error_code |= 0x02000000; |
error_code |= 0x02000000; |
512 |
/* Store fault address */ |
/* Store fault address */ |
513 |
env->spr[SPR_DAR] = address; |
env->spr[SPR_DAR] = address; |
1416 |
/* Jump to handler */ |
/* Jump to handler */ |
1417 |
env->nip = excp; |
env->nip = excp; |
1418 |
env->exception_index = EXCP_NONE; |
env->exception_index = EXCP_NONE; |
1419 |
|
#if 0 |
1420 |
/* ensure that no TB jump will be modified as |
/* ensure that no TB jump will be modified as |
1421 |
the program flow was changed */ |
the program flow was changed */ |
1422 |
#ifdef __sparc__ |
#ifdef __sparc__ |
1424 |
#else |
#else |
1425 |
T0 = 0; |
T0 = 0; |
1426 |
#endif |
#endif |
1427 |
|
#endif |
1428 |
env->interrupt_request |= CPU_INTERRUPT_EXITTB; |
env->interrupt_request |= CPU_INTERRUPT_EXITTB; |
1429 |
} |
} |
1430 |
#endif /* !CONFIG_USER_ONLY */ |
#endif /* !CONFIG_USER_ONLY */ |