Commit 100ce98812c2624a7e7922055d80ebbd81e8caa9

Authored by ths
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
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;