diff options
Diffstat (limited to 'target-xtensa')
-rw-r--r-- | target-xtensa/cpu.h | 5 | ||||
-rw-r--r-- | target-xtensa/helper.c | 61 | ||||
-rw-r--r-- | target-xtensa/op_helper.c | 20 | ||||
-rw-r--r-- | target-xtensa/translate.c | 2 |
4 files changed, 55 insertions, 33 deletions
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 6d0ea7c03..d5b50d111 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -370,9 +370,12 @@ void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb, uint32_t *vpn, uint32_t wi, uint32_t *ei); int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb, uint32_t *pwi, uint32_t *pei, uint8_t *pring); +void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env, + xtensa_tlb_entry *entry, bool dtlb, + unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte); void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte); -int xtensa_get_physical_addr(CPUXtensaState *env, +int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, uint32_t vaddr, int is_write, int mmu_idx, uint32_t *paddr, uint32_t *page_size, unsigned *access); void reset_mmu(CPUXtensaState *env); diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index 209422784..8ebef729b 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -135,11 +135,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong add uint32_t page_size; unsigned access; - if (xtensa_get_physical_addr(env, addr, 0, 0, + if (xtensa_get_physical_addr(env, false, addr, 0, 0, &paddr, &page_size, &access) == 0) { return paddr; } - if (xtensa_get_physical_addr(env, addr, 2, 0, + if (xtensa_get_physical_addr(env, false, addr, 2, 0, &paddr, &page_size, &access) == 0) { return paddr; } @@ -448,30 +448,48 @@ static bool is_access_granted(unsigned access, int is_write) } } -static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb, - uint32_t *wi, uint32_t *ei, uint8_t *ring); +static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte); -static int get_physical_addr_mmu(CPUXtensaState *env, +static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb, uint32_t vaddr, int is_write, int mmu_idx, - uint32_t *paddr, uint32_t *page_size, unsigned *access) + uint32_t *paddr, uint32_t *page_size, unsigned *access, + bool may_lookup_pt) { bool dtlb = is_write != 2; uint32_t wi; uint32_t ei; uint8_t ring; + uint32_t vpn; + uint32_t pte; + const xtensa_tlb_entry *entry = NULL; + xtensa_tlb_entry tmp_entry; int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring); if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) && - (mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) && - autorefill_mmu(env, vaddr, dtlb, &wi, &ei, &ring) == 0) { + may_lookup_pt && get_pte(env, vaddr, &pte) == 0) { + ring = (pte >> 4) & 0x3; + wi = 0; + split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei); + + if (update_tlb) { + wi = ++env->autorefill_idx & 0x3; + xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte); + env->sregs[EXCVADDR] = vaddr; + qemu_log("%s: autorefill(%08x): %08x -> %08x\n", + __func__, vaddr, vpn, pte); + } else { + xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte); + entry = &tmp_entry; + } ret = 0; } if (ret != 0) { return ret; } - const xtensa_tlb_entry *entry = - xtensa_tlb_get_entry(env, dtlb, wi, ei); + if (entry == NULL) { + entry = xtensa_tlb_get_entry(env, dtlb, wi, ei); + } if (ring < mmu_idx) { return dtlb ? @@ -494,30 +512,21 @@ static int get_physical_addr_mmu(CPUXtensaState *env, return 0; } -static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb, - uint32_t *wi, uint32_t *ei, uint8_t *ring) +static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte) { uint32_t paddr; uint32_t page_size; unsigned access; uint32_t pt_vaddr = (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc; - int ret = get_physical_addr_mmu(env, pt_vaddr, 0, 0, - &paddr, &page_size, &access); + int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0, + &paddr, &page_size, &access, false); qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__, vaddr, ret ? ~0 : paddr); if (ret == 0) { - uint32_t vpn; - uint32_t pte = ldl_phys(paddr); - - *ring = (pte >> 4) & 0x3; - *wi = (++env->autorefill_idx) & 0x3; - split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, *wi, ei); - xtensa_tlb_set_entry(env, dtlb, *wi, *ei, vpn, pte); - qemu_log("%s: autorefill(%08x): %08x -> %08x\n", - __func__, vaddr, vpn, pte); + *pte = ldl_phys(paddr); } return ret; } @@ -553,13 +562,13 @@ static int get_physical_addr_region(CPUXtensaState *env, * * \return 0 if ok, exception cause code otherwise */ -int xtensa_get_physical_addr(CPUXtensaState *env, +int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, uint32_t vaddr, int is_write, int mmu_idx, uint32_t *paddr, uint32_t *page_size, unsigned *access) { if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { - return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx, - paddr, page_size, access); + return get_physical_addr_mmu(env, update_tlb, + vaddr, is_write, mmu_idx, paddr, page_size, access, true); } else if (xtensa_option_bits_enabled(env->config, XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) { diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index 364dc19bc..41107ff64 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -79,7 +79,7 @@ void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_id uint32_t paddr; uint32_t page_size; unsigned access; - int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx, + int ret = xtensa_get_physical_addr(env, true, vaddr, is_write, mmu_idx, &paddr, &page_size, &access); qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__, @@ -103,7 +103,7 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) uint32_t paddr; uint32_t page_size; unsigned access; - int ret = xtensa_get_physical_addr(env, vaddr, 2, 0, + int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0, &paddr, &page_size, &access); if (ret == 0) { tb_invalidate_phys_addr(paddr); @@ -655,6 +655,16 @@ uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb) } } +void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env, + xtensa_tlb_entry *entry, bool dtlb, + unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte) +{ + entry->vaddr = vpn; + entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi); + entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff; + entry->attr = pte & 0xf; +} + void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte) { @@ -665,10 +675,8 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, if (entry->asid) { tlb_flush_page(env, entry->vaddr); } - entry->vaddr = vpn; - entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi); - entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff; - entry->attr = pte & 0xf; + xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte); + tlb_flush_page(env, entry->vaddr); } else { qemu_log("%s %d, %d, %d trying to set immutable entry\n", __func__, dtlb, wi, ei); diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 521c0e622..a542a319d 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -388,6 +388,7 @@ static bool gen_check_loop_end(DisasContext *dc, int slot) dc->next_pc == dc->lend) { int label = gen_new_label(); + gen_advance_ccount(dc); tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label); tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1); gen_jumpi(dc, dc->lbeg, slot); @@ -410,6 +411,7 @@ static void gen_brcond(DisasContext *dc, TCGCond cond, { int label = gen_new_label(); + gen_advance_ccount(dc); tcg_gen_brcond_i32(cond, t0, t1, label); gen_jumpi_check_loop_end(dc, 0); gen_set_label(label); |