aboutsummaryrefslogtreecommitdiff
path: root/target-xtensa
diff options
context:
space:
mode:
Diffstat (limited to 'target-xtensa')
-rw-r--r--target-xtensa/cpu.h5
-rw-r--r--target-xtensa/helper.c61
-rw-r--r--target-xtensa/op_helper.c20
-rw-r--r--target-xtensa/translate.c2
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);