Commit 3b1c8be4f4f1b5d4114320aaf41ec4872ab4598c
1 parent
c281868e
Fix PageMask handling, second part.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2345 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
36 additions
and
16 deletions
target-mips/cpu.h
target-mips/helper.c
... | ... | @@ -41,23 +41,26 @@ enum { |
41 | 41 | static int map_address (CPUState *env, target_ulong *physical, int *prot, |
42 | 42 | target_ulong address, int rw, int access_type) |
43 | 43 | { |
44 | - target_ulong tag = address & (TARGET_PAGE_MASK << 1); | |
45 | - uint8_t ASID = env->CP0_EntryHi & 0xFF; | |
46 | - tlb_t *tlb; | |
47 | - int i, n; | |
44 | + int i; | |
48 | 45 | |
49 | 46 | for (i = 0; i < env->tlb_in_use; i++) { |
50 | - tlb = &env->tlb[i]; | |
47 | + tlb_t *tlb = &env->tlb[i]; | |
48 | + /* 1k pages are not supported. */ | |
49 | + uint8_t ASID = env->CP0_EntryHi & 0xFF; | |
50 | + target_ulong mask = tlb->PageMask | 0x1FFF; | |
51 | + target_ulong tag = address & ~mask; | |
52 | + int n; | |
53 | + | |
51 | 54 | /* Check ASID, virtual page number & size */ |
52 | 55 | if ((tlb->G == 1 || tlb->ASID == ASID) && |
53 | 56 | tlb->VPN == tag) { |
54 | 57 | /* TLB match */ |
55 | - n = (address >> TARGET_PAGE_BITS) & 1; | |
58 | + n = !!(address & mask & ~(mask >> 1)); | |
56 | 59 | /* Check access rights */ |
57 | 60 | if (!(n ? tlb->V1 : tlb->V0)) |
58 | 61 | return TLBRET_INVALID; |
59 | 62 | if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { |
60 | - *physical = tlb->PFN[n] | (address & ~TARGET_PAGE_MASK); | |
63 | + *physical = tlb->PFN[n] | (address & (mask >> 1)); | |
61 | 64 | *prot = PAGE_READ; |
62 | 65 | if (n ? tlb->D1 : tlb->D0) |
63 | 66 | *prot |= PAGE_WRITE; |
... | ... | @@ -420,9 +423,10 @@ void do_interrupt (CPUState *env) |
420 | 423 | void invalidate_tlb (CPUState *env, int idx, int use_extra) |
421 | 424 | { |
422 | 425 | tlb_t *tlb; |
423 | - uint8_t ASID; | |
424 | - | |
425 | - ASID = env->CP0_EntryHi & 0xFF; | |
426 | + target_ulong addr; | |
427 | + target_ulong end; | |
428 | + uint8_t ASID = env->CP0_EntryHi & 0xFF; | |
429 | + target_ulong mask; | |
426 | 430 | |
427 | 431 | tlb = &env->tlb[idx]; |
428 | 432 | /* The qemu TLB is flushed then the ASID changes, so no need to |
... | ... | @@ -440,8 +444,23 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra) |
440 | 444 | return; |
441 | 445 | } |
442 | 446 | |
443 | - if (tlb->V0) | |
444 | - tlb_flush_page (env, tlb->VPN); | |
445 | - if (tlb->V1) | |
446 | - tlb_flush_page (env, tlb->VPN + TARGET_PAGE_SIZE); | |
447 | + /* 1k pages are not supported. */ | |
448 | + mask = tlb->PageMask | 0x1FFF; | |
449 | + if (tlb->V0) { | |
450 | + addr = tlb->VPN; | |
451 | + end = addr | (mask >> 1); | |
452 | + while (addr < end) { | |
453 | + tlb_flush_page (env, addr); | |
454 | + addr += TARGET_PAGE_SIZE; | |
455 | + } | |
456 | + } | |
457 | + if (tlb->V1) { | |
458 | + addr = tlb->VPN | ((mask >> 1) + 1); | |
459 | + addr = tlb->VPN + TARGET_PAGE_SIZE; | |
460 | + end = addr | mask; | |
461 | + while (addr < end) { | |
462 | + tlb_flush_page (env, addr); | |
463 | + addr += TARGET_PAGE_SIZE; | |
464 | + } | |
465 | + } | |
447 | 466 | } | ... | ... |
target-mips/op_helper.c
... | ... | @@ -392,6 +392,7 @@ static void fill_tlb (int idx) |
392 | 392 | tlb = &env->tlb[idx]; |
393 | 393 | tlb->VPN = env->CP0_EntryHi & (int32_t)0xFFFFE000; |
394 | 394 | tlb->ASID = env->CP0_EntryHi & 0xFF; |
395 | + tlb->PageMask = env->CP0_PageMask; | |
395 | 396 | tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; |
396 | 397 | tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; |
397 | 398 | tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; |
... | ... | @@ -473,6 +474,7 @@ void do_tlbr (void) |
473 | 474 | mips_tlb_flush_extra(env, MIPS_TLB_NB); |
474 | 475 | |
475 | 476 | env->CP0_EntryHi = tlb->VPN | tlb->ASID; |
477 | + env->CP0_PageMask = tlb->PageMask; | |
476 | 478 | env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | |
477 | 479 | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); |
478 | 480 | env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | | ... | ... |