Revision 814b9a47 target-mips/op_helper.c
b/target-mips/op_helper.c | ||
---|---|---|
367 | 367 |
env->CP0_EntryHi = val; |
368 | 368 |
/* If the ASID changes, flush qemu's TLB. */ |
369 | 369 |
if ((old & 0xFF) != (val & 0xFF)) |
370 |
tlb_flush (env, 1); |
|
370 |
cpu_mips_tlb_flush (env, 1);
|
|
371 | 371 |
rn = "EntryHi"; |
372 | 372 |
break; |
373 | 373 |
case 11: |
... | ... | |
568 | 568 |
|
569 | 569 |
/* TLB management */ |
570 | 570 |
#if defined(MIPS_USES_R4K_TLB) |
571 |
static void invalidate_tlb (int idx) |
|
571 |
void cpu_mips_tlb_flush (CPUState *env, int flush_global) |
|
572 |
{ |
|
573 |
/* Flush qemu's TLB and discard all shadowed entries. */ |
|
574 |
tlb_flush (env, flush_global); |
|
575 |
env->tlb_in_use = MIPS_TLB_NB; |
|
576 |
} |
|
577 |
|
|
578 |
static void invalidate_tlb (int idx, int use_extra) |
|
572 | 579 |
{ |
573 | 580 |
tlb_t *tlb; |
574 | 581 |
target_ulong addr; |
... | ... | |
583 | 590 |
return; |
584 | 591 |
} |
585 | 592 |
|
593 |
if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) { |
|
594 |
/* For tlbwr, we can shadow the discarded entry into |
|
595 |
a new (fake) TLB entry, as long as the guest can not |
|
596 |
tell that it's there. */ |
|
597 |
env->tlb[env->tlb_in_use] = *tlb; |
|
598 |
env->tlb_in_use++; |
|
599 |
return; |
|
600 |
} |
|
601 |
|
|
586 | 602 |
if (tlb->V0) { |
587 | 603 |
tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN); |
588 | 604 |
addr = tlb->VPN; |
... | ... | |
601 | 617 |
} |
602 | 618 |
} |
603 | 619 |
|
620 |
static void mips_tlb_flush_extra (CPUState *env, int first) |
|
621 |
{ |
|
622 |
/* Discard entries from env->tlb[first] onwards. */ |
|
623 |
while (env->tlb_in_use > first) { |
|
624 |
invalidate_tlb(--env->tlb_in_use, 0); |
|
625 |
} |
|
626 |
} |
|
627 |
|
|
604 | 628 |
static void fill_tlb (int idx) |
605 | 629 |
{ |
606 | 630 |
tlb_t *tlb; |
... | ... | |
627 | 651 |
|
628 | 652 |
void do_tlbwi (void) |
629 | 653 |
{ |
654 |
/* Discard cached TLB entries. We could avoid doing this if the |
|
655 |
tlbwi is just upgrading access permissions on the current entry; |
|
656 |
that might be a further win. */ |
|
657 |
mips_tlb_flush_extra (env, MIPS_TLB_NB); |
|
658 |
|
|
630 | 659 |
/* Wildly undefined effects for CP0_index containing a too high value and |
631 | 660 |
MIPS_TLB_NB not being a power of two. But so does real silicon. */ |
632 |
invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); |
|
661 |
invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1), 0);
|
|
633 | 662 |
fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); |
634 | 663 |
} |
635 | 664 |
|
... | ... | |
637 | 666 |
{ |
638 | 667 |
int r = cpu_mips_get_random(env); |
639 | 668 |
|
640 |
invalidate_tlb(r); |
|
669 |
invalidate_tlb(r, 1);
|
|
641 | 670 |
fill_tlb(r); |
642 | 671 |
} |
643 | 672 |
|
... | ... | |
660 | 689 |
} |
661 | 690 |
} |
662 | 691 |
if (i == MIPS_TLB_NB) { |
692 |
/* No match. Discard any shadow entries, if any of them match. */ |
|
693 |
for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) { |
|
694 |
tlb = &env->tlb[i]; |
|
695 |
|
|
696 |
/* Check ASID, virtual page number & size */ |
|
697 |
if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { |
|
698 |
mips_tlb_flush_extra (env, i); |
|
699 |
break; |
|
700 |
} |
|
701 |
} |
|
702 |
|
|
663 | 703 |
env->CP0_index |= 0x80000000; |
664 | 704 |
} |
665 | 705 |
} |
... | ... | |
674 | 714 |
tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; |
675 | 715 |
|
676 | 716 |
/* If this will change the current ASID, flush qemu's TLB. */ |
677 |
if (ASID != tlb->ASID && tlb->G != 1) |
|
678 |
tlb_flush (env, 1); |
|
717 |
if (ASID != tlb->ASID) |
|
718 |
cpu_mips_tlb_flush (env, 1); |
|
719 |
|
|
720 |
mips_tlb_flush_extra(env, MIPS_TLB_NB); |
|
679 | 721 |
|
680 | 722 |
env->CP0_EntryHi = tlb->VPN | tlb->ASID; |
681 | 723 |
size = (tlb->end - tlb->VPN) >> 12; |
Also available in: Unified diff