Commit 100ce98812c2624a7e7922055d80ebbd81e8caa9
1 parent
f1b0aa5d
Full MIPS64 MMU implementation, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2820 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
53 additions
and
7 deletions
target-mips/helper.c
| @@ -76,6 +76,9 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, | @@ -76,6 +76,9 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, | ||
| 76 | target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); | 76 | target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); |
| 77 | target_ulong tag = address & ~mask; | 77 | target_ulong tag = address & ~mask; |
| 78 | target_ulong VPN = tlb->VPN & ~mask; | 78 | target_ulong VPN = tlb->VPN & ~mask; |
| 79 | +#ifdef TARGET_MIPS64 | ||
| 80 | + tag &= 0xC00000FFFFFFFFFFULL; | ||
| 81 | +#endif | ||
| 79 | 82 | ||
| 80 | /* Check ASID, virtual page number & size */ | 83 | /* Check ASID, virtual page number & size */ |
| 81 | if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { | 84 | 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, | @@ -295,10 +298,16 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||
| 295 | } | 298 | } |
| 296 | /* Raise exception */ | 299 | /* Raise exception */ |
| 297 | env->CP0_BadVAddr = address; | 300 | env->CP0_BadVAddr = address; |
| 298 | - env->CP0_Context = (env->CP0_Context & 0xff800000) | | 301 | + env->CP0_Context = (env->CP0_Context & ~0x007fffff) | |
| 299 | ((address >> 9) & 0x007ffff0); | 302 | ((address >> 9) & 0x007ffff0); |
| 300 | env->CP0_EntryHi = | 303 | env->CP0_EntryHi = |
| 301 | (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); | 304 | (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); |
| 305 | +#ifdef TARGET_MIPS64 | ||
| 306 | + env->CP0_EntryHi &= 0xc00000ffffffffffULL; | ||
| 307 | + env->CP0_XContext = (env->CP0_XContext & 0xfffffffe00000000ULL) | | ||
| 308 | + ((address >> 31) & 0x0000000180000000ULL) | | ||
| 309 | + ((address >> 9) & 0x000000007ffffff0ULL); | ||
| 310 | +#endif | ||
| 302 | env->exception_index = exception; | 311 | env->exception_index = exception; |
| 303 | env->error_code = error_code; | 312 | env->error_code = error_code; |
| 304 | ret = 1; | 313 | ret = 1; |
| @@ -411,8 +420,19 @@ void do_interrupt (CPUState *env) | @@ -411,8 +420,19 @@ void do_interrupt (CPUState *env) | ||
| 411 | goto set_EPC; | 420 | goto set_EPC; |
| 412 | case EXCP_TLBL: | 421 | case EXCP_TLBL: |
| 413 | cause = 2; | 422 | cause = 2; |
| 414 | - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) | ||
| 415 | - offset = 0x000; | 423 | + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { |
| 424 | +#ifdef TARGET_MIPS64 | ||
| 425 | + int R = env->CP0_BadVAddr >> 62; | ||
| 426 | + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; | ||
| 427 | + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; | ||
| 428 | + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; | ||
| 429 | + | ||
| 430 | + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) | ||
| 431 | + offset = 0x080; | ||
| 432 | + else | ||
| 433 | +#endif | ||
| 434 | + offset = 0x000; | ||
| 435 | + } | ||
| 416 | goto set_EPC; | 436 | goto set_EPC; |
| 417 | case EXCP_IBE: | 437 | case EXCP_IBE: |
| 418 | cause = 6; | 438 | cause = 6; |
| @@ -448,8 +468,19 @@ void do_interrupt (CPUState *env) | @@ -448,8 +468,19 @@ void do_interrupt (CPUState *env) | ||
| 448 | goto set_EPC; | 468 | goto set_EPC; |
| 449 | case EXCP_TLBS: | 469 | case EXCP_TLBS: |
| 450 | cause = 3; | 470 | cause = 3; |
| 451 | - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) | ||
| 452 | - offset = 0x000; | 471 | + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { |
| 472 | +#ifdef TARGET_MIPS64 | ||
| 473 | + int R = env->CP0_BadVAddr >> 62; | ||
| 474 | + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; | ||
| 475 | + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; | ||
| 476 | + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; | ||
| 477 | + | ||
| 478 | + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) | ||
| 479 | + offset = 0x080; | ||
| 480 | + else | ||
| 481 | +#endif | ||
| 482 | + offset = 0x000; | ||
| 483 | + } | ||
| 453 | set_EPC: | 484 | set_EPC: |
| 454 | if (!(env->CP0_Status & (1 << CP0St_EXL))) { | 485 | if (!(env->CP0_Status & (1 << CP0St_EXL))) { |
| 455 | if (env->hflags & MIPS_HFLAG_BMASK) { | 486 | if (env->hflags & MIPS_HFLAG_BMASK) { |
| @@ -520,6 +551,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) | @@ -520,6 +551,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) | ||
| 520 | mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); | 551 | mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); |
| 521 | if (tlb->V0) { | 552 | if (tlb->V0) { |
| 522 | addr = tlb->VPN & ~mask; | 553 | addr = tlb->VPN & ~mask; |
| 554 | +#ifdef TARGET_MIPS64 | ||
| 555 | + if (addr >= 0xC00000FF80000000ULL) { | ||
| 556 | + addr |= 0x3FFFFF0000000000ULL; | ||
| 557 | + } | ||
| 558 | +#endif | ||
| 523 | end = addr | (mask >> 1); | 559 | end = addr | (mask >> 1); |
| 524 | while (addr < end) { | 560 | while (addr < end) { |
| 525 | tlb_flush_page (env, addr); | 561 | tlb_flush_page (env, addr); |
| @@ -528,6 +564,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) | @@ -528,6 +564,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) | ||
| 528 | } | 564 | } |
| 529 | if (tlb->V1) { | 565 | if (tlb->V1) { |
| 530 | addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); | 566 | addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); |
| 567 | +#ifdef TARGET_MIPS64 | ||
| 568 | + if (addr >= 0xC00000FF80000000ULL) { | ||
| 569 | + addr |= 0x3FFFFF0000000000ULL; | ||
| 570 | + } | ||
| 571 | +#endif | ||
| 531 | end = addr | mask; | 572 | end = addr | mask; |
| 532 | while (addr < end) { | 573 | while (addr < end) { |
| 533 | tlb_flush_page (env, addr); | 574 | tlb_flush_page (env, addr); |
target-mips/op.c
| @@ -1317,8 +1317,10 @@ void op_mtc0_entryhi (void) | @@ -1317,8 +1317,10 @@ void op_mtc0_entryhi (void) | ||
| 1317 | target_ulong old, val; | 1317 | target_ulong old, val; |
| 1318 | 1318 | ||
| 1319 | /* 1k pages not implemented */ | 1319 | /* 1k pages not implemented */ |
| 1320 | - /* Ignore MIPS64 TLB for now */ | ||
| 1321 | - val = (target_ulong)(int32_t)T0 & ~(target_ulong)0x1F00; | 1320 | + val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF); |
| 1321 | +#ifdef TARGET_MIPS64 | ||
| 1322 | + val = T0 & 0xC00000FFFFFFFFFFULL; | ||
| 1323 | +#endif | ||
| 1322 | old = env->CP0_EntryHi; | 1324 | old = env->CP0_EntryHi; |
| 1323 | env->CP0_EntryHi = val; | 1325 | env->CP0_EntryHi = val; |
| 1324 | /* If the ASID changes, flush qemu's TLB. */ | 1326 | /* If the ASID changes, flush qemu's TLB. */ |
target-mips/op_helper.c
| @@ -391,6 +391,9 @@ static void r4k_fill_tlb (int idx) | @@ -391,6 +391,9 @@ static void r4k_fill_tlb (int idx) | ||
| 391 | /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ | 391 | /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ |
| 392 | tlb = &env->mmu.r4k.tlb[idx]; | 392 | tlb = &env->mmu.r4k.tlb[idx]; |
| 393 | tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); | 393 | tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); |
| 394 | +#ifdef TARGET_MIPS64 | ||
| 395 | + tlb->VPN &= 0xC00000FFFFFFFFFFULL; | ||
| 396 | +#endif | ||
| 394 | tlb->ASID = env->CP0_EntryHi & 0xFF; | 397 | tlb->ASID = env->CP0_EntryHi & 0xFF; |
| 395 | tlb->PageMask = env->CP0_PageMask; | 398 | tlb->PageMask = env->CP0_PageMask; |
| 396 | tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; | 399 | tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; |