Avoid multiple calls to io_prepare for unaligned acceses. One call to do_st_mmio_leN will never cross pages.
Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- accel/tcg/cputlb.c | 82 +++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 6cf69bd79d..1d56e3ec0c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1388,30 +1388,6 @@ static void io_failed(CPUArchState *env, CPUTLBEntryFull *full, vaddr addr, } } -static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, - int mmu_idx, uint64_t val, vaddr addr, - uintptr_t retaddr, MemOp op) -{ - MemoryRegionSection *section; - hwaddr mr_offset; - MemoryRegion *mr; - MemTxResult r; - - section = io_prepare(&mr_offset, env, full->xlat_section, - full->attrs, addr, retaddr); - mr = section->mr; - - { - QEMU_IOTHREAD_LOCK_GUARD(); - r = memory_region_dispatch_write(mr, mr_offset, val, op, full->attrs); - } - - if (r != MEMTX_OK) { - io_failed(env, full, addr, memop_size(op), MMU_DATA_STORE, mmu_idx, - r, retaddr); - } -} - /* Return true if ADDR is present in the victim tlb, and has been copied back to the main tlb. */ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, @@ -2682,39 +2658,41 @@ static uint64_t do_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, uint64_t val_le, vaddr addr, int size, int mmu_idx, uintptr_t ra) { + MemoryRegionSection *section; + hwaddr mr_offset; + MemoryRegion *mr; + MemTxAttrs attrs; + tcg_debug_assert(size > 0 && size <= 8); + attrs = full->attrs; + section = io_prepare(&mr_offset, env, full->xlat_section, attrs, addr, ra); + mr = section->mr; + do { + MemOp this_mop; + unsigned this_size; + MemTxResult r; + /* Store aligned pieces up to 8 bytes. */ - switch ((size | (int)addr) & 7) { - case 1: - case 3: - case 5: - case 7: - io_writex(env, full, mmu_idx, val_le, addr, ra, MO_UB); - val_le >>= 8; - size -= 1; - addr += 1; - break; - case 2: - case 6: - io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUW); - val_le >>= 16; - size -= 2; - addr += 2; - break; - case 4: - io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUL); - val_le >>= 32; - size -= 4; - addr += 4; - break; - case 0: - io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUQ); - return 0; - default: - qemu_build_not_reached(); + this_mop = ctz32(size | (int)addr | 8); + this_size = 1 << this_mop; + this_mop |= MO_LE; + + r = memory_region_dispatch_write(mr, mr_offset, val_le, + this_mop, attrs); + if (unlikely(r != MEMTX_OK)) { + io_failed(env, full, addr, this_size, MMU_DATA_STORE, + mmu_idx, r, ra); } + if (this_size == 8) { + return 0; + } + + val_le >>= this_size * 8; + addr += this_size; + mr_offset += this_size; + size -= this_size; } while (size); return val_le; -- 2.34.1