From: David Hildenbrand <da...@redhat.com> Right now, we only allow for writing to memory regions that allow direct access using memcpy etc; all other writes are simply ignored. This implies that debugging guests will not work as expected when writing to MMIO device regions.
Let's extend cpu_memory_rw_debug() to write to more memory regions, including MMIO device regions. Reshuffle the condition in memory_access_is_direct() to make it easier to read and add a comment. While this change implies that debug access can now also write to MMIO devices, we now are also permit ELF image loads and similar users of cpu_memory_rw_debug() to write to MMIO devices; currently we ignore these writes. Peter assumes [1] that there's probably a class of guest images, which will start writing junk (likely zeroes) into device model registers; we previously would silently ignore any such bogus ELF sections. Likely these images are of questionable correctness and this can be ignored. If ever a problem, we could make these cases use address_space_write_rom() instead, which is left unchanged for now. This patch is based on previous work by Stefan Zabka. [1] https://lore.kernel.org/all/CAFEAcA_2CEJKFyjvbwmpt=on=GgMVamQ5hiiVt+zUr6AY3X=x...@mail.gmail.com/ Resolves: https://gitlab.com/qemu-project/qemu/-/issues/213 Reviewed-by: Peter Xu <pet...@redhat.com> Signed-off-by: David Hildenbrand <da...@redhat.com> Link: https://lore.kernel.org/r/20250210084648.33798-8-da...@redhat.com Signed-off-by: Peter Xu <pet...@redhat.com> --- include/exec/memattrs.h | 5 ++++- include/exec/memory.h | 3 ++- hw/core/cpu-system.c | 13 +++++++++---- system/physmem.c | 9 ++------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h index 060b7e7131..8db1d30464 100644 --- a/include/exec/memattrs.h +++ b/include/exec/memattrs.h @@ -44,6 +44,8 @@ typedef struct MemTxAttrs { * (see MEMTX_ACCESS_ERROR). */ unsigned int memory:1; + /* Debug access that can even write to ROM. */ + unsigned int debug:1; /* Requester ID (for MSI for example) */ unsigned int requester_id:16; @@ -56,7 +58,8 @@ typedef struct MemTxAttrs { * Bus masters which don't specify any attributes will get this * (via the MEMTXATTRS_UNSPECIFIED constant), so that we can * distinguish "all attributes deliberately clear" from - * "didn't specify" if necessary. + * "didn't specify" if necessary. "debug" can be set alongside + * "unspecified". */ bool unspecified; diff --git a/include/exec/memory.h b/include/exec/memory.h index b18ecf933e..78c4e0aec8 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -3018,7 +3018,8 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write, if (!memory_region_supports_direct_access(mr)) { return false; } - if (is_write) { + /* Debug access can write to ROM. */ + if (is_write && !attrs.debug) { return !mr->readonly && !mr->rom_device; } return true; diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index 6aae28a349..6e307c8959 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -51,13 +51,18 @@ hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, MemTxAttrs *attrs) { CPUClass *cc = CPU_GET_CLASS(cpu); + hwaddr paddr; if (cc->sysemu_ops->get_phys_page_attrs_debug) { - return cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs); + paddr = cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs); + } else { + /* Fallback for CPUs which don't implement the _attrs_ hook */ + *attrs = MEMTXATTRS_UNSPECIFIED; + paddr = cc->sysemu_ops->get_phys_page_debug(cpu, addr); } - /* Fallback for CPUs which don't implement the _attrs_ hook */ - *attrs = MEMTXATTRS_UNSPECIFIED; - return cc->sysemu_ops->get_phys_page_debug(cpu, addr); + /* Indicate that this is a debug access. */ + attrs->debug = 1; + return paddr; } hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr) diff --git a/system/physmem.c b/system/physmem.c index 8745c10c9d..d3efdf13d3 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3680,13 +3680,8 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, if (l > len) l = len; phys_addr += (addr & ~TARGET_PAGE_MASK); - if (is_write) { - res = address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr, - attrs, buf, l); - } else { - res = address_space_read(cpu->cpu_ases[asidx].as, phys_addr, - attrs, buf, l); - } + res = address_space_rw(cpu->cpu_ases[asidx].as, phys_addr, attrs, buf, + l, is_write); if (res != MEMTX_OK) { return -1; } -- 2.47.0