* [PATCH] hw/block/pflash: invalidate TBs on flash update @ 2026-10-16 19:15 Elliot Berman 2026-10-26 6:03 ` Philippe Mathieu-Daudé 0 siblings, 1 reply; 4+ messages in thread From: Elliot Berman @ 2026-10-16 19:15 UTC (permalink / raw) To: qemu-devel Cc: Philippe Mathieu-Daudé, Kevin Wolf, Hanna Reitz, Paolo Bonzini, Peter Xu, qemu-block, Alex Bennée, Elliot Berman When pflash_cfi01/02 are out of Read Array mode and being reprogrammed or erased (such as a firmware update) by a guest under TCG, TBs from when the guest was executing instructions from the pflash are never invalidated. After re-enabling Read Array, the guest continues to execute instructions from the stale TBs. Call memory_region_flush_rom_device() from pflash_update() so the TBs over the updated range are invalidated. memory_region_flush_rom_device() asserted that the memory region was in romd_mode (i.e. Read Array mode), but the pflash is not in romd_mode when processing MemoryRegionOps->write() commands. Since the RAM can change even when !romd_mode, relax the assertion so it only checks rom_device. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4490 Suggested-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Elliot Berman <elliotjb+anduril@elliotjb.com> --- hw/block/pflash_cfi01.c | 5 ++++- hw/block/pflash_cfi02.c | 3 +++ system/physmem.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 486fc6350d..66ecdb0969 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -388,12 +388,15 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, return ret; } -/* update flash content on disk */ +/* update flash content on disk and invalidate the guest view of RAM */ static void pflash_update(PFlashCFI01 *pfl, int offset, int size) { int offset_end; int ret; + + memory_region_flush_rom_device(&pfl->mem, offset, size); + if (pfl->blk) { offset_end = offset + size; /* widen to sector boundaries */ diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 4f72c438c0..22b27366ee 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -419,6 +419,9 @@ static void pflash_update(PFlashCFI02 *pfl, int offset, int size) { int offset_end; int ret; + + memory_region_flush_rom_device(&pfl->orig_mem, offset, size); + if (pfl->blk) { offset_end = offset + size; /* widen to sector boundaries */ diff --git a/system/physmem.c b/system/physmem.c index db3dda563d..c532e29571 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3162,7 +3162,7 @@ void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size) * necessary. Other memory regions should use the * address_space_read/write() APIs. */ - assert(memory_region_is_romd(mr)); + assert(mr->rom_device); invalidate_and_set_dirty(mr, addr, size); } --- base-commit: 7e8d3c7fc460fe7cd28a3e423d7466fa292bc269 change-id: 20261015-pflash-update-invalidate-tbs-7d7e9fa3a3cf Best regards, -- Elliot Berman <elliotjb+anduril@elliotjb.com> ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] hw/block/pflash: invalidate TBs on flash update 2026-10-16 19:15 [PATCH] hw/block/pflash: invalidate TBs on flash update Elliot Berman @ 2026-10-26 6:03 ` Philippe Mathieu-Daudé 2026-10-26 21:02 ` Fabiano Rosas 0 siblings, 1 reply; 4+ messages in thread From: Philippe Mathieu-Daudé @ 2026-10-26 6:03 UTC (permalink / raw) To: Elliot Berman, qemu-devel, Fabiano Rosas, Peter Xu Cc: Kevin Wolf, Hanna Reitz, Paolo Bonzini, qemu-block, Alex Bennée Hi Elliot, On 16/10/26 21:15, Elliot Berman wrote: > When pflash_cfi01/02 are out of Read Array mode and being reprogrammed > or erased (such as a firmware update) by a guest under TCG, TBs from > when the guest was executing instructions from the pflash are never > invalidated. After re-enabling Read Array, the guest continues to > execute instructions from the stale TBs. > > Call memory_region_flush_rom_device() from pflash_update() so the TBs > over the updated range are invalidated. > > memory_region_flush_rom_device() asserted that the memory region was in > romd_mode (i.e. Read Array mode), but the pflash is not in romd_mode > when processing MemoryRegionOps->write() commands. Since the RAM can > change even when !romd_mode, relax the assertion so it only checks > rom_device. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4490 > Suggested-by: Alex Bennée <alex.bennee@linaro.org> > Signed-off-by: Elliot Berman <elliotjb+anduril@elliotjb.com> > --- > hw/block/pflash_cfi01.c | 5 ++++- > hw/block/pflash_cfi02.c | 3 +++ > system/physmem.c | 2 +- > 3 files changed, 8 insertions(+), 2 deletions(-) > > diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c > index 486fc6350d..66ecdb0969 100644 > --- a/hw/block/pflash_cfi01.c > +++ b/hw/block/pflash_cfi01.c > @@ -388,12 +388,15 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, > return ret; > } > > -/* update flash content on disk */ > +/* update flash content on disk and invalidate the guest view of RAM */ /* * Flush modified flash content: mark the range dirty, invalidate the * TBs translated from it, and write it back to the block backend. */ > static void pflash_update(PFlashCFI01 *pfl, int offset, > int size) > { > int offset_end; > int ret; > + > + memory_region_flush_rom_device(&pfl->mem, offset, size); > + > if (pfl->blk) { > offset_end = offset + size; > /* widen to sector boundaries */ I'd like feedback from migration maintainers: could we be writing staled content during live migration? Or maybe we are already safe. invalidate_and_set_dirty() gets DIRTY_MEMORY_MIGRATION set via the memory_region_get_dirty_log_mask call. Hmm so this change also fixes migration then. If confirmed, worth mentioning in the patch description: Direct writes to the flash RAM were not marked dirty for migration, so pages reprogrammed during pre-copy were not re-sent, and postload_update_cb() wrote the stale content to the block backend. The memory_region_flush_rom_device() call now also fixes this. > diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c > index 4f72c438c0..22b27366ee 100644 > --- a/hw/block/pflash_cfi02.c > +++ b/hw/block/pflash_cfi02.c > @@ -419,6 +419,9 @@ static void pflash_update(PFlashCFI02 *pfl, int offset, int size) Same comment update missing: /* * Flush modified flash content: mark the range dirty, invalidate the * TBs translated from it, and write it back to the block backend. */ > { > int offset_end; > int ret; > + > + memory_region_flush_rom_device(&pfl->orig_mem, offset, size); > + > if (pfl->blk) { > offset_end = offset + size; > /* widen to sector boundaries */ > diff --git a/system/physmem.c b/system/physmem.c > index db3dda563d..c532e29571 100644 > --- a/system/physmem.c > +++ b/system/physmem.c > @@ -3162,7 +3162,7 @@ void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size) > * necessary. Other memory regions should use the > * address_space_read/write() APIs. * The ROMD mode is not checked: the RAM backing a ROM device can be * modified while the region is in MMIO mode. > */ > - assert(memory_region_is_romd(mr)); > + assert(mr->rom_device); > > invalidate_and_set_dirty(mr, addr, size); > } We need to update the API contract: -- >8 -- /** * memory_region_flush_rom_device: Mark a range of pages dirty and invalidate * TBs (for self-modifying code). * * The MemoryRegionOps->write() callback of a ROM device must use this function * to mark byte ranges that have been modified internally, such as by directly * accessing the memory returned by memory_region_get_ram_ptr(). * + * This function may be called whether or not the region is in ROMD mode: + * a device that leaves ROMD mode (see memory_region_rom_device_set_romd()) + * while it is being programmed must still flush the modified range, so that + * translations created before ROMD mode was left are not reused once it is + * entered again. + * * This function marks the range dirty and invalidates TBs so that TCG can * detect self-modifying code. * - * @mr: the region being flushed. + * @mr: the region being flushed; must be a ROM device. * @addr: the start, relative to the start of the region, of the range being * flushed. * @size: the size, in bytes, of the range being flushed. */ --- Please split this patch in 2, first the memory_region_flush_rom_device change then the pflash ones (2 distinct subsystems, better to bisect or partially cherry-pick). Change LGTM otherwise! Regards, Phil. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] hw/block/pflash: invalidate TBs on flash update 2026-10-26 6:03 ` Philippe Mathieu-Daudé @ 2026-10-26 21:02 ` Fabiano Rosas 2026-10-27 3:30 ` Philippe Mathieu-Daudé 0 siblings, 1 reply; 4+ messages in thread From: Fabiano Rosas @ 2026-10-26 21:02 UTC (permalink / raw) To: Philippe Mathieu-Daudé, Elliot Berman, qemu-devel, Peter Xu Cc: Kevin Wolf, Hanna Reitz, Paolo Bonzini, qemu-block, Alex Bennée Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> writes: > Hi Elliot, > > On 16/10/26 21:15, Elliot Berman wrote: >> When pflash_cfi01/02 are out of Read Array mode and being reprogrammed >> or erased (such as a firmware update) by a guest under TCG, TBs from >> when the guest was executing instructions from the pflash are never >> invalidated. After re-enabling Read Array, the guest continues to >> execute instructions from the stale TBs. >> >> Call memory_region_flush_rom_device() from pflash_update() so the TBs >> over the updated range are invalidated. >> >> memory_region_flush_rom_device() asserted that the memory region was in >> romd_mode (i.e. Read Array mode), but the pflash is not in romd_mode >> when processing MemoryRegionOps->write() commands. Since the RAM can >> change even when !romd_mode, relax the assertion so it only checks >> rom_device. >> >> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4490 >> Suggested-by: Alex Bennée <alex.bennee@linaro.org> >> Signed-off-by: Elliot Berman <elliotjb+anduril@elliotjb.com> >> --- >> hw/block/pflash_cfi01.c | 5 ++++- >> hw/block/pflash_cfi02.c | 3 +++ >> system/physmem.c | 2 +- >> 3 files changed, 8 insertions(+), 2 deletions(-) >> >> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c >> index 486fc6350d..66ecdb0969 100644 >> --- a/hw/block/pflash_cfi01.c >> +++ b/hw/block/pflash_cfi01.c >> @@ -388,12 +388,15 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, >> return ret; >> } >> >> -/* update flash content on disk */ >> +/* update flash content on disk and invalidate the guest view of RAM */ > > /* > * Flush modified flash content: mark the range dirty, invalidate the > * TBs translated from it, and write it back to the block backend. > */ > >> static void pflash_update(PFlashCFI01 *pfl, int offset, >> int size) >> { >> int offset_end; >> int ret; >> + >> + memory_region_flush_rom_device(&pfl->mem, offset, size); >> + >> if (pfl->blk) { >> offset_end = offset + size; >> /* widen to sector boundaries */ > > I'd like feedback from migration maintainers: could we be writing > staled content during live migration? Or maybe we are already safe. > invalidate_and_set_dirty() gets DIRTY_MEMORY_MIGRATION set via the > memory_region_get_dirty_log_mask call. Hmm so this change also fixes > migration then. If confirmed, worth mentioning in the patch description: > > > Direct writes to the flash RAM were not marked dirty for migration, > so pages reprogrammed during pre-copy were not re-sent, and > postload_update_cb() wrote the stale content to the block backend. > The memory_region_flush_rom_device() call now also fixes this. > Yes, this does seem to be the case. I couldn't find any path where the writes from pflash_write() are invalidated. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] hw/block/pflash: invalidate TBs on flash update 2026-10-26 21:02 ` Fabiano Rosas @ 2026-10-27 3:30 ` Philippe Mathieu-Daudé 0 siblings, 0 replies; 4+ messages in thread From: Philippe Mathieu-Daudé @ 2026-10-27 3:30 UTC (permalink / raw) To: Fabiano Rosas, Elliot Berman, qemu-devel, Peter Xu Cc: Kevin Wolf, Hanna Reitz, Paolo Bonzini, qemu-block, Alex Bennée On 26/10/26 22:02, Fabiano Rosas wrote: > Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> writes: > >> Hi Elliot, >> >> On 16/10/26 21:15, Elliot Berman wrote: >>> When pflash_cfi01/02 are out of Read Array mode and being reprogrammed >>> or erased (such as a firmware update) by a guest under TCG, TBs from >>> when the guest was executing instructions from the pflash are never >>> invalidated. After re-enabling Read Array, the guest continues to >>> execute instructions from the stale TBs. >>> >>> Call memory_region_flush_rom_device() from pflash_update() so the TBs >>> over the updated range are invalidated. >>> >>> memory_region_flush_rom_device() asserted that the memory region was in >>> romd_mode (i.e. Read Array mode), but the pflash is not in romd_mode >>> when processing MemoryRegionOps->write() commands. Since the RAM can >>> change even when !romd_mode, relax the assertion so it only checks >>> rom_device. >>> >>> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4490 >>> Suggested-by: Alex Bennée <alex.bennee@linaro.org> >>> Signed-off-by: Elliot Berman <elliotjb+anduril@elliotjb.com> >>> --- >>> hw/block/pflash_cfi01.c | 5 ++++- >>> hw/block/pflash_cfi02.c | 3 +++ >>> system/physmem.c | 2 +- >>> 3 files changed, 8 insertions(+), 2 deletions(-) >>> >>> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c >>> index 486fc6350d..66ecdb0969 100644 >>> --- a/hw/block/pflash_cfi01.c >>> +++ b/hw/block/pflash_cfi01.c >>> @@ -388,12 +388,15 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, >>> return ret; >>> } >>> >>> -/* update flash content on disk */ >>> +/* update flash content on disk and invalidate the guest view of RAM */ >> >> /* >> * Flush modified flash content: mark the range dirty, invalidate the >> * TBs translated from it, and write it back to the block backend. >> */ >> >>> static void pflash_update(PFlashCFI01 *pfl, int offset, >>> int size) >>> { >>> int offset_end; >>> int ret; >>> + >>> + memory_region_flush_rom_device(&pfl->mem, offset, size); >>> + >>> if (pfl->blk) { >>> offset_end = offset + size; >>> /* widen to sector boundaries */ >> >> I'd like feedback from migration maintainers: could we be writing >> staled content during live migration? Or maybe we are already safe. >> invalidate_and_set_dirty() gets DIRTY_MEMORY_MIGRATION set via the >> memory_region_get_dirty_log_mask call. Hmm so this change also fixes >> migration then. If confirmed, worth mentioning in the patch description: >> >> >> Direct writes to the flash RAM were not marked dirty for migration, >> so pages reprogrammed during pre-copy were not re-sent, and >> postload_update_cb() wrote the stale content to the block backend. >> The memory_region_flush_rom_device() call now also fixes this. >> > > Yes, this does seem to be the case. I couldn't find any path where the > writes from pflash_write() are invalidated. Thank you Fabiano for checking and confirming :) ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-27 3:34 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-16 19:15 [PATCH] hw/block/pflash: invalidate TBs on flash update Elliot Berman 2026-10-26 6:03 ` Philippe Mathieu-Daudé 2026-10-26 21:02 ` Fabiano Rosas 2026-10-27 3:30 ` Philippe Mathieu-Daudé
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.