mirror of https://github.com/xemu-project/xemu.git
accel/tcg: Use the alignment test in tlb_fill_align
When we have a tlb miss, defer the alignment check to the new tlb_fill_align hook. Move the existing alignment check so that we only perform it with a tlb hit. Reviewed-by: Helge Deller <deller@gmx.de> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
f168808d7d
commit
795592fef7
|
@ -1620,6 +1620,7 @@ typedef struct MMULookupLocals {
|
||||||
* mmu_lookup1: translate one page
|
* mmu_lookup1: translate one page
|
||||||
* @cpu: generic cpu state
|
* @cpu: generic cpu state
|
||||||
* @data: lookup parameters
|
* @data: lookup parameters
|
||||||
|
* @memop: memory operation for the access, or 0
|
||||||
* @mmu_idx: virtual address context
|
* @mmu_idx: virtual address context
|
||||||
* @access_type: load/store/code
|
* @access_type: load/store/code
|
||||||
* @ra: return address into tcg generated code, or 0
|
* @ra: return address into tcg generated code, or 0
|
||||||
|
@ -1629,7 +1630,7 @@ typedef struct MMULookupLocals {
|
||||||
* tlb_fill_align will longjmp out. Return true if the softmmu tlb for
|
* tlb_fill_align will longjmp out. Return true if the softmmu tlb for
|
||||||
* @mmu_idx may have resized.
|
* @mmu_idx may have resized.
|
||||||
*/
|
*/
|
||||||
static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data,
|
static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data, MemOp memop,
|
||||||
int mmu_idx, MMUAccessType access_type, uintptr_t ra)
|
int mmu_idx, MMUAccessType access_type, uintptr_t ra)
|
||||||
{
|
{
|
||||||
vaddr addr = data->addr;
|
vaddr addr = data->addr;
|
||||||
|
@ -1645,7 +1646,7 @@ static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data,
|
||||||
if (!victim_tlb_hit(cpu, mmu_idx, index, access_type,
|
if (!victim_tlb_hit(cpu, mmu_idx, index, access_type,
|
||||||
addr & TARGET_PAGE_MASK)) {
|
addr & TARGET_PAGE_MASK)) {
|
||||||
tlb_fill_align(cpu, addr, access_type, mmu_idx,
|
tlb_fill_align(cpu, addr, access_type, mmu_idx,
|
||||||
0, data->size, false, ra);
|
memop, data->size, false, ra);
|
||||||
maybe_resized = true;
|
maybe_resized = true;
|
||||||
index = tlb_index(cpu, mmu_idx, addr);
|
index = tlb_index(cpu, mmu_idx, addr);
|
||||||
entry = tlb_entry(cpu, mmu_idx, addr);
|
entry = tlb_entry(cpu, mmu_idx, addr);
|
||||||
|
@ -1657,6 +1658,25 @@ static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data,
|
||||||
flags = tlb_addr & (TLB_FLAGS_MASK & ~TLB_FORCE_SLOW);
|
flags = tlb_addr & (TLB_FLAGS_MASK & ~TLB_FORCE_SLOW);
|
||||||
flags |= full->slow_flags[access_type];
|
flags |= full->slow_flags[access_type];
|
||||||
|
|
||||||
|
if (likely(!maybe_resized)) {
|
||||||
|
/* Alignment has not been checked by tlb_fill_align. */
|
||||||
|
int a_bits = memop_alignment_bits(memop);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This alignment check differs from the one above, in that this is
|
||||||
|
* based on the atomicity of the operation. The intended use case is
|
||||||
|
* the ARM memory type field of each PTE, where access to pages with
|
||||||
|
* Device memory type require alignment.
|
||||||
|
*/
|
||||||
|
if (unlikely(flags & TLB_CHECK_ALIGNED)) {
|
||||||
|
int at_bits = memop_atomicity_bits(memop);
|
||||||
|
a_bits = MAX(a_bits, at_bits);
|
||||||
|
}
|
||||||
|
if (unlikely(addr & ((1 << a_bits) - 1))) {
|
||||||
|
cpu_unaligned_access(cpu, addr, access_type, mmu_idx, ra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data->full = full;
|
data->full = full;
|
||||||
data->flags = flags;
|
data->flags = flags;
|
||||||
/* Compute haddr speculatively; depending on flags it might be invalid. */
|
/* Compute haddr speculatively; depending on flags it might be invalid. */
|
||||||
|
@ -1713,7 +1733,6 @@ static void mmu_watch_or_dirty(CPUState *cpu, MMULookupPageData *data,
|
||||||
static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
uintptr_t ra, MMUAccessType type, MMULookupLocals *l)
|
uintptr_t ra, MMUAccessType type, MMULookupLocals *l)
|
||||||
{
|
{
|
||||||
unsigned a_bits;
|
|
||||||
bool crosspage;
|
bool crosspage;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
@ -1722,12 +1741,6 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
|
|
||||||
tcg_debug_assert(l->mmu_idx < NB_MMU_MODES);
|
tcg_debug_assert(l->mmu_idx < NB_MMU_MODES);
|
||||||
|
|
||||||
/* Handle CPU specific unaligned behaviour */
|
|
||||||
a_bits = memop_alignment_bits(l->memop);
|
|
||||||
if (addr & ((1 << a_bits) - 1)) {
|
|
||||||
cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
l->page[0].addr = addr;
|
l->page[0].addr = addr;
|
||||||
l->page[0].size = memop_size(l->memop);
|
l->page[0].size = memop_size(l->memop);
|
||||||
l->page[1].addr = (addr + l->page[0].size - 1) & TARGET_PAGE_MASK;
|
l->page[1].addr = (addr + l->page[0].size - 1) & TARGET_PAGE_MASK;
|
||||||
|
@ -1735,7 +1748,7 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
crosspage = (addr ^ l->page[1].addr) & TARGET_PAGE_MASK;
|
crosspage = (addr ^ l->page[1].addr) & TARGET_PAGE_MASK;
|
||||||
|
|
||||||
if (likely(!crosspage)) {
|
if (likely(!crosspage)) {
|
||||||
mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra);
|
mmu_lookup1(cpu, &l->page[0], l->memop, l->mmu_idx, type, ra);
|
||||||
|
|
||||||
flags = l->page[0].flags;
|
flags = l->page[0].flags;
|
||||||
if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) {
|
if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) {
|
||||||
|
@ -1754,8 +1767,8 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
* Lookup both pages, recognizing exceptions from either. If the
|
* Lookup both pages, recognizing exceptions from either. If the
|
||||||
* second lookup potentially resized, refresh first CPUTLBEntryFull.
|
* second lookup potentially resized, refresh first CPUTLBEntryFull.
|
||||||
*/
|
*/
|
||||||
mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra);
|
mmu_lookup1(cpu, &l->page[0], l->memop, l->mmu_idx, type, ra);
|
||||||
if (mmu_lookup1(cpu, &l->page[1], l->mmu_idx, type, ra)) {
|
if (mmu_lookup1(cpu, &l->page[1], 0, l->mmu_idx, type, ra)) {
|
||||||
uintptr_t index = tlb_index(cpu, l->mmu_idx, addr);
|
uintptr_t index = tlb_index(cpu, l->mmu_idx, addr);
|
||||||
l->page[0].full = &cpu->neg.tlb.d[l->mmu_idx].fulltlb[index];
|
l->page[0].full = &cpu->neg.tlb.d[l->mmu_idx].fulltlb[index];
|
||||||
}
|
}
|
||||||
|
@ -1774,19 +1787,6 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
tcg_debug_assert((flags & TLB_BSWAP) == 0);
|
tcg_debug_assert((flags & TLB_BSWAP) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This alignment check differs from the one above, in that this is
|
|
||||||
* based on the atomicity of the operation. The intended use case is
|
|
||||||
* the ARM memory type field of each PTE, where access to pages with
|
|
||||||
* Device memory type require alignment.
|
|
||||||
*/
|
|
||||||
if (unlikely(flags & TLB_CHECK_ALIGNED)) {
|
|
||||||
a_bits = memop_atomicity_bits(l->memop);
|
|
||||||
if (addr & ((1 << a_bits) - 1)) {
|
|
||||||
cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return crosspage;
|
return crosspage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1799,34 +1799,18 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
{
|
{
|
||||||
uintptr_t mmu_idx = get_mmuidx(oi);
|
uintptr_t mmu_idx = get_mmuidx(oi);
|
||||||
MemOp mop = get_memop(oi);
|
MemOp mop = get_memop(oi);
|
||||||
int a_bits = memop_alignment_bits(mop);
|
|
||||||
uintptr_t index;
|
uintptr_t index;
|
||||||
CPUTLBEntry *tlbe;
|
CPUTLBEntry *tlbe;
|
||||||
vaddr tlb_addr;
|
vaddr tlb_addr;
|
||||||
void *hostaddr;
|
void *hostaddr;
|
||||||
CPUTLBEntryFull *full;
|
CPUTLBEntryFull *full;
|
||||||
|
bool did_tlb_fill = false;
|
||||||
|
|
||||||
tcg_debug_assert(mmu_idx < NB_MMU_MODES);
|
tcg_debug_assert(mmu_idx < NB_MMU_MODES);
|
||||||
|
|
||||||
/* Adjust the given return address. */
|
/* Adjust the given return address. */
|
||||||
retaddr -= GETPC_ADJ;
|
retaddr -= GETPC_ADJ;
|
||||||
|
|
||||||
/* Enforce guest required alignment. */
|
|
||||||
if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) {
|
|
||||||
/* ??? Maybe indicate atomic op to cpu_unaligned_access */
|
|
||||||
cpu_unaligned_access(cpu, addr, MMU_DATA_STORE,
|
|
||||||
mmu_idx, retaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enforce qemu required alignment. */
|
|
||||||
if (unlikely(addr & (size - 1))) {
|
|
||||||
/* We get here if guest alignment was not requested,
|
|
||||||
or was not enforced by cpu_unaligned_access above.
|
|
||||||
We might widen the access and emulate, but for now
|
|
||||||
mark an exception and exit the cpu loop. */
|
|
||||||
goto stop_the_world;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = tlb_index(cpu, mmu_idx, addr);
|
index = tlb_index(cpu, mmu_idx, addr);
|
||||||
tlbe = tlb_entry(cpu, mmu_idx, addr);
|
tlbe = tlb_entry(cpu, mmu_idx, addr);
|
||||||
|
|
||||||
|
@ -1836,7 +1820,8 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
if (!victim_tlb_hit(cpu, mmu_idx, index, MMU_DATA_STORE,
|
if (!victim_tlb_hit(cpu, mmu_idx, index, MMU_DATA_STORE,
|
||||||
addr & TARGET_PAGE_MASK)) {
|
addr & TARGET_PAGE_MASK)) {
|
||||||
tlb_fill_align(cpu, addr, MMU_DATA_STORE, mmu_idx,
|
tlb_fill_align(cpu, addr, MMU_DATA_STORE, mmu_idx,
|
||||||
0, size, false, retaddr);
|
mop, size, false, retaddr);
|
||||||
|
did_tlb_fill = true;
|
||||||
index = tlb_index(cpu, mmu_idx, addr);
|
index = tlb_index(cpu, mmu_idx, addr);
|
||||||
tlbe = tlb_entry(cpu, mmu_idx, addr);
|
tlbe = tlb_entry(cpu, mmu_idx, addr);
|
||||||
}
|
}
|
||||||
|
@ -1859,6 +1844,23 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
|
||||||
*/
|
*/
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enforce guest required alignment, if not handled by tlb_fill_align. */
|
||||||
|
if (!did_tlb_fill && (addr & ((1 << memop_alignment_bits(mop)) - 1))) {
|
||||||
|
cpu_unaligned_access(cpu, addr, MMU_DATA_STORE, mmu_idx, retaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enforce qemu required alignment. */
|
||||||
|
if (unlikely(addr & (size - 1))) {
|
||||||
|
/*
|
||||||
|
* We get here if guest alignment was not requested, or was not
|
||||||
|
* enforced by cpu_unaligned_access or tlb_fill_align above.
|
||||||
|
* We might widen the access and emulate, but for now
|
||||||
|
* mark an exception and exit the cpu loop.
|
||||||
|
*/
|
||||||
|
goto stop_the_world;
|
||||||
|
}
|
||||||
|
|
||||||
/* Collect tlb flags for read. */
|
/* Collect tlb flags for read. */
|
||||||
tlb_addr |= tlbe->addr_read;
|
tlb_addr |= tlbe->addr_read;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue