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