diff options
author | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-13 19:22:13 +0000 |
---|---|---|
committer | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-13 19:22:13 +0000 |
commit | 100ce98812c2624a7e7922055d80ebbd81e8caa9 (patch) | |
tree | 7f44bac550cbac7dcc5437450242789f447566c1 /target-mips | |
parent | f1b0aa5de7f48650aa6260d5dfb8ece1899e286c (diff) | |
download | hqemu-100ce98812c2624a7e7922055d80ebbd81e8caa9.zip hqemu-100ce98812c2624a7e7922055d80ebbd81e8caa9.tar.gz |
Full MIPS64 MMU implementation, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2820 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-mips')
-rw-r--r-- | target-mips/helper.c | 51 | ||||
-rw-r--r-- | target-mips/op.c | 6 | ||||
-rw-r--r-- | target-mips/op_helper.c | 3 |
3 files changed, 53 insertions, 7 deletions
diff --git a/target-mips/helper.c b/target-mips/helper.c index 484834a..306ddf0 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -76,6 +76,9 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; target_ulong VPN = tlb->VPN & ~mask; +#ifdef TARGET_MIPS64 + tag &= 0xC00000FFFFFFFFFFULL; +#endif /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { @@ -295,10 +298,16 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, } /* Raise exception */ env->CP0_BadVAddr = address; - env->CP0_Context = (env->CP0_Context & 0xff800000) | + env->CP0_Context = (env->CP0_Context & ~0x007fffff) | ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); +#ifdef TARGET_MIPS64 + env->CP0_EntryHi &= 0xc00000ffffffffffULL; + env->CP0_XContext = (env->CP0_XContext & 0xfffffffe00000000ULL) | + ((address >> 31) & 0x0000000180000000ULL) | + ((address >> 9) & 0x000000007ffffff0ULL); +#endif env->exception_index = exception; env->error_code = error_code; ret = 1; @@ -411,8 +420,19 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBL: cause = 2; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) - offset = 0x000; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#ifdef TARGET_MIPS64 + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else +#endif + offset = 0x000; + } goto set_EPC; case EXCP_IBE: cause = 6; @@ -448,8 +468,19 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) - offset = 0x000; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#ifdef TARGET_MIPS64 + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else +#endif + offset = 0x000; + } set_EPC: if (!(env->CP0_Status & (1 << CP0St_EXL))) { if (env->hflags & MIPS_HFLAG_BMASK) { @@ -520,6 +551,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); if (tlb->V0) { addr = tlb->VPN & ~mask; +#ifdef TARGET_MIPS64 + if (addr >= 0xC00000FF80000000ULL) { + addr |= 0x3FFFFF0000000000ULL; + } +#endif end = addr | (mask >> 1); while (addr < end) { tlb_flush_page (env, addr); @@ -528,6 +564,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } if (tlb->V1) { addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); +#ifdef TARGET_MIPS64 + if (addr >= 0xC00000FF80000000ULL) { + addr |= 0x3FFFFF0000000000ULL; + } +#endif end = addr | mask; while (addr < end) { tlb_flush_page (env, addr); diff --git a/target-mips/op.c b/target-mips/op.c index a820aad..ddc3cde 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1317,8 +1317,10 @@ void op_mtc0_entryhi (void) target_ulong old, val; /* 1k pages not implemented */ - /* Ignore MIPS64 TLB for now */ - val = (target_ulong)(int32_t)T0 & ~(target_ulong)0x1F00; + val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF); +#ifdef TARGET_MIPS64 + val = T0 & 0xC00000FFFFFFFFFFULL; +#endif old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 895ca7f..2dd0f88 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -391,6 +391,9 @@ static void r4k_fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); +#ifdef TARGET_MIPS64 + tlb->VPN &= 0xC00000FFFFFFFFFFULL; +#endif tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->PageMask = env->CP0_PageMask; tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; |