diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index b7abcc68c..1ca62b5db 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -22,9 +22,13 @@ #include "system/tcg.h" #include "qemu/plugin.h" #include "internal-common.h" +#include bool tcg_allowed; -bool mmu_log_enabled = false; +bool mmu_fast_log_enabled = false; +bool mmu_slow_log_enabled = false; +bool mmu_log_to_file = false; +FILE *mmu_log_file = NULL; bool tcg_cflags_has(CPUState *cpu, uint32_t flags) { diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index f5a821cc4..97bf23ff3 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2673,19 +2673,31 @@ static void do_st_1(CPUState *cpu, MMULookupPageData *p, uint8_t val, hwaddr paddr = 0; if (unlikely(p->flags & TLB_MMIO)) { - if (mmu_log_enabled){ - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=1 data=0x%02x (MMIO)\n", - (unsigned long)p->addr, (unsigned long)paddr, val); - } paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=1 data=0x%02x (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=1 data=0x%02x (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, val); + fflush(mmu_log_file); + } + } do_st_mmio_leN(cpu, p->full, val, p->addr, 1, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { - if (mmu_log_enabled){ paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=1 data=0x%02x \n", - (unsigned long)p->addr, (unsigned long)paddr, val); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=1 data=0x%02x\n", + (unsigned long)p->addr, (unsigned long)paddr, val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=1 data=0x%02x\n", + (unsigned long)p->addr, (unsigned long)paddr, val); + fflush(mmu_log_file); + } } *(uint8_t *)p->haddr = val; } @@ -2698,10 +2710,16 @@ static void do_st_2(CPUState *cpu, MMULookupPageData *p, uint16_t val, uint16_t orig_val = val; if (unlikely(p->flags & TLB_MMIO)) { - if (mmu_log_enabled){ paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=2 data=0x%04x (MMIO)\n", - (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=2 data=0x%04x (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=2 data=0x%04x (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + fflush(mmu_log_file); + } } if ((memop & MO_BSWAP) != MO_LE) { val = bswap16(val); @@ -2710,10 +2728,16 @@ static void do_st_2(CPUState *cpu, MMULookupPageData *p, uint16_t val, } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { - if (mmu_log_enabled){ paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=2 data=0x%04x \n", - (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=2 data=0x%04x\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=2 data=0x%04x\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + fflush(mmu_log_file); + } } /* Swap to host endian if necessary, then store. */ if (memop & MO_BSWAP) { @@ -2730,10 +2754,16 @@ static void do_st_4(CPUState *cpu, MMULookupPageData *p, uint32_t val, uint32_t orig_val = val; if (unlikely(p->flags & TLB_MMIO)) { - if (mmu_log_enabled){ - paddr = p->full->phys_addr+ (p->addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=4 data=0x%08x (MMIO)\n", - (unsigned long)p->addr, (unsigned long)paddr, orig_val); + paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=4 data=0x%08x (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=4 data=0x%08x (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + fflush(mmu_log_file); + } } if ((memop & MO_BSWAP) != MO_LE) { val = bswap32(val); @@ -2742,10 +2772,16 @@ static void do_st_4(CPUState *cpu, MMULookupPageData *p, uint32_t val, } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { - if (mmu_log_enabled){ paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=4 data=0x%08x \n", - (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=4 data=0x%08x\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=4 data=0x%08x\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + fflush(mmu_log_file); + } } /* Swap to host endian if necessary, then store. */ if (memop & MO_BSWAP) { @@ -2762,10 +2798,16 @@ static void do_st_8(CPUState *cpu, MMULookupPageData *p, uint64_t val, uint64_t orig_val = val; if (unlikely(p->flags & TLB_MMIO)) { - if (mmu_log_enabled){ paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=8 data=0x%016lx (MMIO)\n", - (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=8 data=0x%016lx (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=8 data=0x%016lx (MMIO)\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + fflush(mmu_log_file); + } } if ((memop & MO_BSWAP) != MO_LE) { val = bswap64(val); @@ -2774,10 +2816,16 @@ static void do_st_8(CPUState *cpu, MMULookupPageData *p, uint64_t val, } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { - if (mmu_log_enabled){ - paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=8 data=0x%016lx \n", - (unsigned long)p->addr, (unsigned long)paddr, orig_val); + paddr = p->full->phys_addr + (p->addr & ~TARGET_PAGE_MASK); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=8 data=0x%016lx\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=8 data=0x%016lx\n", + (unsigned long)p->addr, (unsigned long)paddr, orig_val); + fflush(mmu_log_file); + } } /* Swap to host endian if necessary, then store. */ if (memop & MO_BSWAP) { @@ -2878,13 +2926,19 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { - hwaddr paddr = 0; if (unlikely(l.page[0].flags & TLB_MMIO)) { - if (mmu_log_enabled){ - paddr = l.page[0].full->xlat_section + (addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=16 data=0x%016lx%016lx (MMIO)\n", - (unsigned long)addr, (unsigned long)paddr, - (unsigned long)int128_gethi(val), (unsigned long)int128_getlo(val)); + hwaddr paddr = l.page[0].full->xlat_section + (addr & ~TARGET_PAGE_MASK); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=16 data=0x%016lx%016lx (MMIO)\n", + (unsigned long)addr, (unsigned long)paddr, + (unsigned long)int128_gethi(val), (unsigned long)int128_getlo(val)); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=16 data=0x%016lx%016lx (MMIO)\n", + (unsigned long)addr, (unsigned long)paddr, + (unsigned long)int128_gethi(val), (unsigned long)int128_getlo(val)); + fflush(mmu_log_file); + } } if ((l.memop & MO_BSWAP) != MO_LE) { val = bswap128(val); @@ -2893,11 +2947,18 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, } else if (unlikely(l.page[0].flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { - if (mmu_log_enabled){ - paddr = l.page[0].full->xlat_section + (addr & ~TARGET_PAGE_MASK); - printf("[MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=16 data=0x%016lx%016lx \n", - (unsigned long)addr, (unsigned long)paddr, - (unsigned long)int128_gethi(val), (unsigned long)int128_getlo(val)); + hwaddr paddr = l.page[0].full->xlat_section + (addr & ~TARGET_PAGE_MASK); + if (mmu_slow_log_enabled) { + printf("[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=16 data=0x%016lx%016lx\n", + (unsigned long)addr, (unsigned long)paddr, + (unsigned long)int128_gethi(val), (unsigned long)int128_getlo(val)); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[SLOW_MEMORY_WRITE] vaddr=0x%lx paddr=0x%lx size=16 data=0x%016lx%016lx\n", + (unsigned long)addr, (unsigned long)paddr, + (unsigned long)int128_gethi(val), (unsigned long)int128_getlo(val)); + fflush(mmu_log_file); + } } /* Swap to host endian if necessary, then store. */ if (l.memop & MO_BSWAP) { diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index ecca0f4a8..60c122938 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -13,6 +13,7 @@ #include "exec/translation-block.h" #include "exec/mmap-lock.h" #include "accel/tcg/tb-cpu-state.h" +#include extern int64_t max_delay; extern int64_t max_advance; @@ -141,6 +142,9 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); void tcg_get_stats(AccelState *accel, GString *buf); -extern bool mmu_log_enabled; +extern bool mmu_fast_log_enabled; +extern bool mmu_slow_log_enabled; +extern bool mmu_log_to_file; +extern FILE *mmu_log_file; -#endif /* ACCEL_TCG_INTERNAL_COMMON_H */ \ No newline at end of file +#endif /* ACCEL_TCG_INTERNAL_COMMON_H */ diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index d77b52ac3..baf48c612 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -15,17 +15,89 @@ #include "tcg/tcg.h" #include "internal-common.h" #include "exec/log.h" -#include "qapi/qapi-commands-misc.h" +#include "qapi/qapi-commands-misc.h" +#include + +#define MMU_LOG_FILE_PATH "../vm/mmu.log" + +static bool mmu_open_log_file(Error **errp) +{ + if (mmu_log_to_file && mmu_log_file) { + return true; + } + + mmu_log_file = fopen(MMU_LOG_FILE_PATH, "a"); + if (!mmu_log_file) { + error_setg_errno(errp, errno, + "Could not open MMU log file '%s'", MMU_LOG_FILE_PATH); + return false; + } + mmu_log_to_file = true; + return true; +} + +static void mmu_close_log_file(void) +{ + if (mmu_log_file) { + fclose(mmu_log_file); + mmu_log_file = NULL; + } + mmu_log_to_file = false; +} + +void qmp_sfmmu(Error **errp) +{ + mmu_fast_log_enabled = true; + qemu_log("Fast path MMU write logging enabled.\n"); +} + +void qmp_qfmmu(Error **errp) +{ + mmu_fast_log_enabled = false; + qemu_log("Fast path MMU write logging disabled.\n"); + if (!mmu_slow_log_enabled) { + mmu_close_log_file(); + } +} + +void qmp_ssmmu(Error **errp) +{ + mmu_slow_log_enabled = true; + qemu_log("Slow path MMU write logging enabled.\n"); +} + +void qmp_qsmmu(Error **errp) +{ + mmu_slow_log_enabled = false; + qemu_log("Slow path MMU write logging disabled.\n"); + if (!mmu_fast_log_enabled) { + mmu_close_log_file(); + } +} + +void qmp_wmmu(Error **errp) +{ + if (!mmu_open_log_file(errp)) { + return; + } + + mmu_fast_log_enabled = true; + mmu_slow_log_enabled = true; + qemu_log("MMU write logging enabled (file and console).\n"); +} void qmp_smmu(Error **errp) { - mmu_log_enabled = true; + mmu_fast_log_enabled = true; + mmu_slow_log_enabled = true; qemu_log("MMU write logging enabled.\n"); } void qmp_qmmu(Error **errp) { - mmu_log_enabled = false; + mmu_fast_log_enabled = false; + mmu_slow_log_enabled = false; + mmu_close_log_file(); qemu_log("MMU write logging disabled.\n"); } diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index fa7ed9739..3ea8713fc 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -26,6 +26,12 @@ #include "exec/cpu-common.h" #include "exec/helper-proto-common.h" #include "accel/tcg/getpc.h" +#include "accel/tcg/internal-common.h" +#include "hw/core/cpu.h" +#include "exec/memopidx.h" +#include "exec/tlb-common.h" +#include "exec/tlb-flags.h" +#include "exec/target_page.h" #define HELPER_H "accel/tcg/tcg-runtime.h" #include "exec/helper-info.c.inc" @@ -148,3 +154,122 @@ void HELPER(exit_atomic)(CPUArchState *env) { cpu_loop_exit_atomic(env_cpu(env), GETPC()); } + +void HELPER(log_store_fastpath)(CPUArchState *env, uint64_t addr, + uint64_t value_lo, uint64_t value_hi, + uint32_t oi) +{ +#ifdef CONFIG_USER_ONLY + (void)env; + (void)addr; + (void)value_lo; + (void)value_hi; + (void)oi; + return; +#else + if (!mmu_fast_log_enabled) { + return; + } + + CPUState *cpu = env_cpu(env); + MemOp memop = get_memop(oi); + unsigned size_shift = memop & MO_SIZE; + unsigned size = (size_shift == MO_128) ? 16u : 1u << size_shift; + unsigned mmu_idx = get_mmuidx(oi); + CPUTLBDescFast *fast = &cpu->neg.tlb.f[mmu_idx]; + uintptr_t index_mask = fast->mask >> CPU_TLB_ENTRY_BITS; + + if (fast->table == NULL || index_mask == 0) { + return; + } + + uintptr_t index = (addr >> TARGET_PAGE_BITS) & index_mask; + CPUTLBEntry *entry = &fast->table[index]; + uint64_t tlb_addr = entry->addr_write; + + if (((tlb_addr ^ addr) & TARGET_PAGE_MASK) || + (tlb_addr & TLB_INVALID_MASK)) { + return; + } + + CPUTLBEntryFull *full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; + hwaddr phys = full->phys_addr + (addr & ~TARGET_PAGE_MASK); + + switch (size) { + case 1: + printf("[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=1 data=0x%02" PRIx64 "\n", + addr, phys, value_lo & UINT8_MAX); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=1 data=0x%02" PRIx64 "\n", + addr, phys, value_lo & UINT8_MAX); + fflush(mmu_log_file); + } + break; + case 2: + printf("[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=2 data=0x%04" PRIx64 "\n", + addr, phys, value_lo & UINT16_MAX); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=2 data=0x%04" PRIx64 "\n", + addr, phys, value_lo & UINT16_MAX); + fflush(mmu_log_file); + } + break; + case 4: + printf("[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=4 data=0x%08" PRIx64 "\n", + addr, phys, value_lo & UINT32_MAX); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=4 data=0x%08" PRIx64 "\n", + addr, phys, value_lo & UINT32_MAX); + fflush(mmu_log_file); + } + break; + case 8: + printf("[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=8 data=0x%016" PRIx64 "\n", + addr, phys, value_lo); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=8 data=0x%016" PRIx64 "\n", + addr, phys, value_lo); + fflush(mmu_log_file); + } + break; + case 16: + printf("[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=16 data=0x%016" PRIx64 + "%016" PRIx64 "\n", + addr, phys, value_hi, value_lo); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=16 data=0x%016" PRIx64 + "%016" PRIx64 "\n", + addr, phys, value_hi, value_lo); + fflush(mmu_log_file); + } + break; + default: + printf("[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=%u data=0x%016" PRIx64 "\n", + addr, phys, size, value_lo); + if (mmu_log_to_file && mmu_log_file) { + fprintf(mmu_log_file, + "[FAST_MEMORY_WRITE] vaddr=0x%016" PRIx64 + " paddr=0x%016" PRIx64 " size=%u data=0x%016" PRIx64 "\n", + addr, phys, size, value_lo); + fflush(mmu_log_file); + } + break; + } +#endif +} diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 8436599b9..276fbc050 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -28,6 +28,9 @@ DEF_HELPER_FLAGS_1(lookup_tb_ptr, TCG_CALL_NO_WG_SE, cptr, env) DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env) +DEF_HELPER_FLAGS_5(log_store_fastpath, TCG_CALL_NO_RWG, void, + env, i64, i64, i64, i32) + #ifndef IN_HELPER_PROTO /* * Pass calls to memset directly to libc, without a thunk in qemu. diff --git a/qapi/misc.json b/qapi/misc.json index 780ce4703..5d68c3526 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -612,9 +612,55 @@ 'data': { 'cpu': 'int', 'percent': 'int', 'period-ms': 'int' } } ## +# @sfmmu: +# +# Enable fast-path MMU write logging. +# +# Since: 9.1 +## +{ 'command': 'sfmmu' } + +## +# @qfmmu: +# +# Disable fast-path MMU write logging. +# +# Since: 9.1 +## +{ 'command': 'qfmmu' } + +## +# @ssmmu: +# +# Enable slow-path MMU write logging. +# +# Since: 9.1 +## +{ 'command': 'ssmmu' } + +## +# @qsmmu: +# +# Disable slow-path MMU write logging. +# +# Since: 9.1 +## +{ 'command': 'qsmmu' } + +## +# @wmmu: +# +# Enable logging of both fast-path and slow-path MMU writes to a log file +# located at ../vm/mmu.log (relative to the QEMU working directory). +# +# Since: 9.1 +## +{ 'command': 'wmmu' } + +## # @smmu: # -# Enable MMU logging. +# Enable both fast-path and slow-path MMU write logging (legacy alias). # # Since: 9.1 ## @@ -623,8 +669,8 @@ ## # @qmmu: # -# Disable MMU logging. +# Disable both fast-path and slow-path MMU write logging (legacy alias). # # Since: 9.1 ## -{ 'command': 'qmmu' } \ No newline at end of file +{ 'command': 'qmmu' } diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index ee2726686..ebd2bdd2a 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -42,6 +42,11 @@ # define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_BY_REF #endif +#if !defined(CONFIG_USER_ONLY) && TCG_TARGET_REG_BITS == 64 && !defined(_WIN64) +struct CPUArchState; +extern TCGHelperInfo info_helper_log_store_fastpath; +#endif + #ifdef CONFIG_DEBUG_TCG static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { #if TCG_TARGET_REG_BITS == 64 @@ -2005,6 +2010,106 @@ typedef struct { TCGAtomAlign aa; } HostAddress; +#if !defined(CONFIG_USER_ONLY) && TCG_TARGET_REG_BITS == 64 && !defined(_WIN64) +static void add_saved_reg(TCGReg *saved, int *saved_count, TCGReg reg) +{ + if (reg < 0) { + return; + } + for (int i = 0; i < *saved_count; i++) { + if (saved[i] == reg) { + return; + } + } + saved[(*saved_count)++] = reg; +} + +static void tcg_out_fastpath_store_log(TCGContext *s, const HostAddress *h, + TCGReg datalo, TCGReg datahi, + TCGReg addr_reg, MemOpIdx oi) +{ + if (!tcg_use_softmmu) { + return; + } + + TCGReg saved[8]; + int saved_count = 0; + + add_saved_reg(saved, &saved_count, datalo); + add_saved_reg(saved, &saved_count, datahi); + add_saved_reg(saved, &saved_count, h->base); + add_saved_reg(saved, &saved_count, h->index); + add_saved_reg(saved, &saved_count, addr_reg); + + for (int i = 0; i < saved_count; ++i) { + tcg_out_push(s, saved[i]); + } + + bool adjust_stack = (saved_count & 1) != 0; + if (adjust_stack) { + tcg_out_addi(s, TCG_REG_CALL_STACK, -8); + } + + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_RDI, TCG_AREG0); + + if (addr_reg >= 0) { + TCGType addr_type = s->addr_type <= TCG_TYPE_I32 ? TCG_TYPE_I32 + : TCG_TYPE_I64; + tcg_out_mov(s, addr_type, TCG_REG_RSI, addr_reg); + if (addr_type == TCG_TYPE_I32) { + tcg_out_ext32u(s, TCG_REG_RSI, TCG_REG_RSI); + } + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RSI, 0); + } + + MemOp memop = get_memop(oi); + TCGType val_type = (memop & MO_SIZE) <= MO_32 ? TCG_TYPE_I32 + : TCG_TYPE_I64; + + if (datalo >= 0) { + tcg_out_mov(s, val_type, TCG_REG_RDX, datalo); + if (val_type == TCG_TYPE_I32) { + tcg_out_ext32u(s, TCG_REG_RDX, TCG_REG_RDX); + } + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDX, 0); + } + + if ((memop & MO_SIZE) == MO_128 && datahi >= 0) { + tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_RCX, datahi); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RCX, 0); + } + + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R8, oi); + + tcg_out_call(s, (const tcg_insn_unit *)helper_log_store_fastpath, + &info_helper_log_store_fastpath); + + if (adjust_stack) { + tcg_out_addi(s, TCG_REG_CALL_STACK, 8); + } + + for (int i = saved_count - 1; i >= 0; i--) { + tcg_out_pop(s, saved[i]); + } +} +#else +static inline void tcg_out_fastpath_store_log(TCGContext *s, + const HostAddress *h, + TCGReg datalo, TCGReg datahi, + TCGReg addr_reg, MemOpIdx oi) +{ + (void)s; + (void)h; + (void)datalo; + (void)datahi; + (void)addr_reg; + (void)oi; +} +#endif + bool tcg_target_has_memory_bswap(MemOp memop) { TCGAtomAlign aa; @@ -2466,11 +2571,14 @@ static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { }; static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, - HostAddress h, MemOp memop) + HostAddress h, TCGReg addr, MemOpIdx oi) { + MemOp memop = get_memop(oi); bool use_movbe = false; int movop = OPC_MOVL_EvGv; + tcg_out_fastpath_store_log(s, &h, datalo, datahi, addr, oi); + /* * Do big-endian stores with movbe or system-mode. * User-only without movbe will have its swapping done generically. @@ -2582,7 +2690,7 @@ static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data, HostAddress h; ldst = prepare_host_addr(s, &h, addr, oi, false); - tcg_out_qemu_st_direct(s, data, -1, h, get_memop(oi)); + tcg_out_qemu_st_direct(s, data, -1, h, addr, oi); if (ldst) { ldst->type = type; @@ -2612,7 +2720,7 @@ static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, HostAddress h; ldst = prepare_host_addr(s, &h, addr, oi, false); - tcg_out_qemu_st_direct(s, datalo, datahi, h, get_memop(oi)); + tcg_out_qemu_st_direct(s, datalo, datahi, h, addr, oi); if (ldst) { ldst->type = type;