From: Quan Sun <[email protected]> Backport upstream commit 854cd16e318e ("accel/tcg: Fix iotlb_to_section() for different AddressSpace") to qemu 10.2.0.
The bug causes incorrect memory load/store when CPU access goes through an IOMMUMemoryRegion that returns a different target AddressSpace, and the fix replaces the section_index lookup with a direct MemoryRegionSection pointer stored in CPUTLBEntryFull. Note that the fix primarily targets ARM/RISC-V, but since it eliminates iotlb_to_section() and performs the lookup based on CPUTLBEntryFull, it may also help address some currently observed QEMU boot issues on x86, e.g. the https://bugzilla.yoctoproject.org/show_bug.cgi?id=16259. AI-Generated: kiro-cli Signed-off-by: Quan Sun <[email protected]> --- meta/recipes-devtools/qemu/qemu.inc | 1 + ...tlb_to_section-for-different-Address.patch | 274 ++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 meta/recipes-devtools/qemu/qemu/0001-accel-tcg-Fix-iotlb_to_section-for-different-Address.patch diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc index 7aa593bc5d..a8b4a1a541 100644 --- a/meta/recipes-devtools/qemu/qemu.inc +++ b/meta/recipes-devtools/qemu/qemu.inc @@ -33,6 +33,7 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \ file://0010-configure-lookup-meson-exutable-from-PATH.patch \ file://0011-qemu-Ensure-pip-and-the-python-venv-aren-t-used-for-.patch \ file://0001-linux-user-elfload.c-Correction-to-HWCAP2-accessor.patch \ + file://0001-accel-tcg-Fix-iotlb_to_section-for-different-Address.patch \ file://qemu-guest-agent.init \ file://qemu-guest-agent.udev \ " diff --git a/meta/recipes-devtools/qemu/qemu/0001-accel-tcg-Fix-iotlb_to_section-for-different-Address.patch b/meta/recipes-devtools/qemu/qemu/0001-accel-tcg-Fix-iotlb_to_section-for-different-Address.patch new file mode 100644 index 0000000000..d19f872fc3 --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/0001-accel-tcg-Fix-iotlb_to_section-for-different-Address.patch @@ -0,0 +1,274 @@ +From 858e6bb252e075e09cca6e78299151d3af0bf5fb Mon Sep 17 00:00:00 2001 +From: Quan Sun <[email protected]> +Date: Tue, 28 Apr 2026 14:56:36 -0400 +Subject: [PATCH] accel/tcg: Fix iotlb_to_section() for different AddressSpace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +'CPUTLBEntryFull.xlat_section' stores section_index in last 12 bits to +find the correct section when CPU access the IO region over the IOTLB. +However, section_index is only unique inside single AddressSpace. If +address space translation is over IOMMUMemoryRegion, it could return +section from other AddressSpace. 'iotlb_to_section()' API only finds the +sections from CPU's AddressSpace so that it couldn't find section in +other AddressSpace. Thus, using 'iotlb_to_section()' API will find the +wrong section and QEMU will have wrong load/store access. + +To fix this bug of iotlb_to_section(), store complete MemoryRegionSection +pointer in CPUTLBEntryFull to replace the section_index in xlat_section. +Rename 'xlat_section' to 'xlat_offset' as we remove last 12 bits +section_index inside. Also, since we directly use section pointer in the +CPUTLBEntryFull (full->section), we can remove the unused functions: +iotlb_to_section(), memory_region_section_get_iotlb(). + +This bug occurs only when +(1) IOMMUMemoryRegion is in the path of CPU access. +(2) IOMMUMemoryRegion returns different target_as and the section is in +the IO region. + +This patch incorporates prerequisite changes from upstream commit +94c6e9cf0440 ("accel/tcg: Send the CPUTLBEntryFull struct into +io_prepare()") needed for the fix to apply cleanly. + +Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/854cd16e318eed12de2995014b28d9f374c64bf7] + +Signed-off-by: Jim Shu <[email protected]> +Reviewed-by: Philippe Mathieu-Daudé <[email protected]> +Tested-by: Mark Burton <[email protected]> +Reviewed-by: Pierrick Bouvier <[email protected]> +Signed-off-by: Philippe Mathieu-Daudé <[email protected]> +Signed-off-by: Quan Sun <[email protected]> +--- + accel/tcg/cputlb.c | 32 +++++++++++++++----------------- + include/accel/tcg/iommu.h | 15 --------------- + include/exec/cputlb.h | 4 ++-- + include/hw/core/cpu.h | 17 +++++++++-------- + system/physmem.c | 25 ------------------------- + 5 files changed, 26 insertions(+), 67 deletions(-) + +diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c +index fd1606c85..fa0f4d8b3 100644 +--- a/accel/tcg/cputlb.c ++++ b/accel/tcg/cputlb.c +@@ -1089,7 +1089,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, + } + } else { + /* I/O or ROMD */ +- iotlb = memory_region_section_get_iotlb(cpu, section) + xlat; ++ iotlb = xlat; + /* + * Writes to romd devices must go through MMIO to enable write. + * Reads to romd devices go through the ram_ptr found above, +@@ -1140,10 +1140,9 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, + /* + * When memory region is ram, iotlb contains a TARGET_PAGE_BITS + * aligned ram_addr_t of the page base of the target RAM. +- * Otherwise, iotlb contains +- * - a physical section number in the lower TARGET_PAGE_BITS +- * - the offset within section->mr of the page base (I/O, ROMD) with the +- * TARGET_PAGE_BITS masked off. ++ * Otherwise, iotlb contains a TARGET_PAGE_BITS aligned ++ * offset within section->mr of the page base (I/O, ROMD) ++ * + * We subtract addr_page (which is page aligned and thus won't + * disturb the low bits) to give an offset which can be added to the + * (non-page-aligned) vaddr of the eventual memory access to get +@@ -1153,7 +1152,8 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, + */ + desc->fulltlb[index] = *full; + full = &desc->fulltlb[index]; +- full->xlat_section = iotlb - addr_page; ++ full->xlat_offset = iotlb - addr_page; ++ full->section = section; + full->phys_addr = paddr_page; + + /* Now calculate the new entry */ +@@ -1269,14 +1269,14 @@ static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr, + } + + static MemoryRegionSection * +-io_prepare(hwaddr *out_offset, CPUState *cpu, hwaddr xlat, ++io_prepare(hwaddr *out_offset, CPUState *cpu, CPUTLBEntryFull *full, + MemTxAttrs attrs, vaddr addr, uintptr_t retaddr) + { + MemoryRegionSection *section; + hwaddr mr_offset; + +- section = iotlb_to_section(cpu, xlat, attrs); +- mr_offset = (xlat & TARGET_PAGE_MASK) + addr; ++ section = full->section; ++ mr_offset = full->xlat_offset + addr; + cpu->mem_io_pc = retaddr; + if (!cpu->neg.can_do_io) { + cpu_io_recompile(cpu, retaddr); +@@ -1335,7 +1335,7 @@ static bool victim_tlb_hit(CPUState *cpu, size_t mmu_idx, size_t index, + static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, + CPUTLBEntryFull *full, uintptr_t retaddr) + { +- ram_addr_t ram_addr = mem_vaddr + full->xlat_section; ++ ram_addr_t ram_addr = mem_vaddr + full->xlat_offset; + + trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size); + +@@ -1592,9 +1592,7 @@ bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, + + /* We must have an iotlb entry for MMIO */ + if (tlb_addr & TLB_MMIO) { +- MemoryRegionSection *section = +- iotlb_to_section(cpu, full->xlat_section & ~TARGET_PAGE_MASK, +- full->attrs); ++ MemoryRegionSection *section = full->section; + data->is_io = true; + data->mr = section->mr; + } else { +@@ -1980,7 +1978,7 @@ static uint64_t do_ld_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, + tcg_debug_assert(size > 0 && size <= 8); + + attrs = full->attrs; +- section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); ++ section = io_prepare(&mr_offset, cpu, full, attrs, addr, ra); + mr = section->mr; + + BQL_LOCK_GUARD(); +@@ -2001,7 +1999,7 @@ static Int128 do_ld16_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, + tcg_debug_assert(size > 8 && size <= 16); + + attrs = full->attrs; +- section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); ++ section = io_prepare(&mr_offset, cpu, full, attrs, addr, ra); + mr = section->mr; + + BQL_LOCK_GUARD(); +@@ -2521,7 +2519,7 @@ static uint64_t do_st_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, + tcg_debug_assert(size > 0 && size <= 8); + + attrs = full->attrs; +- section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); ++ section = io_prepare(&mr_offset, cpu, full, attrs, addr, ra); + mr = section->mr; + + BQL_LOCK_GUARD(); +@@ -2541,7 +2539,7 @@ static uint64_t do_st16_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, + tcg_debug_assert(size > 8 && size <= 16); + + attrs = full->attrs; +- section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); ++ section = io_prepare(&mr_offset, cpu, full, attrs, addr, ra); + mr = section->mr; + + BQL_LOCK_GUARD(); +diff --git a/include/accel/tcg/iommu.h b/include/accel/tcg/iommu.h +index 90cfd6c0e..547f8ea0e 100644 +--- a/include/accel/tcg/iommu.h ++++ b/include/accel/tcg/iommu.h +@@ -14,18 +14,6 @@ + #include "exec/hwaddr.h" + #include "exec/memattrs.h" + +-/** +- * iotlb_to_section: +- * @cpu: CPU performing the access +- * @index: TCG CPU IOTLB entry +- * +- * Given a TCG CPU IOTLB entry, return the MemoryRegionSection that +- * it refers to. @index will have been initially created and returned +- * by memory_region_section_get_iotlb(). +- */ +-MemoryRegionSection *iotlb_to_section(CPUState *cpu, +- hwaddr index, MemTxAttrs attrs); +- + MemoryRegionSection *address_space_translate_for_iotlb(CPUState *cpu, + int asidx, + hwaddr addr, +@@ -34,8 +22,5 @@ MemoryRegionSection *address_space_translate_for_iotlb(CPUState *cpu, + MemTxAttrs attrs, + int *prot); + +-hwaddr memory_region_section_get_iotlb(CPUState *cpu, +- MemoryRegionSection *section); +- + #endif + +diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h +index 9bec0e789..16f866990 100644 +--- a/include/exec/cputlb.h ++++ b/include/exec/cputlb.h +@@ -43,8 +43,8 @@ void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length); + * @full: the details of the tlb entry + * + * Add an entry to @cpu tlb index @mmu_idx. All of the fields of +- * @full must be filled, except for xlat_section, and constitute +- * the complete description of the translated page. ++ * @full must be filled, except for xlat_offset & section, and ++ * constitute the complete description of the translated page. + * + * This is generally called by the target tlb_fill function after + * having performed a successful page table walk to find the physical +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index 961505177..a3db3f66f 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -214,15 +214,16 @@ typedef uint32_t MMUIdxMap; + */ + struct CPUTLBEntryFull { + /* +- * @xlat_section contains: +- * - in the lower TARGET_PAGE_BITS, a physical section number +- * - with the lower TARGET_PAGE_BITS masked off, an offset which +- * must be added to the virtual address to obtain: +- * + the ram_addr_t of the target RAM (if the physical section +- * number is PHYS_SECTION_NOTDIRTY or PHYS_SECTION_ROM) +- * + the offset within the target MemoryRegion (otherwise) ++ * @xlat_offset: TARGET_PAGE_BITS aligned offset which must be added to ++ * the virtual address to obtain: ++ * + the ram_addr_t of the target RAM (if the physical section ++ * number is PHYS_SECTION_NOTDIRTY or PHYS_SECTION_ROM) ++ * + the offset within the target MemoryRegion (otherwise) + */ +- hwaddr xlat_section; ++ hwaddr xlat_offset; ++ ++ /* @section contains physical section. */ ++ MemoryRegionSection *section; + + /* + * @phys_addr contains the physical address in the address space +diff --git a/system/physmem.c b/system/physmem.c +index c9869e404..a21e7ca64 100644 +--- a/system/physmem.c ++++ b/system/physmem.c +@@ -748,31 +748,6 @@ translate_fail: + return &d->map.sections[PHYS_SECTION_UNASSIGNED]; + } + +-MemoryRegionSection *iotlb_to_section(CPUState *cpu, +- hwaddr index, MemTxAttrs attrs) +-{ +- int asidx = cpu_asidx_from_attrs(cpu, attrs); +- CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx]; +- AddressSpaceDispatch *d = address_space_to_dispatch(cpuas->as); +- int section_index = index & ~TARGET_PAGE_MASK; +- MemoryRegionSection *ret; +- +- assert(section_index < d->map.sections_nb); +- ret = d->map.sections + section_index; +- assert(ret->mr); +- assert(ret->mr->ops); +- +- return ret; +-} +- +-/* Called from RCU critical section */ +-hwaddr memory_region_section_get_iotlb(CPUState *cpu, +- MemoryRegionSection *section) +-{ +- AddressSpaceDispatch *d = flatview_to_dispatch(section->fv); +- return section - d->map.sections; +-} +- + #endif /* CONFIG_TCG */ + + void cpu_address_space_init(CPUState *cpu, int asidx, +-- +2.43.0 -- 2.49.0
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#236838): https://lists.openembedded.org/g/openembedded-core/message/236838 Mute This Topic: https://lists.openembedded.org/mt/119264493/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
