Skip to contentSkip to conversation

Misc HW patches for 2026-07-07

GIT PULL Applied Philippe Mathieu-Daudé 4 participants 36 messages Jul 7 – Jul 10

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

The following changes since commit 94826ec1370328375c3b6d1e80fdc94c8f46c348:

Merge tag 'accel-20260706' of https://github.com/philmd/qemu into staging (2026-07-06 18:38:14 +0200)

are available in the Git repository at:

https://github.com/philmd/qemu.git tags/hw-misc-20260707

for you to fetch changes up to 04584a27dd59741bc20272c6faab96c08bcbb926:

Revert "aspeed/smc: snoop SPI transfers to fake dummy cycles" (2026-07-07 15:08:41 +0200)

----------------------------------------------------------------
Misc HW patches

- Fix in few trace event formats
- A pair of improvements in util/
- FlexCAN3 to imx8mp-evk board
- Various fixes in hw/
(EDU, ATI VGA, IDE AHCI, PCA9552, i8257 DMA,
e1000e/igb, MPT SAS, Hyper-V, QXL, M25P80)
----------------------------------------------------------------

BALATON Zoltan (1):
hw/display/ati: Include vga state in the blit context

Bernhard Beschow (5):
hw/net/can/flexcan: Wire clock control module via link property hw/net/can/flexcan: Subclass TYPE_CAN_FLEXCAN hw/arm/imx8mp-evk: Open code DEFINE_MACHINE_AARCH64 hw/arm/imx8mp-evk: Introduce FslImx8mpEvkState
hw/arm: Add basic FlexCAN3 support to TYPE_FSL_IMX8MP and imx8mp-evk

Bin Meng (8):
hw/block: m25p80: Fix dummy byte handling for Winbond flash hw/block: m25p80: Fix dummy byte handling for Numonyx/Micron flash hw/block: m25p80: Fix dummy byte handling for Macronix flash hw/ssi: npcm7xx_fiu: Correct the dummy cycle emulation logic hw/ssi: xilinx_spips: Fix dummy phase handling
hw/ssi: aspeed_smc: Fix direct-read dummy bytes
Revert "aspeed/smc: Fix number of dummy cycles for FAST_READ_4
command"
Revert "aspeed/smc: snoop SPI transfers to fake dummy cycles"

Denis V. Lunev (1):
hw/ide/ahci: cancel in-flight buffered reads on command engine restart

Dmitry Frolov (1):
utils/module: fix memleak in module_load()

Evgeny Kolmakov (1):
util/filemonitor-inotify: Use QEMU_LOCK_GUARD()

Junjie Cao (2):
hw/display/ati: reset host_data.next in write handler after flush hw/display/ati: guard against zero bpp in ati_host_data_flush

Mark Cave-Ayland (2):
hw/rtc/mc146818rtc: convert date from object prop to class prop hw/acpi/ich9: move initial property values into
ich9_reset_properties()

Peter Maydell (3):
hw/dma/i8257: Return zeroes for read_memory in verify mode hw/scsi/mptsas: Reset doorbell state on reset
hw/hyperv: Avoid crash if hyperv_find_cpu() passed invalid vp_index

Sanjeeva Yerrapureddy (1):
hw/net: fix e1000e/igb ip_len inflation by Ethernet minimum-frame
padding

Shameer Kolothum (1):
backends/iommufd: Fix dev_id and type order in viommu trace

Song Gao (1):
hw/intc/loongarch_dintc: Fix OOB access in DINT MMIO write handler

Thomas Huth (1):
hw/display/qxl: Fix mono cursor validation that can read past a cursor
chunk

Torin Carey (1):
hw/misc/edu: restrict dma access to dma buffer

yujun (3):
hw/gpio/pca9552: fix off-by-one in QOM led index validation
ebpf: fix swapped toeplitz/indirection args in set_data trace crypto/x509-utils: fix gnutls error code in crt_init failure path

 docs/system/arm/imx8m.rst     |   1 +
 include/hw/acpi/ich9.h        |   2 +
 include/hw/arm/fsl-imx8mp.h   |   8 ++
 include/hw/net/flexcan.h      |   4 +-
 include/hw/ssi/aspeed_smc.h   |   2 -
 include/hw/ssi/xilinx_spips.h |   2 +-
 crypto/x509-utils.c           |   3 +-
 ebpf/ebpf_rss.c               |   2 +-
 hw/acpi/ich9.c                |   8 +-
 hw/arm/fsl-imx6.c             |   5 +-
 hw/arm/fsl-imx8mp.c           |  38 ++++++++++
 hw/arm/imx8mp-evk.c           |  64 +++++++++++++---
 hw/block/m25p80.c             | 122 +++++++++++++++++++-----------
 hw/display/ati.c              |   2 +
 hw/display/ati_2d.c           |  44 +++++------
 hw/display/qxl-render.c       |   8 +-
 hw/dma/i8257.c                |  13 ++++
 hw/gpio/pca9552.c             |   8 +-
 hw/hyperv/hyperv.c            |   4 +-
 hw/ide/ahci.c                 |   3 +
 hw/intc/loongarch_dintc.c     |  13 ++++
 hw/isa/lpc_ich9.c             |   1 +
 hw/misc/edu.c                 |  24 +++---
 hw/misc/imx8mp_ccm.c          |   3 +
 hw/net/can/flexcan.c          |  90 ++++++++++++++++++-----
 hw/net/net_tx_pkt.c           |   7 +-
 hw/rtc/mc146818rtc.c          |   4 +-
 hw/scsi/mptsas.c              |   4 +
 hw/ssi/aspeed_smc.c           | 135 +++++-----------------------------
 hw/ssi/npcm7xx_fiu.c          |  25 ++-----
 hw/ssi/xilinx_spips.c         | 123 ++++++++++++++++++++++---------
 util/filemonitor-inotify.c    |  28 ++-----
 util/module.c                 |   2 +-
 backends/trace-events         |   2 +-
 hw/arm/Kconfig                |   1 +
 hw/ssi/trace-events           |   1 -
 36 files changed, 488 insertions(+), 318 deletions(-)
Signature · 1 line
2.53.0
#1 lore raw

[PULL 01/32] hw/misc/edu: restrict dma access to dma buffer

From: Torin Carey <[email protected]>

The EDU device doesn't enforce any bound checks on the addresses provided, allowing users of the device to perform arbitrary reads and writes to QEMU's address space.

Fixes 7b608e5d6c1 ("hw: misc: edu: use qemu_log_mask instead of hw_error")

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3852

Message-ID: <[email protected]>

---
 hw/misc/edu.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)
hw/misc/edu.c +14 -10
index cece633e113..a4b01269e8b 100644
@@ -103,7 +103,7 @@ static void edu_lower_irq(EduState *edu, uint32_t val)
     }
 }
 
-static void edu_check_range(uint64_t xfer_start, uint64_t xfer_size,
+static bool edu_check_range(uint64_t xfer_start, uint64_t xfer_size,
                 uint64_t dma_start, uint64_t dma_size)
 {
     uint64_t xfer_end = xfer_start + xfer_size;
@@ -115,13 +115,15 @@ static void edu_check_range(uint64_t xfer_start, uint64_t xfer_size,
      */
     if (dma_end >= dma_start && xfer_end >= xfer_start &&
         xfer_start >= dma_start && xfer_end <= dma_end) {
-        return;
+        return true;
     }
 
     qemu_log_mask(LOG_GUEST_ERROR,
                   "EDU: DMA range 0x%016"PRIx64"-0x%016"PRIx64
                   " out of bounds (0x%016"PRIx64"-0x%016"PRIx64")!",
                   xfer_start, xfer_end - 1, dma_start, dma_end - 1);
+
+    return false;
 }
 
 static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr)
@@ -148,16 +150,18 @@ static void edu_dma_timer(void *opaque)
 
     if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) {
         uint64_t dst = edu->dma.dst;
-        edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE);
-        dst -= DMA_START;
-        pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src),
-                edu->dma_buf + dst, edu->dma.cnt);
+        if (edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE)) {
+            dst -= DMA_START;
+            pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src),
+                         edu->dma_buf + dst, edu->dma.cnt);
+        }
     } else {
         uint64_t src = edu->dma.src;
-        edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE);
-        src -= DMA_START;
-        pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst),
-                edu->dma_buf + src, edu->dma.cnt);
+        if (edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE)) {
+            src -= DMA_START;
+            pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst),
+                          edu->dma_buf + src, edu->dma.cnt);
+        }
     }
 
     edu->dma.cmd &= ~EDU_DMA_RUN;
Signature · 1 line
2.53.0
#2 lore raw

[PULL 02/32] hw/display/ati: reset host_data.next in write handler after flush

In reply to Philippe Mathieu-Daudé

From: Junjie Cao <[email protected]>

ati_host_data_flush() resets host_data.next only on its success path. When it returns early (unsupported bpp, direction, src_source, or src_datatype), next remains stale at >= 4. The next HOST_DATA write then stores a guest-controlled dword at acc[4+], overflowing the 4-element accumulator array.

Fix this by resetting next unconditionally in the write handler after calling ati_host_data_flush() or ati_host_data_finish(), and removing the reset from inside ati_host_data_flush(). This ensures the write handler owns the full lifecycle of the accumulator index regardless of flush success or failure.

Resolves: https://lore.kernel.org/qemu-devel/Czyl6yVfL6sHl_o1kRk8N_LpwXMMRVhO9vgz1qCVJFagn9D4nHSKuiux39iOLty0Q3acxQq_FeovPhTQvSKus2htwjI9lTajLZmqovr0Wxs=@proton.me/

Message-ID: <[email protected]>

---
 hw/display/ati.c    | 2 ++
 hw/display/ati_2d.c | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)
hw/display/ati.c +2 -0
index d77589df67a..db7e08a462a 100644
@@ -1034,8 +1034,10 @@ static void ati_mm_write(void *opaque, hwaddr addr,
         s->host_data.acc[s->host_data.next++] = data;
         if (addr == HOST_DATA_LAST) {
             ati_host_data_finish(s);
+            s->host_data.next = 0;
         } else if (s->host_data.next >= 4) {
             ati_host_data_flush(s);
+            s->host_data.next = 0;
         }
         break;
     default:
hw/display/ati_2d.c +0 -1
index 48498677c7e..8ef82bb87fd 100644
@@ -452,7 +452,6 @@ bool ati_host_data_flush(ATIVGAState *s)
     }
 
     /* Track state of the overall blit for use by the next flush */
-    s->host_data.next = 0;
     s->host_data.row = row;
     s->host_data.col = col;
     if (s->host_data.row >= ctx.dst.height) {
Signature · 1 line
2.53.0
#3 lore raw

[PULL 03/32] hw/display/ati: guard against zero bpp in ati_host_data_flush

In reply to Philippe Mathieu-Daudé

From: Junjie Cao <[email protected]>

ati_bpp_from_datatype() returns 0 for unrecognized dp_datatype nibble values (0, 1, or >= 7). ati_host_data_flush() only guards against the bpp == 24 case but not bpp == 0, leading to:

1. Division by zero at "pix_count /= ctx.bpp" (SIGFPE) when src_datatype is SRC_COLOR.
2. g_assert_not_reached() in stn_he_p() when bypp (= bpp/8 = 0) hits the default case of the size switch.

Both are guest-triggerable via MMIO writes to the dp_datatype register while a HOST_DATA blit is active.

Add an explicit bpp == 0 check with LOG_GUEST_ERROR before proceeding with the blit, consistent with the existing check in ati_2d_do_blt().

Message-ID: <[email protected]>

---
 hw/display/ati_2d.c | 5 +++++
 1 file changed, 5 insertions(+)
hw/display/ati_2d.c +5 -0
index 8ef82bb87fd..22dd811bd85 100644
@@ -377,6 +377,11 @@ bool ati_host_data_flush(ATIVGAState *s)
 
     setup_2d_blt_ctx(s, &ctx);
 
+    if (!ctx.bpp) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "host_data_blt: invalid bpp from datatype\n");
+        return false;
+    }
     if (ctx.bpp == 24) {
         qemu_log_mask(LOG_UNIMP,
                       "host_data_blt: unsupported in 24 bits mode\n");
Signature · 1 line
2.53.0
#4 lore raw

[PULL 04/32] hw/ide/ahci: cancel in-flight buffered reads on command engine restart

In reply to Philippe Mathieu-Daudé

From: "Denis V. Lunev" <[email protected]>

ATAPI CD reads are issued through ide_buffered_readv() (cd_read_sector() and ide_atapi_cmd_read_dma_cb() in hw/ide/atapi.c). The PIO path discards the returned aiocb; the DMA path stores it in s->bus->dma->aiocb.

A guest can stop and restart a port's command engine (PxCMD.ST 1 -> 0 -> 1) while such a read is still in flight. Stopping the engine unmaps the command list (ahci_unmap_clb_address()) and restarting it re-maps the list and clears AHCIDevice.cur_cmd to NULL, but nothing tears down the outstanding read. This path does not run ide_reset(), so the drive's transfer state is preserved and the read still completes. Its callbacks then dereference the stale or NULL cur_cmd in the AHCI transfer helpers:

PIO: cd_read_sector_cb() -> ide_atapi_cmd_reply_end() ->

       ide_transfer_start_norecurse() -> ahci_pio_transfer()

DMA: ide_atapi_cmd_read_dma_cb() -> ahci_dma_rw_buf() ->
ahci_populate_sglist()

Both crash with a NULL cur_cmd; the PIO variant has been seen in the field.

Cancel the outstanding I/O when the command list is unmapped, reusing ide_cancel_dma_sync() as the ATAPI DEVICE RESET command does. It runs the completion callback with -ECANCELED (which tears down s->bus->dma->aiocb for the DMA case) and orphans the buffered request, so the eventual asynchronous completion is a no-op. Merely setting the orphaned flag is not enough: it would leave s->bus->dma->aiocb pointing at a freed aiocb that a later reset would cancel.

Fixes 1d8c11d63154 ("ide: add support for IDEBufferedRequest")

Message-ID: <[email protected]>

[PMD: Use ide_bus_active_if()]
---
 hw/ide/ahci.c | 3 +++
 1 file changed, 3 insertions(+)
hw/ide/ahci.c +3 -0
index c2b4432b947..749f0efa1d0 100644
@@ -740,6 +740,9 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
 
 static void ahci_unmap_clb_address(AHCIDevice *ad)
 {
+    /* Cancel in-flight reads that would complete against a cleared cur_cmd. */
+    ide_cancel_dma_sync(ide_bus_active_if(&ad->port));
+
     if (ad->lst == NULL) {
         trace_ahci_unmap_clb_address_null(ad->hba, ad->port_no);
         return;
Signature · 1 line
2.53.0
#5 lore raw

Re: [PULL 04/32] hw/ide/ahci: cancel in-flight buffered reads on command engine restart

Quoted 33 lines · Philippe Mathieu-Daudé

From: "Denis V. Lunev" <[email protected]>

ATAPI CD reads are issued through ide_buffered_readv() (cd_read_sector() and ide_atapi_cmd_read_dma_cb() in hw/ide/atapi.c). The PIO path discards the returned aiocb; the DMA path stores it in s->bus->dma->aiocb.

A guest can stop and restart a port's command engine (PxCMD.ST 1 -> 0 -> 1) while such a read is still in flight. Stopping the engine unmaps the command list (ahci_unmap_clb_address()) and restarting it re-maps the list and clears AHCIDevice.cur_cmd to NULL, but nothing tears down the outstanding read. This path does not run ide_reset(), so the drive's transfer state is preserved and the read still completes. Its callbacks then dereference the stale or NULL cur_cmd in the AHCI transfer helpers:

   PIO: cd_read_sector_cb() -> ide_atapi_cmd_reply_end() ->
        ide_transfer_start_norecurse() -> ahci_pio_transfer()

   DMA: ide_atapi_cmd_read_dma_cb() -> ahci_dma_rw_buf() ->
        ahci_populate_sglist()

Both crash with a NULL cur_cmd; the PIO variant has been seen in the field.

Cancel the outstanding I/O when the command list is unmapped, reusing ide_cancel_dma_sync() as the ATAPI DEVICE RESET command does. It runs the completion callback with -ECANCELED (which tears down s->bus->dma->aiocb for the DMA case) and orphans the buffered request, so the eventual asynchronous completion is a no-op. Merely setting the orphaned flag is not enough: it would leave s->bus->dma->aiocb pointing at a freed aiocb that a later reset would cancel.

Quoted 5 lines
Fixes 1d8c11d63154 ("ide: add support for IDEBufferedRequest")

Message-ID: <[email protected]>

[PMD: Use ide_bus_active_if()]

I'm picking this (and the test) up for the currently active stable qemu series. Please let me know if I shouldn't.

Thanks,

/mjt

Quoted 14 lines
hw/ide/ahci.c +3 -0
index c2b4432b947..749f0efa1d0 100644
@@ -740,6 +740,9 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
 
  static void ahci_unmap_clb_address(AHCIDevice *ad)
  {
+    /* Cancel in-flight reads that would complete against a cleared cur_cmd. */
+    ide_cancel_dma_sync(ide_bus_active_if(&ad->port));
+
      if (ad->lst == NULL) {
          trace_ahci_unmap_clb_address_null(ad->hba, ad->port_no);
          return;
#6 lore raw

[PULL 05/32] hw/display/ati: Include vga state in the blit context

In reply to Philippe Mathieu-Daudé

From: BALATON Zoltan <[email protected]>

The vga state is needed by several functions using the blit context so just include it in the context instead of passing it separately.

Message-ID: <[email protected]>

---
 hw/display/ati_2d.c | 38 ++++++++++++++++++--------------------
 1 file changed, 18 insertions(+), 20 deletions(-)
hw/display/ati_2d.c +18 -20
index 22dd811bd85..7a4a115aee2 100644
@@ -45,6 +45,7 @@ static int ati_bpp_from_datatype(const ATIVGAState *s)
 }
 
 typedef struct {
+    VGACommonState *vga;
     int bpp;
     uint32_t rop3;
     bool host_data_active;
@@ -52,8 +53,6 @@ typedef struct {
     bool top_to_bottom;
     bool need_swap;
     uint32_t frgd_clr;
-    const uint8_t *palette;
-    const uint8_t *vram_end;
     QemuRect scissor;
 
     QemuRect dst;
@@ -66,8 +65,9 @@ typedef struct {
     const uint8_t *src_bits;
 } ATI2DCtx;
 
-static void ati_set_dirty(VGACommonState *vga, const ATI2DCtx *ctx)
+static void ati_set_dirty(const ATI2DCtx *ctx)
 {
+    VGACommonState *vga = ctx->vga;
     DisplaySurface *ds = qemu_console_surface(vga->con);
     unsigned int bypp = ctx->bpp / 8;
     hwaddr dirty_start = ctx->dst_offset + ctx->dst.x * bypp +
@@ -94,8 +94,9 @@ static void ati_set_dirty(VGACommonState *vga, const ATI2DCtx *ctx)
     }
 }
 
-static void setup_2d_blt_ctx(const ATIVGAState *s, ATI2DCtx *ctx)
+static void setup_2d_blt_ctx(ATIVGAState *s, ATI2DCtx *ctx)
 {
+    ctx->vga = &s->vga;
     ctx->bpp = ati_bpp_from_datatype(s);
     ctx->rop3 = s->regs.dp_mix & GMC_ROP3_MASK;
     ctx->host_data_active = s->host_data.active;
@@ -103,9 +104,7 @@ static void setup_2d_blt_ctx(const ATIVGAState *s, ATI2DCtx *ctx)
     ctx->top_to_bottom = s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM;
     ctx->need_swap = (HOST_BIG_ENDIAN != s->vga.big_endian_fb);
     ctx->frgd_clr = s->regs.dp_brush_frgd_clr;
-    ctx->palette = s->vga.palette;
     ctx->dst_offset = s->regs.dst_offset;
-    ctx->vram_end = s->vga.vram_ptr + s->vga.vram_size;
 
     ctx->scissor.width = s->regs.sc_right - s->regs.sc_left + 1;
     ctx->scissor.height = s->regs.sc_bottom - s->regs.sc_top + 1;
@@ -153,10 +152,11 @@ static uint32_t make_filler(int bpp, uint32_t color)
     return color;
 }
 
-static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
+static bool ati_2d_do_blt(const ATI2DCtx *ctx, uint8_t use_pixman)
 {
     QemuRect vis_src, vis_dst;
     unsigned int x, y, i, j, bypp = ctx->bpp / 8;
+    const uint8_t *vram_end = ctx->vga->vram_ptr + ctx->vga->vram_size;
 
     if (!ctx->bpp) {
         qemu_log_mask(LOG_GUEST_ERROR, "Invalid bpp\n");
@@ -167,9 +167,8 @@ static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
         return false;
     }
     if (ctx->dst.x > 0x3fff || ctx->dst.y > 0x3fff ||
-        ctx->dst_bits >= ctx->vram_end - bypp ||
-        ctx->dst_bits + ctx->dst.x * bypp + (ctx->dst.y + ctx->dst.height) *
-        ctx->dst_stride >= ctx->vram_end - bypp) {
+        ctx->dst_bits >= vram_end - bypp || ctx->dst_bits + ctx->dst.x * bypp +
+        (ctx->dst.y + ctx->dst.height) * ctx->dst_stride >= vram_end - bypp) {
         qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
         return false;
     }
@@ -206,9 +205,9 @@ static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
         }
         if (!ctx->host_data_active &&
             (vis_src.x > 0x3fff || vis_src.y > 0x3fff ||
-            ctx->src_bits >= ctx->vram_end - bypp ||
+            ctx->src_bits >= vram_end - bypp ||
             ctx->src_bits + vis_src.x * bypp + (vis_src.y + vis_dst.height) *
-            ctx->src_stride >= ctx->vram_end - bypp)) {
+            ctx->src_stride >= vram_end - bypp)) {
             qemu_log_mask(LOG_UNIMP, "blt outside vram not implemented\n");
             return false;
         }
@@ -275,6 +274,7 @@ static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
     case ROP3_BLACKNESS:
     case ROP3_WHITENESS:
     {
+        const uint8_t *palette = ctx->vga->palette;
         uint32_t filler = 0;
 
         if (ctx->bpp == 24) {
@@ -286,14 +286,12 @@ static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
             filler = make_filler(ctx->bpp, ctx->frgd_clr);
             break;
         case ROP3_BLACKNESS:
-            filler = 0xffUL << 24 | rgb_to_pixel32(ctx->palette[0],
-                                                   ctx->palette[1],
-                                                   ctx->palette[2]);
+            filler = 0xffUL << 24 | rgb_to_pixel32(palette[0], palette[1],
+                                                   palette[2]);
             break;
         case ROP3_WHITENESS:
-            filler = 0xffUL << 24 | rgb_to_pixel32(ctx->palette[3],
-                                                   ctx->palette[4],
-                                                   ctx->palette[5]);
+            filler = 0xffUL << 24 | rgb_to_pixel32(palette[3], palette[4],
+                                                   palette[5]);
             break;
         }
         DPRINTF("pixman_fill(%p, %ld, %d, %d, %d, %d, %d, %x)\n",
@@ -347,7 +345,7 @@ void ati_2d_blt(ATIVGAState *s)
     }
     setup_2d_blt_ctx(s, &ctx);
     if (ati_2d_do_blt(&ctx, s->use_pixman)) {
-        ati_set_dirty(&s->vga, &ctx);
+        ati_set_dirty(&ctx);
     }
 }
 
@@ -446,7 +444,7 @@ bool ati_host_data_flush(ATIVGAState *s)
         DPRINTF("blt %dpx span @ row: %d, col: %d to dst (%d,%d)\n",
                 pix_in_scanline, row, col, chunk.dst.x, chunk.dst.y);
         if (ati_2d_do_blt(&chunk, s->use_pixman)) {
-            ati_set_dirty(&s->vga, &chunk);
+            ati_set_dirty(&chunk);
         }
         idx += pix_in_scanline;
         col += pix_in_scanline;
Signature · 1 line
2.53.0
#7 lore raw

[PULL 07/32] hw/gpio/pca9552: fix off-by-one in QOM led index validation

In reply to Philippe Mathieu-Daudé

From: yujun <[email protected]>

pca955x_get_led() and pca955x_set_led() accept led indices equal to pin_count, but valid indices are 0..pin_count-1. For a 16-pin device, led16 passes the current check and then accesses an LS register past max_reg.

Use the same >= pin_count bounds check as pca9554_set_pin() and the gpio input handler assert in this file.

Fixes a90d8f84674 ("misc/pca9552: Add qom set and get")

Message-ID: <[email protected]>

---
 hw/gpio/pca9552.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
hw/gpio/pca9552.c +4 -4
index 472d8ad9571..b13ac9fd9ce 100644
@@ -311,8 +311,8 @@ static void pca955x_get_led(Object *obj, Visitor *v, const char *name,
         error_setg(errp, "%s: error reading %s", __func__, name);
         return;
     }
-    if (led < 0 || led > k->pin_count) {
-        error_setg(errp, "%s invalid led %s", __func__, name);
+    if (led < 0 || led >= k->pin_count) {
+        error_setg(errp, "%s: invalid led %s", __func__, name);
         return;
     }
     /*
@@ -352,8 +352,8 @@ static void pca955x_set_led(Object *obj, Visitor *v, const char *name,
         error_setg(errp, "%s: error reading %s", __func__, name);
         return;
     }
-    if (led < 0 || led > k->pin_count) {
-        error_setg(errp, "%s invalid led %s", __func__, name);
+    if (led < 0 || led >= k->pin_count) {
+        error_setg(errp, "%s: invalid led %s", __func__, name);
         return;
     }
 
Signature · 1 line
2.53.0
#8 lore raw

[PULL 09/32] crypto/x509-utils: fix gnutls error code in crt_init failure path

In reply to Philippe Mathieu-Daudé

From: yujun <[email protected]>

qcrypto_get_x509_cert_fingerprint() reports gnutls_strerror(ret) when gnutls_x509_crt_init() fails, but ret is still the initial value -1. Store the gnutls return code before formatting the error, matching other gnutls call sites in the tree.

Fixes 2183ab6251 ("crypto/x509-utils: Check for error from gnutls_x509_crt_init()")

Message-ID: <[email protected]>

---
 crypto/x509-utils.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
crypto/x509-utils.c +2 -1
index 39bb6d4d8c3..1843488bca3 100644
@@ -46,7 +46,8 @@ int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
         return -1;
     }
 
-    if (gnutls_x509_crt_init(&crt) < 0) {
+    ret = gnutls_x509_crt_init(&crt);
+    if (ret < 0) {
         error_setg(errp, "Unable to initialize certificate: %s",
                    gnutls_strerror(ret));
         return -1;
Signature · 1 line
2.53.0
#9 lore raw

[PULL 10/32] hw/dma/i8257: Return zeroes for read_memory in verify mode

In reply to Philippe Mathieu-Daudé

From: Peter Maydell <[email protected]>

The i8257 DMA controller has a "verify" mode, which the datasheet describes like this:

Quoted 4 lines

DMA verify, which does not actually involve the transfer of data. When an 8257 channel is in the DMA verify mode, it will respond the same as described for transfer operations, except that no memory or I/O read/write control signals will be generated. When an 8257

Quoted 8 lines

channel is in the DMA verify mode, it will respond the same as described for transfer operations, except that no memory or I/O read /write control signals will be generated, thus preventing the transfer of data. The 8257, however, will gain control of the system bus and will acknowledge the peripheral's DMA request for each DMA cycle. The perihperal can use these acknowledge signals to enable an internal access of each byte of a data block in order to execute some verification procedure, such as the accumulation of a CRC check word.

In practice, for QEMU's purposes the only real user of this is the floppy controller, which can be made to perform a "read data from floppy disk and check the checksum" by telling the fdc to do a read and the DMA controller to do a verify. This causes the fdc to do all the usual read actions including the checksum, but the data is never written to memory. However, it is possible for a guest doing something silly to program the DMA controller to do a verify operation for a device that wants to read from memory. Currently we simply return early from i8257_dma_read_memory() without writing to the buffer. None of the callers (the GUS, sb16 and cs4231a sound cards, plus the fdc) expect this, so they will take the uninitialized data as if it were from the guest. This can cause us to leak host data off the stack into the guest.

Make i8257_dma_read_memory() fill the buffer with zeroes rather than leaving it untouched for a verify operation.

Cc: [email protected]
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3487

Message-ID: <[email protected]>

---
 hw/dma/i8257.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
hw/dma/i8257.c +13 -0
index 7d7e5434275..57715498895 100644
@@ -408,6 +408,19 @@ static int i8257_dma_read_memory(IsaDma *obj, int nchan, void *buf, int pos,
     hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
 
     if (i8257_is_verify_transfer(r)) {
+        /*
+         * If the device is expecting this verify operation then
+         * it won't care about the nonexistent data. But if it
+         * is expecting a real read (i.e. the guest has misprogrammed
+         * the DMA controller and the device) it's going to try to do
+         * something with the buffer contents. Give it zeroes.
+         * (It's not clear whether this is exactly what happens if
+         * you do this on real hardware. In practice no device QEMU
+         * emulates has a use for verify on a memory-read transfer,
+         * so we don't care beyond avoiding the guest being able to
+         * trigger the caller reading uninitialized data.)
+         */
+        memset(buf, 0, len);
         return len;
     }
 
Signature · 1 line
2.53.0
#10 lore raw

[PULL 11/32] hw/net: fix e1000e/igb ip_len inflation by Ethernet minimum-frame padding

In reply to Philippe Mathieu-Daudé

From: Sanjeeva Yerrapureddy <[email protected]>

When a guest transmits a short Ethernet frame, iov_size() returns the padded wire length including any bytes added to reach the Ethernet minimum frame size of 60 bytes. net_tx_pkt_rebuild_payload() uses this inflated size as payload_len. net_tx_pkt_update_ip_hdr_checksum() then overwrites the IPv4 Total Length field with payload_len + l3_hdr_len, inflating it by the padding. The receiver interprets Ethernet padding as IP payload, producing a malformed packet.

Fix by removing the ip_len write from net_tx_pkt_update_ip_hdr_checksum() so it only recomputes the checksum, and moving the ip_len assignment into net_tx_pkt_update_ip_checksums() where it is only performed for TSO (where ip_len must be derived from payload_len since the guest sets ip_len=0 per Intel 82574 datasheet §7.3.4 for super-packets the host will segment).

Both e1000e and igb already call net_tx_pkt_update_ip_hdr_checksum() from their IXSM paths, so both are corrected by this single common- layer change.

Message-ID: <20260629-net-tx-pkt-ip-length-padding-v5-1-16760e30252e@gmail.com>

---
 hw/net/net_tx_pkt.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
hw/net/net_tx_pkt.c +3 -4
index 903238dca24..b134348fe80 100644
@@ -93,9 +93,6 @@ void net_tx_pkt_update_ip_hdr_checksum(struct NetTxPkt *pkt)
     uint16_t csum;
     assert(pkt);
 
-    pkt->l3_hdr.ip.ip_len = cpu_to_be16(pkt->payload_len +
-        pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len);
-
     pkt->l3_hdr.ip.ip_sum = 0;
     csum = net_raw_checksum(pkt->l3_hdr.octets,
         pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len);
@@ -117,7 +114,9 @@ void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt)
 
     if (gso_type == VIRTIO_NET_HDR_GSO_TCPV4 ||
         gso_type == VIRTIO_NET_HDR_GSO_UDP) {
-        /* Calculate IP header checksum */
+        /* Set ip_len and calculate IP header checksum */
+        pkt->l3_hdr.ip.ip_len = cpu_to_be16(pkt->payload_len +
+            pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len);
         net_tx_pkt_update_ip_hdr_checksum(pkt);
 
         /* Calculate IP pseudo header checksum */
Signature · 1 line
2.53.0
#11 lore raw

[PULL 06/32] util/filemonitor-inotify: Use QEMU_LOCK_GUARD()

In reply to Philippe Mathieu-Daudé

From: Evgeny Kolmakov <[email protected]>

Replace manual qemu_mutex_(un)lock() calls with
QEMU_LOCK_GUARD() to remove 'goto cleanup' code

Message-ID: <[email protected]>

---
 util/filemonitor-inotify.c | 28 ++++++++--------------------
 1 file changed, 8 insertions(+), 20 deletions(-)
util/filemonitor-inotify.c +8 -20
index 7352b9fe53e..fe2057f820c 100644
@@ -21,6 +21,7 @@
 #include "qemu/osdep.h"
 #include "qemu/filemonitor.h"
 #include "qemu/main-loop.h"
+#include "qemu/lockable.h"
 #include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "trace.h"
@@ -59,10 +60,9 @@ static void qemu_file_monitor_watch(void *arg)
     int used = 0;
     int len;
 
-    qemu_mutex_lock(&mon->lock);
+    QEMU_LOCK_GUARD(&mon->lock);
 
     if (mon->fd == -1) {
-        qemu_mutex_unlock(&mon->lock);
         return;
     }
 
@@ -72,11 +72,10 @@ static void qemu_file_monitor_watch(void *arg)
         if (errno != EAGAIN) {
             error_report("Failure monitoring inotify FD '%s',"
                          "disabling events", strerror(errno));
-            goto cleanup;
         }
 
         /* no more events right now */
-        goto cleanup;
+        return;
     }
 
     /* Loop over all events in the buffer */
@@ -151,9 +150,6 @@ static void qemu_file_monitor_watch(void *arg)
             }
         }
     }
-
- cleanup:
-    qemu_mutex_unlock(&mon->lock);
 }
 
 
@@ -257,9 +253,8 @@ qemu_file_monitor_add_watch(QFileMonitor *mon,
 {
     QFileMonitorDir *dir;
     QFileMonitorWatch watch;
-    int64_t ret = -1;
 
-    qemu_mutex_lock(&mon->lock);
+    QEMU_LOCK_GUARD(&mon->lock);
     dir = g_hash_table_lookup(mon->dirs, dirpath);
     if (!dir) {
         int rv = inotify_add_watch(mon->fd, dirpath,
@@ -268,7 +263,7 @@ qemu_file_monitor_add_watch(QFileMonitor *mon,
 
         if (rv < 0) {
             error_setg_errno(errp, errno, "Unable to watch '%s'", dirpath);
-            goto cleanup;
+            return -1;
         }
 
         trace_qemu_file_monitor_enable_watch(mon, dirpath, rv);
@@ -297,11 +292,7 @@ qemu_file_monitor_add_watch(QFileMonitor *mon,
                                       filename ? filename : "<none>",
                                       cb, opaque, watch.id);
 
-    ret = watch.id;
-
- cleanup:
-    qemu_mutex_unlock(&mon->lock);
-    return ret;
+    return watch.id;
 }
 
 
@@ -312,13 +303,13 @@ void qemu_file_monitor_remove_watch(QFileMonitor *mon,
     QFileMonitorDir *dir;
     gsize i;
 
-    qemu_mutex_lock(&mon->lock);
+    QEMU_LOCK_GUARD(&mon->lock);
 
     trace_qemu_file_monitor_remove_watch(mon, dirpath, id);
 
     dir = g_hash_table_lookup(mon->dirs, dirpath);
     if (!dir) {
-        goto cleanup;
+        return;
     }
 
     for (i = 0; i < dir->watches->len; i++) {
@@ -342,7 +333,4 @@ void qemu_file_monitor_remove_watch(QFileMonitor *mon,
             qemu_set_fd_handler(mon->fd, NULL, NULL, NULL);
         }
     }
-
- cleanup:
-    qemu_mutex_unlock(&mon->lock);
 }
Signature · 1 line
2.53.0
#12 lore raw

[PULL 08/32] ebpf: fix swapped toeplitz/indirection args in set_data trace

In reply to Philippe Mathieu-Daudé

From: yujun <[email protected]>

trace_ebpf_rss_set_data() passes its third and fourth arguments to the toeplitz-ptr and indirection-ptr fields defined in trace-events. ebpf_rss_set_all() passed indirections_table and toeplitz_key in the opposite order, so tracing mislabeled the two pointers.

Match the argument order already used by trace_ebpf_rss_mmap().

Fixes f5cae19d10 ("ebpf: improve trace event coverage to all key operations")

Message-ID: <[email protected]>

---
 ebpf/ebpf_rss.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
ebpf/ebpf_rss.c +1 -1
index 926392b3c58..6650d0daef0 100644
@@ -270,7 +270,7 @@ bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
 
     ebpf_rss_set_toepliz_key(ctx, toeplitz_key);
 
-    trace_ebpf_rss_set_data(ctx, config, indirections_table, toeplitz_key);
+    trace_ebpf_rss_set_data(ctx, config, toeplitz_key, indirections_table);
 
     return true;
 }
Signature · 1 line
2.53.0
#13 lore raw

[PULL 15/32] utils/module: fix memleak in module_load()

In reply to Philippe Mathieu-Daudé

From: Dmitry Frolov <[email protected]>

Memory for version_dir, allocated by g_strdup, is not freed

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Message-ID: <[email protected]>

---
 util/module.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
util/module.c +1 -1
index 09dc43f51eb..8f8e6994f11 100644
@@ -203,7 +203,7 @@ int module_load(const char *prefix, const char *name, Error **errp)
 {
     int rv = -1;
 #ifdef CONFIG_MODULE_UPGRADES
-    char *version_dir;
+    g_autofree char *version_dir = NULL;
 #endif
     const char *search_dir;
     char *dirs[5];
Signature · 1 line
2.53.0
#14 lore raw

[PULL 17/32] hw/net/can/flexcan: Wire clock control module via link property

In reply to Philippe Mathieu-Daudé

From: Bernhard Beschow <[email protected]>

When wiring struct FlexcanState to the clock control module, it is currently necessary to reach into its private data. Moreover, when forgetting to wire the clock control module, QEMU will crash after the guest has already started. Fix both by letting struct FlexcanState expose a link property whose sanity is checked at realize time.

Message-ID: <[email protected]>

---
 hw/arm/fsl-imx6.c    |  3 ++-
 hw/net/can/flexcan.c | 10 ++++++++--
 2 files changed, 10 insertions(+), 3 deletions(-)
hw/arm/fsl-imx6.c +2 -1
index bf106a90632..585c935b899 100644
@@ -391,7 +391,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
             { FSL_IMX6_CAN2_ADDR, FSL_IMX6_FLEXCAN2_IRQ },
         };
 
-        s->flexcan[i].ccm = IMX_CCM(&s->ccm);
+        object_property_set_link(OBJECT(&s->flexcan[i]), "clock-control-module",
+                                 OBJECT(&s->ccm), &error_abort);
         object_property_set_link(OBJECT(&s->flexcan[i]), "canbus",
                                  OBJECT(s->canbus[i]), &error_abort);
 
hw/net/can/flexcan.c +8 -2
index 1ea459d9f69..8f3f066ef50 100644
@@ -333,8 +333,6 @@ static uint32_t flexcan_get_bitrate(FlexcanState *s)
 
     uint32_t pe_freq, s_freq, bitrate;
 
-    assert(s->ccm);
-
     /* s_freq: CAN clock from CCM divided by the prescaler */
     pe_freq = imx_ccm_get_clock_frequency(s->ccm, CLK_CAN);
     s_freq = pe_freq / (1 + conf_presdiv);
@@ -1346,6 +1344,12 @@ static void flexcan_realize(DeviceState *dev, Error **errp)
         }
     }
 
+    if (!s->ccm) {
+        error_setg(errp, "%s 'clock-control-module' link property not set",
+                   dev->canonical_path);
+        return;
+    }
+
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
     sysbus_init_irq(SYS_BUS_DEVICE(SYS_BUS_DEVICE(dev)), &s->irq);
 }
@@ -1366,6 +1370,8 @@ static const VMStateDescription vmstate_can = {
 static const Property flexcan_properties[] = {
     DEFINE_PROP_LINK("canbus", FlexcanState, canbus, TYPE_CAN_BUS,
                      CanBusState *),
+    DEFINE_PROP_LINK("clock-control-module", FlexcanState, ccm, TYPE_IMX_CCM,
+                     IMXCCMState *),
 };
 
 static void flexcan_class_init(ObjectClass *klass, const void *data)
Signature · 1 line
2.53.0
#15 lore raw

[PULL 13/32] hw/hyperv: Avoid crash if hyperv_find_cpu() passed invalid vp_index

In reply to Philippe Mathieu-Daudé

From: Peter Maydell <[email protected]>

The hyperv_find_cpu() function finds a CPU from a CPU index; this is basically a wrapper around qemu_get_cpu(). It is allowed to fail, in which case it returns NULL, which its caller handles. However, it includes an assertion check which accidentally assumes the CPU pointer is non-NULL.

We could assert only if cs != NULL, but the assertion here is not doing anything interesting -- hyperv_vp_index() is a trivial wrapper returning cs->cpu_index, so this is effectively asserting that qemu_get_cpu() did what it claims to do, i.e. returned us the CPU matching the index we gave it. qemu_get_cpu() is a simple "iterate through list and find matching CPU" which is unlikely to be buggy, and we don't feel the need to sanity-check it in any of our other many uses of it. Drop the assertion entirely.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3568

Message-ID: <[email protected]>

---
 hw/hyperv/hyperv.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
hw/hyperv/hyperv.c +1 -3
index 4d900327857..900ff80213d 100644
@@ -237,9 +237,7 @@ struct HvSintRoute {
 
 static CPUState *hyperv_find_vcpu(uint32_t vp_index)
 {
-    CPUState *cs = qemu_get_cpu(vp_index);
-    assert(hyperv_vp_index(cs) == vp_index);
-    return cs;
+    return qemu_get_cpu(vp_index);
 }
 
 /*
Signature · 1 line
2.53.0
#16 lore raw

[PULL 14/32] hw/display/qxl: Fix mono cursor validation that can read past a cursor chunk

In reply to Philippe Mathieu-Daudé

From: Thomas Huth <[email protected]>

qxl_render_cursor() maps the guest-provided QXLCursor object using the guest-controlled cursor->chunk.data_size.
For a mono cursor, qxl_cursor() then validates the expected bitmap size against cursor->data_size, but it does not validate that the first chunk actually contains that many bytes.
A guest could set cursor->data_size to the correct full mono cursor size while setting cursor->chunk.data_size to zero. In that case, cursor_set_mono() reads the AND/XOR masks starting at cursor->chunk.data. If the cursor object is placed at the end of the QXL RAM BAR, those reads cross the mapped RAM region and could crash the QEMU process (e.g. under ASan).

Fix it by double-checking cursor->chunk.data_size for the correct size.

This patch is based on the suggested changes by the reporter in the bug ticket.

Reported-by: huntr bubble
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3646

Message-ID: <[email protected]>

---
 hw/display/qxl-render.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
hw/display/qxl-render.c +5 -3
index 7b692d5a854..3bf634ee059 100644
@@ -272,9 +272,11 @@ static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor,
     case SPICE_CURSOR_TYPE_MONO:
         /* Assume that the full cursor is available in a single chunk. */
         size = 2 * cursor_get_mono_bpl(c) * c->height;
-        if (size != cursor->data_size) {
-            fprintf(stderr, "%s: bad monochrome cursor %ux%u with size %u\n",
-                    __func__, c->width, c->height, cursor->data_size);
+        if (size != cursor->data_size || cursor->chunk.data_size < size) {
+            qxl_set_guest_bug(qxl, "%s: bad monochrome cursor %ux%u"
+                              " data_size %u chunk_size %u",
+                              __func__, c->width, c->height,
+                              cursor->data_size, cursor->chunk.data_size);
             goto fail;
         }
         and_mask = cursor->chunk.data;
Signature · 1 line
2.53.0
#17 lore raw

[PULL 20/32] hw/arm/imx8mp-evk: Introduce FslImx8mpEvkState

In reply to Philippe Mathieu-Daudé

From: Bernhard Beschow <[email protected]>

Introduce class FslImx8mpEvkState which will be needed for holding CanBusState attributes and associated properties.

Message-ID: <[email protected]>

---
 hw/arm/imx8mp-evk.c | 30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)
hw/arm/imx8mp-evk.c +20 -10
index 4a0c9df76b7..ca0ee2d3f2e 100644
@@ -19,6 +19,17 @@
 #include "qapi/error.h"
 #include <libfdt.h>
 
+#define TYPE_IMX8MPEVK_MACHINE MACHINE_TYPE_NAME("imx8mp-evk")
+OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpEvkState, IMX8MPEVK_MACHINE)
+
+struct FslImx8mpEvkState {
+    MachineState parent_obj;
+
+    FslImx8mpState soc;
+
+    struct arm_boot_info boot_info;
+};
+
 static void imx8mp_evk_modify_dtb(const struct arm_boot_info *info, void *fdt)
 {
     int i, offset;
@@ -57,8 +68,7 @@ static void imx8mp_evk_modify_dtb(const struct arm_boot_info *info, void *fdt)
 
 static void imx8mp_evk_init(MachineState *machine)
 {
-    static struct arm_boot_info boot_info;
-    FslImx8mpState *s;
+    FslImx8mpEvkState *s = IMX8MPEVK_MACHINE(machine);
 
     if (machine->ram_size > FSL_IMX8MP_RAM_SIZE_MAX) {
         error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")",
@@ -66,7 +76,7 @@ static void imx8mp_evk_init(MachineState *machine)
         exit(1);
     }
 
-    boot_info = (struct arm_boot_info) {
+    s->boot_info = (struct arm_boot_info) {
         .loader_start = FSL_IMX8MP_RAM_START,
         .board_id = -1,
         .ram_size = machine->ram_size,
@@ -74,10 +84,9 @@ static void imx8mp_evk_init(MachineState *machine)
         .modify_dtb = imx8mp_evk_modify_dtb,
     };
 
-    s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
-    object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
-    object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal);
-    sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal);
+    object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX8MP);
+    object_property_set_uint(OBJECT(&s->soc), "fec1-phy-num", 1, &error_fatal);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->soc), &error_fatal);
 
     memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
                                 machine->ram);
@@ -93,14 +102,14 @@ static void imx8mp_evk_init(MachineState *machine)
         }
 
         blk = blk_by_legacy_dinfo(di);
-        bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
+        bus = qdev_get_child_bus(DEVICE(&s->soc.usdhc[i]), "sd-bus");
         carddev = qdev_new(TYPE_SD_CARD);
         qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
         qdev_realize_and_unref(carddev, bus, &error_fatal);
     }
 
     if (!qtest_enabled()) {
-        arm_load_kernel(&s->cpu[0], machine, &boot_info);
+        arm_load_kernel(&s->soc.cpu[0], machine, &s->boot_info);
     }
 }
 
@@ -128,9 +137,10 @@ static void imx8mp_evk_machine_class_init(ObjectClass *oc, const void *data)
 
 static const TypeInfo imx8mp_evk_machine_types[] = {
     {
-        .name = MACHINE_TYPE_NAME("imx8mp-evk"),
+        .name = TYPE_IMX8MPEVK_MACHINE,
         .parent = TYPE_MACHINE,
         .class_init = imx8mp_evk_machine_class_init,
+        .instance_size = sizeof(FslImx8mpEvkState),
         .interfaces = aarch64_machine_interfaces,
     },
 };
Signature · 1 line
2.53.0
#18 lore raw

[PULL 22/32] hw/rtc/mc146818rtc: convert date from object prop to class prop

In reply to Philippe Mathieu-Daudé

From: Mark Cave-Ayland <[email protected]>

This is to allow it to be the target of a class alias property.

Message-ID: <[email protected]>

---
 hw/rtc/mc146818rtc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
hw/rtc/mc146818rtc.c +2 -2
index bcab018c7cd..ba396435d1a 100644
@@ -920,8 +920,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
     memory_region_add_subregion(&s->io, 0, &s->coalesced_io);
     memory_region_add_coalescing(&s->coalesced_io, 0, 1);
 
-    object_property_add_tm(OBJECT(s), "date", rtc_get_date);
-
     qdev_init_gpio_out(dev, &s->irq, 1);
 }
 
@@ -1020,6 +1018,8 @@ static void rtc_class_initfn(ObjectClass *klass, const void *data)
     adevc->build_dev_aml = rtc_build_aml;
     device_class_set_props(dc, mc146818rtc_properties);
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+
+    object_class_property_add_tm(klass, "date", rtc_get_date);
 }
 
 static const TypeInfo mc146818rtc_info = {
Signature · 1 line
2.53.0
#19 lore raw

[PULL 24/32] backends/iommufd: Fix dev_id and type order in viommu trace

In reply to Philippe Mathieu-Daudé

From: Shameer Kolothum <[email protected]>

The trace event receives dev_id before type, but its format string prints them in the wrong order. Correct the order.

Fixes f2d31df0d925 ("backends/iommufd: Introduce iommufd_backend_alloc_viommu")

Message-ID: <[email protected]>

---
 backends/trace-events | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
backends/trace-events +1 -1
index b63420b73ee..009a25b0be9 100644
@@ -21,7 +21,7 @@ iommufd_backend_free_id(int iommufd, uint32_t id, int ret) " iommufd=%d id=%d (%
 iommufd_backend_set_dirty(int iommufd, uint32_t hwpt_id, bool start, int ret) " iommufd=%d hwpt=%u enable=%d (%d)"
 iommufd_backend_get_dirty_bitmap(int iommufd, uint32_t hwpt_id, uint64_t iova, uint64_t size, uint64_t flags, uint64_t page_size, int ret) " iommufd=%d hwpt=%u iova=0x%"PRIx64" size=0x%"PRIx64" flags=0x%"PRIx64" page_size=0x%"PRIx64" (%d)"
 iommufd_backend_invalidate_cache(int iommufd, uint32_t id, uint32_t data_type, uint32_t entry_len, uint32_t entry_num, uint32_t done_num, uint64_t data_ptr, int ret) " iommufd=%d id=%u data_type=%u entry_len=%u entry_num=%u done_num=%u data_ptr=0x%"PRIx64" (%d)"
-iommufd_backend_alloc_viommu(int iommufd, uint32_t dev_id, uint32_t type, uint32_t hwpt_id, uint64_t data_ptr, uint32_t data_len, uint32_t viommu_id, int ret) " iommufd=%d type=%u dev_id=%u hwpt_id=%u data_ptr=0x%"PRIx64" data_len=0x%x viommu_id=%u (%d)"
+iommufd_backend_alloc_viommu(int iommufd, uint32_t dev_id, uint32_t type, uint32_t hwpt_id, uint64_t data_ptr, uint32_t data_len, uint32_t viommu_id, int ret) " iommufd=%d dev_id=%u type=%u hwpt_id=%u data_ptr=0x%"PRIx64" data_len=0x%x viommu_id=%u (%d)"
 iommufd_backend_alloc_vdev(int iommufd, uint32_t dev_id, uint32_t viommu_id, uint64_t virt_id, uint32_t vdev_id, int ret) " iommufd=%d dev_id=%u viommu_id=%u virt_id=0x%"PRIx64" vdev_id=%u (%d)"
 iommufd_viommu_alloc_eventq(int iommufd, uint32_t viommu_id, uint32_t type, uint32_t veventq_id, uint32_t veventq_fd, int ret) " iommufd=%d viommu_id=%u type=%u veventq_id=%u veventq_fd=%u (%d)"
 iommufd_backend_alloc_hw_queue(int iommufd, uint32_t viommu_id, uint32_t queue_type, uint32_t index, uint64_t addr, uint64_t size, uint32_t queue_id, int ret) " iommufd=%d viommu_id=%u queue_type=%u index=%u addr=0x%"PRIx64" size=0x%"PRIx64" queue_id=%u (%d)"
Signature · 1 line
2.53.0
#20 lore raw

[PULL 29/32] hw/ssi: xilinx_spips: Fix dummy phase handling

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

The ZynqMP generic FIFO encodes dummy phases as a number of dummy cycles. QEMU's SSI bus transfers whole bytes, so the controller model must convert the programmed cycle count to the number of SSI byte transfers needed for the selected SPI, dual SPI or quad SPI mode.

The legacy Xilinx QSPI snoop paths had the opposite problem after the m25p80 dummy handling was fixed. They still treated each dummy byte queued through the FIFO as a request to generate several SSI transfers based on the current link width. The flash model now consumes dummy phases as byte counts, so the manual FIFO path should forward one SSI transfer per dummy byte.

Update the Xilinx QSPI dummy accounting consistently for the generic FIFO, manual FIFO and LQSPI direct-read paths. Also make the command table report the dummy byte counts consumed by m25p80 for dual and quad output reads, and account for the mode byte before LQSPI data reads begin.

This matches the ZynqMP TRM (ug1085, v2.2 [1]) description of the generic FIFO dummy cycle entry and keeps the controller side aligned with the flash model's dummy byte ownership.

The description of the generic command fifo register says:

When [receive, transmit, data_xfer] = [0,0,1], the [immediate_data] field represents the number of dummy cycle sent on the SPI interface.

[1] https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf
table 24‐22, an example of Generic FIFO Contents for Quad I/O Read Command (EBh)

Fixes ef06ca3946e2 ("xilinx_spips: Add support for RX discard and RX drain")
Fixes c95997a39de6 ("xilinx_spips: Add support for the ZynqMP Generic QSPI")

Message-ID: <[email protected]>

---
 include/hw/ssi/xilinx_spips.h |   2 +-
 hw/ssi/xilinx_spips.c         | 123 +++++++++++++++++++++++++---------
 2 files changed, 91 insertions(+), 34 deletions(-)
include/hw/ssi/xilinx_spips.h +1 -1
index c8f6c5053c4..d1eefa4ba67 100644
@@ -69,7 +69,7 @@ struct XilinxSPIPS {
     uint8_t num_busses;
 
     uint8_t snoop_state;
-    int cmd_dummies;
+    int cmd_dummy_bytes;
     uint8_t link_state;
     uint8_t link_state_next;
     uint8_t link_state_next_when;
hw/ssi/xilinx_spips.c +90 -33

241 lines not on this page · raw message

Signature · 1 line
2.53.0
#21 lore raw

[PULL 30/32] hw/ssi: aspeed_smc: Fix direct-read dummy bytes

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

m25p80 now consumes fast-read dummy phases as byte counts. The ASPEED SMC direct-read path still treated the CEx dummy field as raw cycles and emitted field * 8 SSI transfers. Convert the ASPEED dummy field to SSI byte transfers using the selected direct-read data width.

Fixes ac2810defa9d ("aspeed/smc: handle dummy bytes when doing fast reads in command mode")

Message-ID: <[email protected]>

---
 hw/ssi/aspeed_smc.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)
hw/ssi/aspeed_smc.c +15 -6
index d87fbd798c6..3f957d153f8 100644
@@ -449,19 +449,28 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl,
     return addr;
 }
 
-static int aspeed_smc_flash_dummies(const AspeedSMCFlash *fl)
+static int aspeed_smc_flash_dummy_bytes(const AspeedSMCFlash *fl)
 {
     const AspeedSMCState *s = fl->controller;
     uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->cs];
     uint32_t dummy_high = (r_ctrl0 >> CTRL_DUMMY_HIGH_SHIFT) & 0x1;
     uint32_t dummy_low = (r_ctrl0 >> CTRL_DUMMY_LOW_SHIFT) & 0x3;
-    uint32_t dummies = ((dummy_high << 2) | dummy_low) * 8;
+    uint32_t dummy_bytes = (dummy_high << 2) | dummy_low;
 
-    if (r_ctrl0 & CTRL_IO_DUAL_ADDR_DATA) {
-        dummies /= 2;
+    /*
+     * Scale the controller dummy field to SSI byte transfers using the
+     * direct-read dummy/address bus width.
+     */
+    if ((r_ctrl0 & CTRL_IO_QPI) ||
+        ((r_ctrl0 & CTRL_IO_QUAD_DATA) &&
+         (r_ctrl0 & CTRL_IO_QUAD_ADDR_DATA))) {
+        dummy_bytes *= 4;
+    } else if ((r_ctrl0 & CTRL_IO_DUAL_DATA) &&
+               (r_ctrl0 & CTRL_IO_DUAL_ADDR_DATA)) {
+        dummy_bytes *= 2;
     }
 
-    return dummies;
+    return dummy_bytes;
 }
 
 static void aspeed_smc_flash_setup(AspeedSMCFlash *fl, uint32_t addr)
@@ -487,7 +496,7 @@ static void aspeed_smc_flash_setup(AspeedSMCFlash *fl, uint32_t addr)
      * settings, let's check for fast read mode.
      */
     if (aspeed_smc_flash_mode(fl) == CTRL_FREADMODE) {
-        for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) {
+        for (i = 0; i < aspeed_smc_flash_dummy_bytes(fl); i++) {
             ssi_transfer(fl->controller->spi, s->regs[R_DUMMY_DATA] & 0xff);
         }
     }
Signature · 1 line
2.53.0
#22 lore raw

[PULL 25/32] hw/block: m25p80: Fix dummy byte handling for Winbond flash

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

The m25p80 model uses s->needed_bytes to track how many bytes a controller must send after an opcode before the flash model can enter the data phase. For address-bearing commands this includes the address bytes. For fast-read commands it also includes the dummy phase.

The tricky part is that flash datasheets describe the dummy phase in clock cycles, while the QEMU SSI interface advances the flash model one transferred byte at a time. The dummy clock count therefore has to be converted to the number of SSI bytes that the controller will actually emit.

Some controllers have drivers that push these dummy bytes into a FIFO. Other controllers are programmed with a dummy-cycle count and generate the clocks themselves. The flash model still has to use the same byte count that a FIFO-style controller or the Linux spi-mem layer would use, otherwise the model waits too long and drops the first data bytes.

Let's fix the inconsistency from the flash side first. We start from an easy one, the Winbond flashes.

Per the Windbond W25Q256JV datasheet [1] instruction set table (chapter 8.1.2, 8.1.3, 8.1.4, 8.1.5), fix the wrong number of dummy bytes needed for fast read commands.

[1] https://www.winbond.com/resource-files/w25q256jv%20spi%20revb%2009202016.pdf

Fixes fe8477052831 ("m25p80: Fix QIOR/DIOR handling for Winbond")
Fixes 3830c7a460b8 ("m25p80: Fix WINBOND fast read command handling")
Fixes cf6f1efe0b57 ("m25p80: Fast read commands family changes")

Message-ID: <[email protected]>

---
 hw/block/m25p80.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
hw/block/m25p80.c +2 -2
index 4a4cda66024..59ecb32c0a2 100644
@@ -1004,7 +1004,7 @@ static void decode_fast_read_cmd(Flash *s)
         s->needed_bytes += 1;
         break;
     case MAN_WINBOND:
-        s->needed_bytes += 8;
+        s->needed_bytes += 1;
         break;
     case MAN_NUMONYX:
         s->needed_bytes += numonyx_extract_cfg_num_dummies(s);
@@ -1099,7 +1099,7 @@ static void decode_qio_read_cmd(Flash *s)
     switch (get_man(s)) {
     case MAN_WINBOND:
         s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN;
-        s->needed_bytes += 4;
+        s->needed_bytes += 2;
         break;
     case MAN_SPANSION:
         s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
Signature · 1 line
2.53.0
#23 lore raw

[PULL 21/32] hw/arm: Add basic FlexCAN3 support to TYPE_FSL_IMX8MP and imx8mp-evk

In reply to Philippe Mathieu-Daudé

From: Bernhard Beschow <[email protected]>

Real hardware supports CAN FD which is missing in the emulation and is considered future work. Still, CAN communication already works under Linux.

Message-ID: <[email protected]>

---
 docs/system/arm/imx8m.rst   |  1 +
 include/hw/arm/fsl-imx8mp.h |  8 ++++++++
 hw/arm/fsl-imx8mp.c         | 38 +++++++++++++++++++++++++++++++++++++
 hw/arm/imx8mp-evk.c         | 21 ++++++++++++++++++++
 hw/misc/imx8mp_ccm.c        |  3 +++
 hw/arm/Kconfig              |  1 +
 6 files changed, 72 insertions(+)
docs/system/arm/imx8m.rst +1 -0
index afbc33b2f40..1bcb8255be5 100644
@@ -18,6 +18,7 @@ following devices:
  * 1 Designware PCI Express Controller
  * 1 Ethernet Controller
  * 2 Designware USB 3 Controllers
+ * 2 FlexCAN 3 CAN Controllers (``imx8mp-evk`` only)
  * 5 GPIO Controllers
  * 6 I2C Controllers
  * 3 SPI Controllers
include/hw/arm/fsl-imx8mp.h +8 -0
index 3b6183ed1d6..2be3c51af56 100644
@@ -17,6 +17,7 @@
 #include "hw/misc/imx7_snvs.h"
 #include "hw/misc/imx8mp_analog.h"
 #include "hw/misc/imx8mp_ccm.h"
+#include "hw/net/flexcan.h"
 #include "hw/net/imx_fec.h"
 #include "hw/core/or-irq.h"
 #include "hw/pci-host/designware.h"
@@ -37,6 +38,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
 #define FSL_IMX8MP_RAM_SIZE_MAX     (8 * GiB)
 
 enum FslImx8mpConfiguration {
+    FSL_IMX8MP_NUM_CANS         = 2,
     FSL_IMX8MP_NUM_CPUS         = 4,
     FSL_IMX8MP_NUM_ECSPIS       = 3,
     FSL_IMX8MP_NUM_GPIOS        = 5,
@@ -68,11 +70,14 @@ struct FslImx8mpState {
     USBDWC3            usb[FSL_IMX8MP_NUM_USBS];
     DesignwarePCIEHost pcie;
     FslImx8mPciePhyState   pcie_phy;
+    FlexcanState       flexcan[FSL_IMX8MP_NUM_CANS];
     OrIRQState         gpt5_gpt6_irq;
     MemoryRegion       ocram;
 
     uint32_t           phy_num;
     bool               phy_connected;
+
+    CanBusState       *canbus[FSL_IMX8MP_NUM_CANS];
 };
 
 enum FslImx8mpMemoryRegions {
@@ -279,6 +284,9 @@ enum FslImx8mpIrqs {
     FSL_IMX8MP_PCI_INTC_IRQ = 124,
     FSL_IMX8MP_PCI_INTD_IRQ = 123,
     FSL_IMX8MP_PCI_MSI_IRQ  = 140,
+
+    FSL_IMX8MP_FLEXCAN1_IRQ  = 142,
+    FSL_IMX8MP_FLEXCAN2_IRQ  = 144,
 };
 
 #endif /* FSL_IMX8MP_H */
hw/arm/fsl-imx8mp.c +38 -0
index 7c03ed3c347..bcd91739d9b 100644
@@ -246,6 +246,11 @@ static void fsl_imx8mp_init(Object *obj)
         object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
     }
 
+    for (i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
+        g_autofree char *name = g_strdup_printf("flexcan%d", i);
+        object_initialize_child(obj, name, &s->flexcan[i], TYPE_CAN_FLEXCAN3);
+    }
+
     object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET);
 
     object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
@@ -669,6 +674,34 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
                     fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
 
+    /* FlexCANs */
+    for (i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
+        static const struct {
+            hwaddr addr;
+            unsigned int irq;
+        } flexcan_table[FSL_IMX8MP_NUM_CANS] = {
+            {
+                fsl_imx8mp_memmap[FSL_IMX8MP_FLEXCAN1].addr,
+                FSL_IMX8MP_FLEXCAN1_IRQ
+            }, {
+                fsl_imx8mp_memmap[FSL_IMX8MP_FLEXCAN2].addr,
+                FSL_IMX8MP_FLEXCAN2_IRQ
+            },
+        };
+
+        object_property_set_link(OBJECT(&s->flexcan[i]), "clock-control-module",
+                                 OBJECT(&s->ccm), &error_abort);
+        object_property_set_link(OBJECT(&s->flexcan[i]), "canbus",
+                                 OBJECT(s->canbus[i]), &error_abort);
+
+        sysbus_realize(SYS_BUS_DEVICE(&s->flexcan[i]), &error_abort);
+
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->flexcan[i]), 0,
+                        flexcan_table[i].addr);
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->flexcan[i]), 0,
+                           qdev_get_gpio_in(gicdev, flexcan_table[i].irq));
+    }
+
     /* On-Chip RAM */
     if (!memory_region_init_ram(&s->ocram, OBJECT(dev), "imx8mp.ocram",
                                 fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
@@ -684,6 +717,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
         switch (i) {
         case FSL_IMX8MP_ANA_PLL:
         case FSL_IMX8MP_CCM:
+        case FSL_IMX8MP_FLEXCAN1 ... FSL_IMX8MP_FLEXCAN2:
         case FSL_IMX8MP_GIC_DIST:
         case FSL_IMX8MP_GIC_REDIST:
         case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
@@ -715,6 +749,10 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
 static const Property fsl_imx8mp_properties[] = {
     DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mpState, phy_num, 0),
     DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true),
+    DEFINE_PROP_LINK("canbus0", FslImx8mpState, canbus[0], TYPE_CAN_BUS,
+                     CanBusState *),
+    DEFINE_PROP_LINK("canbus1", FslImx8mpState, canbus[1], TYPE_CAN_BUS,
+                     CanBusState *),
 };
 
 static void fsl_imx8mp_class_init(ObjectClass *oc, const void *data)
hw/arm/imx8mp-evk.c +21 -0
index ca0ee2d3f2e..16e9722d146 100644
@@ -26,6 +26,7 @@ struct FslImx8mpEvkState {
     MachineState parent_obj;
 
     FslImx8mpState soc;
+    CanBusState *canbus[FSL_IMX8MP_NUM_CANS];
 
     struct arm_boot_info boot_info;
 };
@@ -86,6 +87,12 @@ static void imx8mp_evk_init(MachineState *machine)
 
     object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX8MP);
     object_property_set_uint(OBJECT(&s->soc), "fec1-phy-num", 1, &error_fatal);
+    for (int i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
+        g_autofree char *bus_name = g_strdup_printf("canbus%d", i);
+
+        object_property_set_link(OBJECT(&s->soc), bus_name,
+                                 OBJECT(s->canbus[i]), &error_fatal);
+    }
     sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->soc), &error_fatal);
 
     memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
@@ -122,6 +129,19 @@ static const char *imx8mp_evk_get_default_cpu_type(const MachineState *ms)
     return ARM_CPU_TYPE_NAME("cortex-a53");
 }
 
+static void imx8mp_evk_machine_init(Object *obj)
+{
+    FslImx8mpEvkState *s = IMX8MPEVK_MACHINE(obj);
+
+    object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
+                             (Object **)&s->canbus[0],
+                             object_property_allow_set_link, 0);
+
+    object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
+                             (Object **)&s->canbus[1],
+                             object_property_allow_set_link, 0);
+}
+
 static void imx8mp_evk_machine_class_init(ObjectClass *oc, const void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -140,6 +160,7 @@ static const TypeInfo imx8mp_evk_machine_types[] = {
         .name = TYPE_IMX8MPEVK_MACHINE,
         .parent = TYPE_MACHINE,
         .class_init = imx8mp_evk_machine_class_init,
+        .instance_init = imx8mp_evk_machine_init,
         .instance_size = sizeof(FslImx8mpEvkState),
         .interfaces = aarch64_machine_interfaces,
     },
hw/misc/imx8mp_ccm.c +3 -0
index 911911ed865..97d363e79d8 100644
@@ -129,6 +129,9 @@ static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
     case CLK_HIGH:
         freq = CKIH_FREQ;
         break;
+    case CLK_CAN:
+        freq = 40000000; /* 40Mhz, taken from device tree */
+        break;
     case CLK_IPG:
     case CLK_IPG_HIGH:
         /*
hw/arm/Kconfig +1 -0
index f9a225c19bc..82e0bc2e700 100644
@@ -601,6 +601,7 @@ config FSL_IMX8MP
     imply I2C_DEVICES
     imply PCI_DEVICES
     select ARM_GIC
+    select CAN_FLEXCAN
     select FSL_IMX8MP_ANALOG
     select FSL_IMX8MP_CCM
     select IMX
Signature · 1 line
2.53.0
#24 lore raw

[PULL 27/32] hw/block: m25p80: Fix dummy byte handling for Macronix flash

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

Macronix flashes expose DC[1:0] bits in the volatile configuration register [1]. These bits select the number of dummy clock cycles used by the fast-read command families.

Convert the Macronix dummy-cycle settings through per-command-family tables and round up the non-byte-aligned cases that the byte-oriented SSI model cannot represent exactly.

[1] https://www.macronix.com/Lists/Datasheet/Attachments/8657/MX66L51235F,%203V,%20512Mb,%20v1.1.pdf

Fixes cf6f1efe0b57 ("m25p80: Fast read commands family changes")

Message-ID: <[email protected]>

---
 hw/block/m25p80.c | 63 +++++++++++++++++++++++++++--------------------
 1 file changed, 36 insertions(+), 27 deletions(-)
hw/block/m25p80.c +36 -27
index 83d1ce1f956..d7a9d793737 100644
@@ -1024,6 +1024,39 @@ static uint8_t numonyx_extract_cfg_dummy_bytes(Flash *s)
     return dummy_bits / 8;
 }
 
+static uint8_t macronix_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
+{
+    static const uint8_t dummy_cycles_fast[4] = { 8, 6, 8, 10 };
+    static const uint8_t dummy_cycles_dio[4] = { 4, 6, 8, 10 };
+    static const uint8_t dummy_cycles_qio[4] = { 6, 4, 8, 10 };
+    const uint8_t *dummy_cycles = dummy_cycles_fast;
+    uint8_t dummy_bits;
+
+    switch (s->cmd_in_progress) {
+    case DIOR:
+    case DIOR4:
+        dummy_cycles = dummy_cycles_dio;
+        break;
+    case QIOR:
+    case QIOR4:
+        dummy_cycles = dummy_cycles_qio;
+        break;
+    default:
+        break;
+    }
+
+    dummy_bits = dummy_cycles[extract32(s->volatile_cfg, 6, 2)];
+    dummy_bits *= bus_width;
+
+    /*
+     * Assert that the dummy bit count is byte-aligned
+     * as SSI core can only consume whole dummy bytes.
+     */
+    assert(dummy_bits % 8 == 0);
+
+    return dummy_bits / 8;
+}
+
 static void decode_fast_read_cmd(Flash *s)
 {
     s->needed_bytes = get_addr_length(s);
@@ -1039,11 +1072,7 @@ static void decode_fast_read_cmd(Flash *s)
         s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
         break;
     case MAN_MACRONIX:
-        if (extract32(s->volatile_cfg, 6, 2) == 1) {
-            s->needed_bytes += 6;
-        } else {
-            s->needed_bytes += 8;
-        }
+        s->needed_bytes += macronix_extract_cfg_dummy_bytes(s, 1);
         break;
     case MAN_SPANSION:
         s->needed_bytes += extract32(s->spansion_cr2v,
@@ -1091,17 +1120,7 @@ static void decode_dio_read_cmd(Flash *s)
         s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
         break;
     case MAN_MACRONIX:
-        switch (extract32(s->volatile_cfg, 6, 2)) {
-        case 1:
-            s->needed_bytes += 6;
-            break;
-        case 2:
-            s->needed_bytes += 8;
-            break;
-        default:
-            s->needed_bytes += 4;
-            break;
-        }
+        s->needed_bytes += macronix_extract_cfg_dummy_bytes(s, 2);
         break;
     case MAN_ISSI:
         /*
@@ -1141,17 +1160,7 @@ static void decode_qio_read_cmd(Flash *s)
         s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
         break;
     case MAN_MACRONIX:
-        switch (extract32(s->volatile_cfg, 6, 2)) {
-        case 1:
-            s->needed_bytes += 4;
-            break;
-        case 2:
-            s->needed_bytes += 8;
-            break;
-        default:
-            s->needed_bytes += 6;
-            break;
-        }
+        s->needed_bytes += macronix_extract_cfg_dummy_bytes(s, 4);
         break;
     case MAN_ISSI:
         /*
Signature · 1 line
2.53.0
#25 lore raw

[PULL 18/32] hw/net/can/flexcan: Subclass TYPE_CAN_FLEXCAN

In reply to Philippe Mathieu-Daudé

From: Bernhard Beschow <[email protected]>

Subclass TYPE_CAN_FLEXCAN, yielding TYPE_CAN_FLEXCAN2 and TYPE_CAN_FLEXCAN3.
Since TYPE_CAN_FLEXCAN is now abstract, TYPE_FSL_IMX6 needs to use TYPE_CAN_FLEXCAN2. TYPE_CAN_FLEXCAN3 will be used in TYPE_FSL_IMX8MP.

Message-ID: <[email protected]>

---
 include/hw/net/flexcan.h |  4 +-
 hw/arm/fsl-imx6.c        |  2 +-
 hw/net/can/flexcan.c     | 80 ++++++++++++++++++++++++++++++++--------
 3 files changed, 69 insertions(+), 17 deletions(-)
include/hw/net/flexcan.h +3 -1
index 153afc1e03b..32de7b904af 100644
@@ -139,7 +139,9 @@ typedef struct FlexcanState {
 } FlexcanState;
 
 #define TYPE_CAN_FLEXCAN "flexcan"
-
 OBJECT_DECLARE_SIMPLE_TYPE(FlexcanState, CAN_FLEXCAN);
 
+#define TYPE_CAN_FLEXCAN2 "flexcan2"
+#define TYPE_CAN_FLEXCAN3 "flexcan3"
+
 #endif
hw/arm/fsl-imx6.c +1 -1
index 585c935b899..eec9673c6fb 100644
@@ -92,7 +92,7 @@ static void fsl_imx6_init(Object *obj)
     }
     for (i = 0; i < FSL_IMX6_NUM_CANS; i++) {
         snprintf(name, NAME_SIZE, "flexcan%d", i + 1);
-        object_initialize_child(obj, name, &s->flexcan[i], TYPE_CAN_FLEXCAN);
+        object_initialize_child(obj, name, &s->flexcan[i], TYPE_CAN_FLEXCAN2);
     }
     for (i = 0; i < FSL_IMX6_NUM_WDTS; i++) {
         snprintf(name, NAME_SIZE, "wdt%d", i);
hw/net/can/flexcan.c +65 -15

113 lines not on this page · raw message

Signature · 1 line
2.53.0
#26 lore raw

[PULL 28/32] hw/ssi: npcm7xx_fiu: Correct the dummy cycle emulation logic

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

Change send_dummy_bits() to send_dummy_bytes() as the FIU register fields are programmed from spi_mem_op.dummy.nbytes, so they already describe byte transfers.

Verified the changes by booting OpenBMC image on gbs machine all the way to the Linux login shell:

$ qemu-system-arm -machine quanta-gbs-bmc -nographic \
      -drive file=image.mtd,if=mtd,bus=0,unit=0,format=raw
Fixes b821242c7b3b ("hw/ssi: NPCM7xx Flash Interface Unit device model")

Message-ID: <[email protected]>

---
 hw/ssi/npcm7xx_fiu.c | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)
hw/ssi/npcm7xx_fiu.c +8 -17
index 2d5bed005ad..d41d877cfbe 100644
@@ -150,7 +150,7 @@ static uint64_t npcm7xx_fiu_flash_read(void *opaque, hwaddr addr,
     NPCM7xxFIUState *fiu = f->fiu;
     uint64_t value = 0;
     uint32_t drd_cfg;
-    int dummy_cycles;
+    int dummy_bytes;
     int i;
 
     if (fiu->active_cs != -1) {
@@ -180,10 +180,8 @@ static uint64_t npcm7xx_fiu_flash_read(void *opaque, hwaddr addr,
         break;
     }
 
-    /* Flash chip model expects one transfer per dummy bit, not byte */
-    dummy_cycles =
-        (FIU_DRD_CFG_DBW(drd_cfg) * 8) >> FIU_DRD_CFG_ACCTYPE(drd_cfg);
-    for (i = 0; i < dummy_cycles; i++) {
+    dummy_bytes = FIU_DRD_CFG_DBW(drd_cfg);
+    for (i = 0; i < dummy_bytes; i++) {
         ssi_transfer(fiu->spi, 0);
     }
 
@@ -305,20 +303,13 @@ static void send_address(SSIBus *spi, unsigned int addsiz, uint32_t addr)
     }
 }
 
-/* Send the number of dummy bits specified in the UMA config register. */
-static void send_dummy_bits(SSIBus *spi, uint32_t uma_cfg, uint32_t uma_cmd)
+/* Send the number of dummy bytes specified in the UMA config register */
+static void send_dummy_bytes(SSIBus *spi, uint32_t uma_cfg)
 {
-    unsigned int bits_per_clock = 1U << FIU_UMA_CFG_DBPCK(uma_cfg);
     unsigned int i;
 
     for (i = 0; i < FIU_UMA_CFG_DBSIZ(uma_cfg); i++) {
-        /* Use bytes 0 and 1 first, then keep repeating byte 2 */
-        unsigned int field = (i < 2) ? ((i + 1) * 8) : 24;
-        unsigned int j;
-
-        for (j = 0; j < 8; j += bits_per_clock) {
-            ssi_transfer(spi, extract32(uma_cmd, field + j, bits_per_clock));
-        }
+        ssi_transfer(spi, 0);
     }
 }
 
@@ -354,8 +345,8 @@ static void npcm7xx_fiu_uma_transaction(NPCM7xxFIUState *s)
         ssi_transfer(s->spi, extract32(s->regs[reg], field, 8));
     }
 
-    /* Send dummy bits, if present. */
-    send_dummy_bits(s->spi, uma_cfg, s->regs[NPCM7XX_FIU_UMA_CMD]);
+    /* Send dummy bytes, if present */
+    send_dummy_bytes(s->spi, uma_cfg);
 
     /* Read data, if present. */
     for (i = 0; i < FIU_UMA_CFG_RDATSIZ(uma_cfg); i++) {
Signature · 1 line
2.53.0
#27 lore raw

[PULL 23/32] hw/acpi/ich9: move initial property values into ich9_reset_properties()

In reply to Philippe Mathieu-Daudé

From: Mark Cave-Ayland <[email protected]>

Message-ID: <[email protected]>

---
 include/hw/acpi/ich9.h | 2 ++
 hw/acpi/ich9.c         | 8 ++++++--
 hw/isa/lpc_ich9.c      | 1 +
 3 files changed, 9 insertions(+), 2 deletions(-)
include/hw/acpi/ich9.h +2 -0
index 019f0915c11..30990fcef53 100644
@@ -81,6 +81,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq);
 void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
 extern const VMStateDescription vmstate_ich9_pm;
 
+void ich9_pm_reset_properties(ICH9LPCPMRegs *pm);
+
 void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm);
 
 void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
hw/acpi/ich9.c +6 -2
index 5c7dfb2c69d..5e8f8a7eafa 100644
@@ -388,9 +388,8 @@ static void ich9_pm_set_keep_pci_slot_hpc(Object *obj, bool value, Error **errp)
     s->pm.keep_pci_slot_hpc = value;
 }
 
-void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
+void ich9_pm_reset_properties(ICH9LPCPMRegs *pm)
 {
-    static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
     pm->acpi_memory_hotplug.is_enabled = true;
     pm->disable_s3 = 0;
     pm->disable_s4 = 0;
@@ -398,6 +397,11 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
     pm->acpi_pci_hotplug.use_acpi_hotplug_bridge = true;
     pm->keep_pci_slot_hpc = true;
     pm->enable_tco = true;
+}
+
+void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
+{
+    static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
 
     object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
                                    &pm->pm_io_base, OBJ_PROP_FLAG_READ);
hw/isa/lpc_ich9.c +1 -0
index 9cec18a378c..edf9783ec8d 100644
@@ -701,6 +701,7 @@ static void ich9_lpc_initfn(Object *obj)
                                    &lpc->smi_negotiated_features,
                                    OBJ_PROP_FLAG_READ);
 
+    ich9_pm_reset_properties(&lpc->pm);
     ich9_pm_add_properties(obj, &lpc->pm);
 }
 
Signature · 1 line
2.53.0
#28 lore raw

[PULL 16/32] hw/intc/loongarch_dintc: Fix OOB access in DINT MMIO write handler

In reply to Philippe Mathieu-Daudé

From: Song Gao <[email protected]>

Validate guest-controlled cpu_num before using it to index the cpu[] array or pass to async_run_on_cpu(). Without this check, a malicious guest can trigger a NULL pointer dereference in async_run_on_cpu() and an out-of-bounds array access in qemu_set_irq(), causing host crash.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3616

Fixes 0d148eaf5a3e ("hw/loongarch: Implement dintc set irq")

Message-ID: <[email protected]>

---
 hw/intc/loongarch_dintc.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
hw/intc/loongarch_dintc.c +13 -0
index c877a8003b7..e40292887c2 100644
@@ -19,6 +19,7 @@
 #include "target/loongarch/cpu.h"
 #include "qemu/error-report.h"
 #include "system/hw_accel.h"
+#include "qemu/log.h"
 
 /* msg addr field */
 FIELD(MSG_ADDR, IRQ_NUM, 4, 8)
@@ -52,7 +53,19 @@ static void loongarch_dintc_mem_write(void *opaque, hwaddr addr,
     CPUState *cs;
 
     cpu_num = FIELD_EX64(msg_addr, MSG_ADDR, CPU_NUM);
+
+    /* Validate cpu_num against the configured number of CPUs */
+    if (cpu_num >= s->num_cpu) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "loongarch-dintc: invalid cpu number%d\n", cpu_num);
+        return;
+    }
     cs = cpu_by_arch_id(cpu_num);
+    if (!cs) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "loongarch-dintc: no CPU for arch_id %d\n", cpu_num);
+        return;
+    }
     irq_num = FIELD_EX64(msg_addr, MSG_ADDR, IRQ_NUM);
 
     async_run_on_cpu(cs, do_set_vcpu_dintc_irq,
Signature · 1 line
2.53.0
#29 lore raw

[PULL 31/32] Revert "aspeed/smc: Fix number of dummy cycles for FAST_READ_4 command"

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

This reverts commit 7faf6f1790dddf9f3acf6ddd95f7bbc1b4a755d0.

The incorrect implementation of dummy cycles in m25p80 model is now corrected. Revert this commit.

Message-ID: <[email protected]>

---
 hw/ssi/aspeed_smc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/ssi/aspeed_smc.c +1 -1
index 3f957d153f8..58e5087b570 100644
@@ -568,11 +568,11 @@ static int aspeed_smc_num_dummies(uint8_t command)
     case FAST_READ:
     case DOR:
     case QOR:
-    case FAST_READ_4:
     case DOR_4:
     case QOR_4:
         return 1;
     case DIOR:
+    case FAST_READ_4:
     case DIOR_4:
         return 2;
     case QIOR:
Signature · 1 line
2.53.0
#30 lore raw

[PULL 12/32] hw/scsi/mptsas: Reset doorbell state on reset

In reply to Philippe Mathieu-Daudé

From: Peter Maydell <[email protected]>

Currently the mptsas reset function clears intr_status, but it doesn't reset the doorbell state machine. This means that the state machine and the interrupt state get out of sync, and the guest can trigger an assertion failure in mptsas_doorbell_read() where s->doorbell_state is still DOORBELL_READ but s->intr_status does not have MPI_HIS_DOORBELL_INTERRUPT set.

Fix this by having reset also reset the doorbell state. Strictly speaking we don't need to also clear doorbell_reply_idx and doorbell_reply_size, because those are only read when in DOORBELL_READ state, and the code always sets them up before transitioning into that state. But it's less confusing to clear them out on reset.

Cc: [email protected]
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/304

Message-ID: <[email protected]>

---
 hw/scsi/mptsas.c | 4 ++++
 1 file changed, 4 insertions(+)
hw/scsi/mptsas.c +4 -0
index e4a7b2fee4a..5df124c0ce5 100644
@@ -811,6 +811,10 @@ static void mptsas_soft_reset(MPTSASState *s)
     s->intr_status = 0;
     s->intr_mask = save_mask;
 
+    s->doorbell_state = DOORBELL_NONE;
+    s->doorbell_reply_idx = 0;
+    s->doorbell_reply_size = 0;
+
     s->reply_free_tail = 0;
     s->reply_free_head = 0;
     s->reply_post_tail = 0;
Signature · 1 line
2.53.0
#31 lore raw

[PULL 19/32] hw/arm/imx8mp-evk: Open code DEFINE_MACHINE_AARCH64

In reply to Philippe Mathieu-Daudé

From: Bernhard Beschow <[email protected]>

Open code the DEFINE_MACHINE_AARCH64 macro in preparation of creating FslImx8mpEvkState class, needed for FlexCAN emulation.

Message-ID: <[email protected]>

---
 hw/arm/imx8mp-evk.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
hw/arm/imx8mp-evk.c +13 -2
index b84ac91a17d..4a0c9df76b7 100644
@@ -113,8 +113,10 @@ static const char *imx8mp_evk_get_default_cpu_type(const MachineState *ms)
     return ARM_CPU_TYPE_NAME("cortex-a53");
 }
 
-static void imx8mp_evk_machine_init(MachineClass *mc)
+static void imx8mp_evk_machine_class_init(ObjectClass *oc, const void *data)
 {
+    MachineClass *mc = MACHINE_CLASS(oc);
+
     mc->desc = "NXP i.MX 8M Plus EVK Board";
     mc->init = imx8mp_evk_init;
     mc->default_cpus = 4;
@@ -124,4 +126,13 @@ static void imx8mp_evk_machine_init(MachineClass *mc)
     mc->get_default_cpu_type = imx8mp_evk_get_default_cpu_type;
 }
 
-DEFINE_MACHINE_AARCH64("imx8mp-evk", imx8mp_evk_machine_init)
+static const TypeInfo imx8mp_evk_machine_types[] = {
+    {
+        .name = MACHINE_TYPE_NAME("imx8mp-evk"),
+        .parent = TYPE_MACHINE,
+        .class_init = imx8mp_evk_machine_class_init,
+        .interfaces = aarch64_machine_interfaces,
+    },
+};
+
+DEFINE_TYPES(imx8mp_evk_machine_types)
Signature · 1 line
2.53.0
#32 lore raw

[PULL 26/32] hw/block: m25p80: Fix dummy byte handling for Numonyx/Micron flash

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

Numonyx/Micron flashes [1] do not use one fixed dummy-phase width for all fast-read commands. The volatile configuration register stores a number of dummy clock cycles, and QEMU must convert that value to the number of SSI bytes consumed by the flash model.

Keep the existing default: 10 dummy clocks in Quad I/O mode and 8 dummy clocks otherwise. In Quad I/O and Dual I/O protocol modes, all command phases are transferred on 4 or 2 lines, so the dummy clock count still needs to be scaled by that bus width.

Standard SPI, also called extended SPI in the Micron datasheet, is more subtle. Quad Output Fast Read (6Bh) and Dual Output Fast Read (3Bh) keep the opcode and address phases on DQ0; their dummy phase is just a clock gap before data is returned on four or two output lines. Do not scale the dummy count for those output-only commands. Only Quad I/O Fast Read (EBh) and Dual I/O Fast Read (BBh) transfer the address and dummy phases on the 4-bit or 2-bit bus, so keep scaling those commands.

[1] https://docs.rs-online.com/cad7/0900766b8121bd3c.pdf

Fixes 23af26856606 ("hw/block/m25p80: Fix Numonyx fast read dummy cycle count")

Message-ID: <[email protected]>

---
 hw/block/m25p80.c | 55 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 42 insertions(+), 13 deletions(-)
hw/block/m25p80.c +42 -13
index 59ecb32c0a2..83d1ce1f956 100644
@@ -971,28 +971,57 @@ static uint8_t numonyx_mode(Flash *s)
     }
 }
 
-static uint8_t numonyx_extract_cfg_num_dummies(Flash *s)
+static uint8_t numonyx_extract_cfg_dummy_bytes(Flash *s)
 {
-    uint8_t num_dummies;
+    uint8_t dummy_bits;
     uint8_t mode;
-    assert(get_man(s) == MAN_NUMONYX);
 
     mode = numonyx_mode(s);
-    num_dummies = extract32(s->volatile_cfg, 4, 4);
+    dummy_bits = extract32(s->volatile_cfg, 4, 4);
 
-    if (num_dummies == 0x0 || num_dummies == 0xf) {
+    /*
+     * The default nubmer of dummy cycles is only related to the SPI
+     * protocol mode. For QSPI it is 10, otherwise it is 8.
+     */
+    if (dummy_bits == 0x0 || dummy_bits == 0xf) {
+        dummy_bits = (mode == MODE_QIO) ? 10 : 8;
+    }
+
+    /*
+     * Convert the number of dummy cycles to bytes.
+     *
+     * In the Dual I/O and Quad I/O protocols, all command phases use 2 or 4
+     * lines. In standard/extended SPI mode the phase width depends on the
+     * command sequence: output-only fast reads keep the dummy clocks on the
+     * single address line, while input/output fast reads use the same 2-line
+     * or 4-line phase as the address.
+     */
+
+    if (mode == MODE_QIO) {
+        dummy_bits *= 4;
+    } else if (mode == MODE_DIO) {
+        dummy_bits *= 2;
+    } else {
         switch (s->cmd_in_progress) {
         case QIOR:
         case QIOR4:
-            num_dummies = 10;
+            dummy_bits *= 4;
             break;
-        default:
-            num_dummies = (mode == MODE_QIO) ? 10 : 8;
+        case DIOR:
+        case DIOR4:
+            dummy_bits *= 2;
             break;
-        }
+         }
     }
 
-    return num_dummies;
+    /*
+     * Assert that the dummy bit count is byte-aligned
+     * as SSI core can only consume whole dummy bytes.
+     */
+    assert(dummy_bits % 8 == 0);
+
+    /* return the number of dummy bytes */
+    return dummy_bits / 8;
 }
 
 static void decode_fast_read_cmd(Flash *s)
@@ -1007,7 +1036,7 @@ static void decode_fast_read_cmd(Flash *s)
         s->needed_bytes += 1;
         break;
     case MAN_NUMONYX:
-        s->needed_bytes += numonyx_extract_cfg_num_dummies(s);
+        s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
         break;
     case MAN_MACRONIX:
         if (extract32(s->volatile_cfg, 6, 2) == 1) {
@@ -1059,7 +1088,7 @@ static void decode_dio_read_cmd(Flash *s)
                                     );
         break;
     case MAN_NUMONYX:
-        s->needed_bytes += numonyx_extract_cfg_num_dummies(s);
+        s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
         break;
     case MAN_MACRONIX:
         switch (extract32(s->volatile_cfg, 6, 2)) {
@@ -1109,7 +1138,7 @@ static void decode_qio_read_cmd(Flash *s)
                                     );
         break;
     case MAN_NUMONYX:
-        s->needed_bytes += numonyx_extract_cfg_num_dummies(s);
+        s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
         break;
     case MAN_MACRONIX:
         switch (extract32(s->volatile_cfg, 6, 2)) {
Signature · 1 line
2.53.0
#33 lore raw

[PULL 32/32] Revert "aspeed/smc: snoop SPI transfers to fake dummy cycles"

In reply to Philippe Mathieu-Daudé

From: Bin Meng <[email protected]>

This reverts commit f95c4bffdc4c53b29f89762cab4adc5a43f95daf.

The m25p80 model now accounts for fast-read dummy bytes in its command decoder. In ASPEED SMC model user mode, guest software already sends the complete byte stream, including any dummy bytes needed by the flash. Hence the model should just forward exactly the bytes supplied by the guest without the need of decoding guest-supplied flash op codes to inject extra dummy transfers.

Message-ID: <[email protected]>

---
 include/hw/ssi/aspeed_smc.h |   2 -
 hw/ssi/aspeed_smc.c         | 114 +-----------------------------------
 hw/ssi/trace-events         |   1 -
 3 files changed, 2 insertions(+), 115 deletions(-)
include/hw/ssi/aspeed_smc.h +0 -2
index 76831422c6f..a273365689e 100644
@@ -80,8 +80,6 @@ struct AspeedSMCState {
 
     AspeedSMCFlash flashes[ASPEED_SMC_CS_MAX];
 
-    uint8_t snoop_index;
-    uint8_t snoop_dummies;
     bool unselect;
 };
 
hw/ssi/aspeed_smc.c +2 -112

152 lines not on this page · raw message

hw/ssi/trace-events +0 -1
index 2f36cf96b8b..b9d86482974 100644
@@ -2,7 +2,6 @@
 
 aspeed_smc_flash_set_segment(int cs, uint64_t reg, uint64_t start, uint64_t end) "CS%d segreg=0x%"PRIx64" [ 0x%"PRIx64" - 0x%"PRIx64" ]"
 aspeed_smc_flash_read(int cs, uint64_t addr,  uint32_t size, uint64_t data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
-aspeed_smc_do_snoop(int cs, int index, int dummies, int data) "CS%d index:0x%x dummies:%d data:0x%x"
 aspeed_smc_flash_write(int cs, uint64_t addr,  uint32_t size, uint64_t data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
 aspeed_smc_read(uint64_t addr,  uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
 aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x"
Signature · 1 line
2.53.0
#34 lore raw
In reply to Philippe Mathieu-Daudé

Am 7. Juli 2026 13:11:50 UTC schrieb "Philippe Mathieu-Daudé" <[email protected]>:

Quoted 26 lines

The following changes since commit 94826ec1370328375c3b6d1e80fdc94c8f46c348:

Merge tag 'accel-20260706' of https://github.com/philmd/qemu into staging (2026-07-06 18:38:14 +0200)

are available in the Git repository at:

https://github.com/philmd/qemu.git tags/hw-misc-20260707

for you to fetch changes up to 04584a27dd59741bc20272c6faab96c08bcbb926:

Revert "aspeed/smc: snoop SPI transfers to fake dummy cycles" (2026-07-07 15:08:41 +0200)

----------------------------------------------------------------
Misc HW patches

- Fix in few trace event formats
- A pair of improvements in util/
- FlexCAN3 to imx8mp-evk board
- Various fixes in hw/
(EDU, ATI VGA, IDE AHCI, PCA9552, i8257 DMA,
e1000e/igb, MPT SAS, Hyper-V, QXL, M25P80)
----------------------------------------------------------------

BALATON Zoltan (1):
hw/display/ati: Include vga state in the blit context

Quoted 6 lines

Bernhard Beschow (5):
hw/net/can/flexcan: Wire clock control module via link property hw/net/can/flexcan: Subclass TYPE_CAN_FLEXCAN hw/arm/imx8mp-evk: Open code DEFINE_MACHINE_AARCH64 hw/arm/imx8mp-evk: Introduce FslImx8mpEvkState
hw/arm: Add basic FlexCAN3 support to TYPE_FSL_IMX8MP and imx8mp-evk

Thanks Phil! I owe you two beer (another one for the rs5c372). Or whatever liquid you like.

Best,
Bernhard

Quoted 95 lines

Bin Meng (8):
hw/block: m25p80: Fix dummy byte handling for Winbond flash hw/block: m25p80: Fix dummy byte handling for Numonyx/Micron flash hw/block: m25p80: Fix dummy byte handling for Macronix flash hw/ssi: npcm7xx_fiu: Correct the dummy cycle emulation logic hw/ssi: xilinx_spips: Fix dummy phase handling
hw/ssi: aspeed_smc: Fix direct-read dummy bytes
Revert "aspeed/smc: Fix number of dummy cycles for FAST_READ_4
command"
Revert "aspeed/smc: snoop SPI transfers to fake dummy cycles"

Denis V. Lunev (1):
hw/ide/ahci: cancel in-flight buffered reads on command engine restart

Dmitry Frolov (1):
utils/module: fix memleak in module_load()

Evgeny Kolmakov (1):
util/filemonitor-inotify: Use QEMU_LOCK_GUARD()

Junjie Cao (2):
hw/display/ati: reset host_data.next in write handler after flush hw/display/ati: guard against zero bpp in ati_host_data_flush

Mark Cave-Ayland (2):
hw/rtc/mc146818rtc: convert date from object prop to class prop hw/acpi/ich9: move initial property values into
ich9_reset_properties()

Peter Maydell (3):
hw/dma/i8257: Return zeroes for read_memory in verify mode hw/scsi/mptsas: Reset doorbell state on reset
hw/hyperv: Avoid crash if hyperv_find_cpu() passed invalid vp_index

Sanjeeva Yerrapureddy (1):
hw/net: fix e1000e/igb ip_len inflation by Ethernet minimum-frame
padding

Shameer Kolothum (1):
backends/iommufd: Fix dev_id and type order in viommu trace

Song Gao (1):
hw/intc/loongarch_dintc: Fix OOB access in DINT MMIO write handler

Thomas Huth (1):
hw/display/qxl: Fix mono cursor validation that can read past a cursor
chunk

Torin Carey (1):
hw/misc/edu: restrict dma access to dma buffer

yujun (3):
hw/gpio/pca9552: fix off-by-one in QOM led index validation
ebpf: fix swapped toeplitz/indirection args in set_data trace crypto/x509-utils: fix gnutls error code in crt_init failure path

docs/system/arm/imx8m.rst     |   1 +
include/hw/acpi/ich9.h        |   2 +
include/hw/arm/fsl-imx8mp.h   |   8 ++
include/hw/net/flexcan.h      |   4 +-
include/hw/ssi/aspeed_smc.h   |   2 -
include/hw/ssi/xilinx_spips.h |   2 +-
crypto/x509-utils.c           |   3 +-
ebpf/ebpf_rss.c               |   2 +-
hw/acpi/ich9.c                |   8 +-
hw/arm/fsl-imx6.c             |   5 +-
hw/arm/fsl-imx8mp.c           |  38 ++++++++++
hw/arm/imx8mp-evk.c           |  64 +++++++++++++---
hw/block/m25p80.c             | 122 +++++++++++++++++++-----------
hw/display/ati.c              |   2 +
hw/display/ati_2d.c           |  44 +++++------
hw/display/qxl-render.c       |   8 +-
hw/dma/i8257.c                |  13 ++++
hw/gpio/pca9552.c             |   8 +-
hw/hyperv/hyperv.c            |   4 +-
hw/ide/ahci.c                 |   3 +
hw/intc/loongarch_dintc.c     |  13 ++++
hw/isa/lpc_ich9.c             |   1 +
hw/misc/edu.c                 |  24 +++---
hw/misc/imx8mp_ccm.c          |   3 +
hw/net/can/flexcan.c          |  90 ++++++++++++++++++-----
hw/net/net_tx_pkt.c           |   7 +-
hw/rtc/mc146818rtc.c          |   4 +-
hw/scsi/mptsas.c              |   4 +
hw/ssi/aspeed_smc.c           | 135 +++++-----------------------------
hw/ssi/npcm7xx_fiu.c          |  25 ++-----
hw/ssi/xilinx_spips.c         | 123 ++++++++++++++++++++++---------
util/filemonitor-inotify.c    |  28 ++-----
util/module.c                 |   2 +-
backends/trace-events         |   2 +-
hw/arm/Kconfig                |   1 +
hw/ssi/trace-events           |   1 -
36 files changed, 488 insertions(+), 318 deletions(-)