target-xtensa: update autorefill TLB entries conditionally
This is to avoid interference of internal QEMU helpers (cpu_get_phys_page_debug, tb_invalidate_virtual_addr) with guest-visible TLB state. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
16bde77a29
commit
ae4e7982e6
@ -386,7 +386,7 @@ void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
|
|||||||
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
|
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
|
||||||
void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
|
void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
|
||||||
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
|
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 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);
|
||||||
void reset_mmu(CPUXtensaState *env);
|
void reset_mmu(CPUXtensaState *env);
|
||||||
|
@ -130,11 +130,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong add
|
|||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
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) {
|
&paddr, &page_size, &access) == 0) {
|
||||||
return paddr;
|
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) {
|
&paddr, &page_size, &access) == 0) {
|
||||||
return paddr;
|
return paddr;
|
||||||
}
|
}
|
||||||
@ -443,10 +443,9 @@ static bool is_access_granted(unsigned access, int is_write)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb,
|
static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte);
|
||||||
uint32_t *wi, uint32_t *ei, uint8_t *ring);
|
|
||||||
|
|
||||||
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 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)
|
||||||
{
|
{
|
||||||
@ -454,19 +453,38 @@ static int get_physical_addr_mmu(CPUXtensaState *env,
|
|||||||
uint32_t wi;
|
uint32_t wi;
|
||||||
uint32_t ei;
|
uint32_t ei;
|
||||||
uint8_t ring;
|
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);
|
int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
|
||||||
|
|
||||||
if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
|
if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
|
||||||
(mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) &&
|
(mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) &&
|
||||||
autorefill_mmu(env, vaddr, dtlb, &wi, &ei, &ring) == 0) {
|
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;
|
ret = 0;
|
||||||
}
|
}
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const xtensa_tlb_entry *entry =
|
if (entry == NULL) {
|
||||||
xtensa_tlb_get_entry(env, dtlb, wi, ei);
|
entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
|
||||||
|
}
|
||||||
|
|
||||||
if (ring < mmu_idx) {
|
if (ring < mmu_idx) {
|
||||||
return dtlb ?
|
return dtlb ?
|
||||||
@ -489,31 +507,21 @@ static int get_physical_addr_mmu(CPUXtensaState *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb,
|
static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte)
|
||||||
uint32_t *wi, uint32_t *ei, uint8_t *ring)
|
|
||||||
{
|
{
|
||||||
uint32_t paddr;
|
uint32_t paddr;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
unsigned access;
|
||||||
uint32_t pt_vaddr =
|
uint32_t pt_vaddr =
|
||||||
(env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
|
(env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
|
||||||
int ret = get_physical_addr_mmu(env, pt_vaddr, 0, 0,
|
int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0,
|
||||||
&paddr, &page_size, &access);
|
&paddr, &page_size, &access);
|
||||||
|
|
||||||
qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
|
qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
|
||||||
vaddr, ret ? ~0 : paddr);
|
vaddr, ret ? ~0 : paddr);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
uint32_t vpn;
|
*pte = ldl_phys(paddr);
|
||||||
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);
|
|
||||||
env->sregs[EXCVADDR] = vaddr;
|
|
||||||
qemu_log("%s: autorefill(%08x): %08x -> %08x\n",
|
|
||||||
__func__, vaddr, vpn, pte);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -549,13 +557,13 @@ static int get_physical_addr_region(CPUXtensaState *env,
|
|||||||
*
|
*
|
||||||
* \return 0 if ok, exception cause code otherwise
|
* \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 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)
|
||||||
{
|
{
|
||||||
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
|
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
|
||||||
return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx,
|
return get_physical_addr_mmu(env, update_tlb,
|
||||||
paddr, page_size, access);
|
vaddr, is_write, mmu_idx, paddr, page_size, access);
|
||||||
} else if (xtensa_option_bits_enabled(env->config,
|
} else if (xtensa_option_bits_enabled(env->config,
|
||||||
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
|
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
|
||||||
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
|
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
|
||||||
|
@ -79,7 +79,7 @@ void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_id
|
|||||||
uint32_t paddr;
|
uint32_t paddr;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
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);
|
&paddr, &page_size, &access);
|
||||||
|
|
||||||
qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
|
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 paddr;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
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);
|
&paddr, &page_size, &access);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
tb_invalidate_phys_addr(paddr);
|
tb_invalidate_phys_addr(paddr);
|
||||||
|
Loading…
Reference in New Issue
Block a user