Commit 06afe2c8840ec39c3b23db0eb830a5f49244b947

Authored by aurel32
1 parent 29e179bc

[sh4] MMU bug fix

Some bugs on SH4 MMU are fixed.

- When a TLB entry is overwritten or invalidated, tlb_flush_page() should be
  invoked to invalidate old entry.
- When a ASID is changed, tlb_flush() should be invoke to invalidate entries
  which have old ASID.
- The check for shared bit in TLB entry causes multiple TLB hit exception.
  As SH3's MMU, shared bit is ignored.
- ASID is used when MMUCR's SV bit or SR's MD bit is zero.
  No need to check both bits are zero.

(Shin-ichiro KAWASAKI)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5068 c046a42c-6fe2-441c-8c8c-71466251a162
hw/sh7750.c
... ... @@ -30,6 +30,7 @@
30 30 #include "sh7750_regs.h"
31 31 #include "sh7750_regnames.h"
32 32 #include "sh_intc.h"
  33 +#include "exec-all.h"
33 34 #include "cpu.h"
34 35  
35 36 #define NB_DEVICES 4
... ... @@ -356,6 +357,9 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr,
356 357 s->cpu->mmucr = mem_value;
357 358 return;
358 359 case SH7750_PTEH_A7:
  360 + /* If asid changes, clear all registered tlb entries. */
  361 + if ((s->cpu->pteh & 0xff) != (mem_value & 0xff))
  362 + tlb_flush(s->cpu, 1);
359 363 s->cpu->pteh = mem_value;
360 364 return;
361 365 case SH7750_PTEL_A7:
... ...
target-sh4/helper.c
... ... @@ -251,7 +251,7 @@ static int find_tlb_entry(CPUState * env, target_ulong address,
251 251 for (i = 0; i < nbtlb; i++) {
252 252 if (!entries[i].v)
253 253 continue; /* Invalid entry */
254   - if (use_asid && entries[i].asid != asid && !entries[i].sh)
  254 + if (use_asid && entries[i].asid != asid)
255 255 continue; /* Bad ASID */
256 256 #if 0
257 257 switch (entries[i].sz) {
... ... @@ -320,8 +320,14 @@ int find_itlb_entry(CPUState * env, target_ulong address,
320 320 else if (e == MMU_DTLB_MISS && update) {
321 321 e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
322 322 if (e >= 0) {
  323 + tlb_t * ientry;
323 324 n = itlb_replacement(env);
324   - env->itlb[n] = env->utlb[e];
  325 + ientry = &env->itlb[n];
  326 + if (ientry->v) {
  327 + if (!same_tlb_entry_exists(env->utlb, UTLB_SIZE, ientry))
  328 + tlb_flush_page(env, ientry->vpn << 10);
  329 + }
  330 + *ientry = env->utlb[e];
325 331 e = n;
326 332 } else if (e == MMU_DTLB_MISS)
327 333 e = MMU_ITLB_MISS;
... ... @@ -356,7 +362,7 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
356 362 int use_asid, is_code, n;
357 363 tlb_t *matching = NULL;
358 364  
359   - use_asid = (env->mmucr & MMUCR_SV) == 0 && (env->sr & SR_MD) == 0;
  365 + use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
360 366 is_code = env->pc == address; /* Hack */
361 367  
362 368 /* Use a hack to find if this is an instruction or data access */
... ... @@ -540,6 +546,17 @@ void cpu_load_tlb(CPUState * env)
540 546 int n = cpu_mmucr_urc(env->mmucr);
541 547 tlb_t * entry = &env->utlb[n];
542 548  
  549 + if (entry->v) {
  550 + /* Overwriting valid entry in utlb. */
  551 + target_ulong address = entry->vpn << 10;
  552 + if (!same_tlb_entry_exists(env->itlb, ITLB_SIZE, entry)) {
  553 + tlb_flush_page(env, address);
  554 + }
  555 + }
  556 +
  557 + /* per utlb access cannot implemented. */
  558 + increment_urc(env);
  559 +
543 560 /* Take values into cpu status from registers. */
544 561 entry->asid = (uint8_t)cpu_pteh_asid(env->pteh);
545 562 entry->vpn = cpu_pteh_vpn(env->pteh);
... ...