All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.