From 8608ed356ef90815cc5bcf04fcdbde987fd24bca Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 11 Jan 2026 18:49:15 +0000 Subject: [PATCH 01/21] hw/misc/virt_ctrl: Fix incorrect trace event in read operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virt_ctrl_read() function currently invokes trace_virt_ctrl_write() instead of trace_virt_ctrl_read(). This results in read operations appearing as write operations in the trace output, which is misleading during debugging and analysis. Replace the incorrect trace call with the proper read-specific trace event to accurately reflect the hardware behavior. Fixes: 0791bc02b8fb ("m68k: add a system controller") Signed-off-by: Kuan-Wei Chiu Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260111184915.1363318-1-visitorckw@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/misc/virt_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c index 40747925a2..9b82e97ffd 100644 --- a/hw/misc/virt_ctrl.c +++ b/hw/misc/virt_ctrl.c @@ -43,7 +43,7 @@ static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size) break; } - trace_virt_ctrl_write(s, addr, size, value); + trace_virt_ctrl_read(s, addr, size, value); return value; } From 2622a178b6a7c9425f00d28a3b6543375f365308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 6 Feb 2026 14:19:00 -0800 Subject: [PATCH 02/21] hw/virtio: Constify virtio_is_big_endian() argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VirtIODevice argument is accessed read-only, make it const. Signed-off-by: Pierrick Bouvier Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260206221908.1451528-2-pierrick.bouvier@linaro.org> --- include/hw/virtio/virtio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 27cd98d2fe..65872f2c54 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -468,7 +468,7 @@ static inline bool virtio_host_has_feature(VirtIODevice *vdev, return virtio_has_feature(vdev->host_features, fbit); } -static inline bool virtio_is_big_endian(VirtIODevice *vdev) +static inline bool virtio_is_big_endian(const VirtIODevice *vdev) { if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); From 6325407f67d279801b59bbde113fe6cfe6623b83 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 12 Feb 2026 15:46:01 -0800 Subject: [PATCH 03/21] hw/virtio: rename virtio_is_big_endian to virtio_vdev_is_big_endian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renaming this function removes the confusion with existing virtio_is_big_endian cpu ops. Indeed, virtio_vdev_is_big_endian is *not* calling cpu virtio_is_big_endian everytime. Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260212234602.338131-3-pierrick.bouvier@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/net/virtio-net.c | 4 ++-- hw/virtio/vhost.c | 4 ++-- hw/virtio/virtio-pci.c | 8 ++++---- include/hw/virtio/virtio-access.h | 2 +- include/hw/virtio/virtio.h | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index cc89619a43..eccb48ad42 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -301,7 +301,7 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) if (n->needs_vnet_hdr_swap) { error_report("backend does not support %s vnet headers; " "falling back on userspace virtio", - virtio_is_big_endian(vdev) ? "BE" : "LE"); + virtio_vdev_is_big_endian(vdev) ? "BE" : "LE"); return; } @@ -343,7 +343,7 @@ static int virtio_net_set_vnet_endian_one(VirtIODevice *vdev, NetClientState *peer, bool enable) { - if (virtio_is_big_endian(vdev)) { + if (virtio_vdev_is_big_endian(vdev)) { return qemu_set_vnet_be(peer, enable); } else { return qemu_set_vnet_le(peer, enable); diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 52801c1796..e98e3a40a0 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1306,7 +1306,7 @@ int vhost_virtqueue_start(struct vhost_dev *dev, if (vhost_needs_vring_endian(vdev)) { r = vhost_virtqueue_set_vring_endian_legacy(dev, - virtio_is_big_endian(vdev), + virtio_vdev_is_big_endian(vdev), vhost_vq_index); if (r) { return r; @@ -1423,7 +1423,7 @@ static int do_vhost_virtqueue_stop(struct vhost_dev *dev, */ if (vhost_needs_vring_endian(vdev)) { vhost_virtqueue_set_vring_endian_legacy(dev, - !virtio_is_big_endian(vdev), + !virtio_vdev_is_big_endian(vdev), vhost_vq_index); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index fe13a7a950..c7b5a79b93 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -586,13 +586,13 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, break; case 2: val = virtio_config_readw(vdev, addr); - if (virtio_is_big_endian(vdev)) { + if (virtio_vdev_is_big_endian(vdev)) { val = bswap16(val); } break; case 4: val = virtio_config_readl(vdev, addr); - if (virtio_is_big_endian(vdev)) { + if (virtio_vdev_is_big_endian(vdev)) { val = bswap32(val); } break; @@ -625,13 +625,13 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr, virtio_config_writeb(vdev, addr, val); break; case 2: - if (virtio_is_big_endian(vdev)) { + if (virtio_vdev_is_big_endian(vdev)) { val = bswap16(val); } virtio_config_writew(vdev, addr, val); break; case 4: - if (virtio_is_big_endian(vdev)) { + if (virtio_vdev_is_big_endian(vdev)) { val = bswap32(val); } virtio_config_writel(vdev, addr, val); diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index cd17d0c87e..b58fb6ed7e 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -28,7 +28,7 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) { #if defined(LEGACY_VIRTIO_IS_BIENDIAN) - return virtio_is_big_endian(vdev); + return virtio_vdev_is_big_endian(vdev); #elif TARGET_BIG_ENDIAN if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { /* Devices conforming to VIRTIO 1.0 or later are always LE. */ diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 65872f2c54..b3c6a9dc6f 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -468,7 +468,7 @@ static inline bool virtio_host_has_feature(VirtIODevice *vdev, return virtio_has_feature(vdev->host_features, fbit); } -static inline bool virtio_is_big_endian(const VirtIODevice *vdev) +static inline bool virtio_vdev_is_big_endian(const VirtIODevice *vdev) { if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); From 730d049c4b65646cb9fbfd789505d985859e83b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 16 Feb 2026 21:36:32 +0100 Subject: [PATCH 04/21] hw/char/virtio-serial-bus: Fix Heap-buffer-overflow in set_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When removing the 'emergency-write' property in commit d0660e5b7fc we neglected to remove the code reducing the virtio_console_config structure size, allowing to access up to the unallocated 'emerg_wr' field. Can be reproduced running: $ cat << EOF | qemu-system-i386 -nodefaults \ -machine q35 -m 512M \ -device virtio-serial \ -display none \ -machine accel=qtest -qtest stdio outl 0xcf8 0x80000810 outl 0xcfc 0xc000 outl 0xcf8 0x80000804 outw 0xcfc 0x01 outl 0xc014 0x00 EOF ==3210206==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000090858 at pc 0x5638f1300a9b bp 0x7fff6b525b80 sp 0x7fff6b525b70 READ of size 4 at 0x502000090858 thread T0 #0 0x5638f1300a9a in set_config hw/char/virtio-serial-bus.c:590 #1 0x5638f0bccdcf in virtio_config_writel hw/virtio/virtio-config-io.c:104 #2 0x5638f0bd0c89 in virtio_pci_config_write hw/virtio/virtio-pci.c:637 #3 0x5638f0cf90cf in memory_region_write_accessor system/memory.c:491 #4 0x5638f0cf975b in access_with_adjusted_size system/memory.c:567 #5 0x5638f0d01d3f in memory_region_dispatch_write system/memory.c:1547 #6 0x5638f0d2fa1e in address_space_stm_internal system/memory_ldst.c.inc:85 #7 0x5638f0d30013 in address_space_stl_le system/memory_ldst_endian.c.inc:53 #8 0x5638f0ceb568 in cpu_outl system/ioport.c:79 #9 0x5638f0d3c0f9 in qtest_process_command system/qtest.c:483 0x502000090858 is located 0 bytes to the right of 8-byte region [0x502000090850,0x502000090858) allocated by thread T0 here: #0 0x7f0dc32cba57 in __interceptor_calloc src/libsanitizer/asan/asan_malloc_linux.cpp:154 #1 0x7f0dc2382c50 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x5ec50) #2 0x5638f1303c27 in virtio_serial_device_realize hw/char/virtio-serial-bus.c:1046 #3 0x5638f1396a9c in virtio_device_realize hw/virtio/virtio.c:4053 #4 0x5638f13ea370 in device_set_realized hw/core/qdev.c:523 #5 0x5638f13fdaf6 in property_set_bool qom/object.c:2376 #6 0x5638f13f9098 in object_property_set qom/object.c:1450 #7 0x5638f140283c in object_property_set_qobject qom/qom-qobject.c:28 #8 0x5638f13f9616 in object_property_set_bool qom/object.c:1520 #9 0x5638f13e91cc in qdev_realize hw/core/qdev.c:276 #10 0x5638f0c3d94b in virtio_serial_pci_realize hw/virtio/virtio-serial-pci.c:69 #11 0x5638f0bda886 in virtio_pci_realize hw/virtio/virtio-pci.c:2351 #12 0x5638f09bc2ae in pci_qdev_realize hw/pci/pci.c:2310 #13 0x5638f0bdb2f2 in virtio_pci_dc_realize hw/virtio/virtio-pci.c:2473 #14 0x5638f13ea370 in device_set_realized hw/core/qdev.c:523 SUMMARY: AddressSanitizer: heap-buffer-overflow hw/char/virtio-serial-bus.c:590 in set_config Fixes: d0660e5b7fc ("hw/char/virtio-serial: Do not expose the 'emergency-write' property") Reported-by: Alexander Bulekov Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3303 Buglink: https://issues.oss-fuzz.com/issues/484647006 Signed-off-by: Philippe Mathieu-Daudé Tested-by: Alexander Bulekov Message-Id: <20260216205527.45938-1-philmd@linaro.org> --- hw/char/virtio-serial-bus.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index b7c57ea967..cd234dc6db 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -1039,10 +1039,6 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) return; } - if (!virtio_has_feature(vdev->host_features, - VIRTIO_CONSOLE_F_EMERG_WRITE)) { - config_size = offsetof(struct virtio_console_config, emerg_wr); - } virtio_init(vdev, VIRTIO_ID_CONSOLE, config_size); /* Spawn a new virtio-serial bus on which the ports will ride as devices */ From 10b63551b623ba9c22f6796aea4f6837fb579d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 14:45:16 +0100 Subject: [PATCH 05/21] hw/display/macfb: Constify macfb_sense_table[] array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macfb_sense_table[] is only read, never updated, so can be const. Update the single call site, macfb_sense_read(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20260216213121.47122-2-philmd@linaro.org> --- hw/display/macfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/display/macfb.c b/hw/display/macfb.c index 388f8de507..57ad8ad558 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -82,7 +82,7 @@ typedef struct MacFbSense { uint8_t ext_sense; } MacFbSense; -static MacFbSense macfb_sense_table[] = { +static const MacFbSense macfb_sense_table[] = { { MACFB_DISPLAY_APPLE_21_COLOR, 0x0, 0 }, { MACFB_DISPLAY_APPLE_PORTRAIT, 0x1, 0 }, { MACFB_DISPLAY_APPLE_12_RGB, 0x2, 0 }, @@ -342,7 +342,7 @@ static void macfb_invalidate_display(void *opaque) static uint32_t macfb_sense_read(MacfbState *s) { - MacFbSense *macfb_sense; + const MacFbSense *macfb_sense; uint8_t sense; assert(s->type < ARRAY_SIZE(macfb_sense_table)); From ee567616072e2b9861e8fc67921ad30612bcaf47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 14:45:37 +0100 Subject: [PATCH 06/21] hw/display/macfb: Constify macfb_mode_table[] array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macfb_mode_table[] is only read, never updated, so can be const. Update the call sites accordingly. Make the MacfbState::mode pointer to const. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20260216213121.47122-3-philmd@linaro.org> --- hw/display/macfb.c | 10 +++++----- hw/m68k/q800.c | 2 +- include/hw/display/macfb.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/display/macfb.c b/hw/display/macfb.c index 57ad8ad558..8ef174dc6d 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -100,7 +100,7 @@ static const MacFbSense macfb_sense_table[] = { { MACFB_DISPLAY_SVGA, 0x7, 0x5 }, }; -static MacFbMode macfb_mode_table[] = { +static const MacFbMode macfb_mode_table[] = { { MACFB_DISPLAY_VGA, 1, 0x100, 0x71e, 640, 480, 0x400, 0x1000 }, { MACFB_DISPLAY_VGA, 2, 0x100, 0x70e, 640, 480, 0x400, 0x1000 }, { MACFB_DISPLAY_VGA, 4, 0x100, 0x706, 640, 480, 0x400, 0x1000 }, @@ -397,7 +397,7 @@ static void macfb_update_mode(MacfbState *s) static void macfb_mode_write(MacfbState *s) { - MacFbMode *macfb_mode; + const MacFbMode *macfb_mode; int i; for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) { @@ -418,11 +418,11 @@ static void macfb_mode_write(MacfbState *s) } } -static MacFbMode *macfb_find_mode(MacfbDisplayType display_type, +static const MacFbMode *macfb_find_mode(MacfbDisplayType display_type, uint16_t width, uint16_t height, uint8_t depth) { - MacFbMode *macfb_mode; + const MacFbMode *macfb_mode; int i; for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) { @@ -440,7 +440,7 @@ static MacFbMode *macfb_find_mode(MacfbDisplayType display_type, static gchar *macfb_mode_list(void) { GString *list = g_string_new(""); - MacFbMode *macfb_mode; + const MacFbMode *macfb_mode; int i; for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) { diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 25ddddb5d9..4767eb4298 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -255,7 +255,7 @@ static void q800_machine_init(MachineState *machine) int32_t initrd_size; uint8_t *prom; int i, checksum; - MacFbMode *macfb_mode; + const MacFbMode *macfb_mode; ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h index 495dead44b..cb7aac7a4d 100644 --- a/include/hw/display/macfb.h +++ b/include/hw/display/macfb.h @@ -66,7 +66,7 @@ typedef struct MacfbState { uint8_t type; uint32_t regs[MACFB_NUM_REGS]; - MacFbMode *mode; + const MacFbMode *mode; QEMUTimer *vbl_timer; qemu_irq irq; From 3445dd26ecbd7a731f73e586dae3410a24b576d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 14:45:46 +0100 Subject: [PATCH 07/21] hw/m68k/q800: Use MacFbMode fields in q800_machine_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once the Mac Frame Buffer device is realized on the NuBus, its MacFbMode might be different of the global graphic_depth and graphic_width globals. Prefer the device MacFbMode fields to initialize the BootInfo structure. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Mark Cave-Ayland Message-Id: <20260216213121.47122-4-philmd@linaro.org> --- hw/m68k/q800.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 4767eb4298..b55c03a90b 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -605,9 +605,9 @@ static void q800_machine_init(MachineState *machine) BOOTINFO2(param_ptr, BI_MEMCHUNK, 0, ram_size); BOOTINFO1(param_ptr, BI_MAC_VADDR, VIDEO_BASE + macfb_mode->offset); - BOOTINFO1(param_ptr, BI_MAC_VDEPTH, graphic_depth); + BOOTINFO1(param_ptr, BI_MAC_VDEPTH, macfb_mode->depth); BOOTINFO1(param_ptr, BI_MAC_VDIM, - (graphic_height << 16) | graphic_width); + (graphic_height << 16) | macfb_mode->width); BOOTINFO1(param_ptr, BI_MAC_VROW, macfb_mode->stride); BOOTINFO1(param_ptr, BI_MAC_SCCBASE, SCC_BASE); From 6c72922fe53851ba3f109b0b0f2312e0df9d5c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 14:46:18 +0100 Subject: [PATCH 08/21] hw/m68k/q800: Set MACFB_DISPLAY_APPLE_21_COLOR within MacFrameBuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MACFB_DISPLAY_APPLE_21_COLOR mode is not specific to the Q800 machine. Check and set it once in the MacFB DeviceRealize handler. No need to explicitly set the MACFB_DISPLAY_VGA mode since this is the default value. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Mark Cave-Ayland Message-Id: <20260216213121.47122-5-philmd@linaro.org> --- hw/display/macfb.c | 4 ++++ hw/m68k/q800.c | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/display/macfb.c b/hw/display/macfb.c index 8ef174dc6d..b8115c2be1 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -645,6 +645,10 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp) { DisplaySurface *surface; + if (s->width == 1152 && s->height == 870) { + s->type = MACFB_DISPLAY_APPLE_21_COLOR; + } + s->mode = macfb_find_mode(s->type, s->width, s->height, s->depth); if (!s->mode) { gchar *list; diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index b55c03a90b..ba32da2fa4 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -563,11 +563,6 @@ static void q800_machine_init(MachineState *machine) qdev_prop_set_uint32(dev, "width", graphic_width); qdev_prop_set_uint32(dev, "height", graphic_height); qdev_prop_set_uint8(dev, "depth", graphic_depth); - if (graphic_width == 1152 && graphic_height == 870) { - qdev_prop_set_uint8(dev, "display", MACFB_DISPLAY_APPLE_21_COLOR); - } else { - qdev_prop_set_uint8(dev, "display", MACFB_DISPLAY_VGA); - } qdev_realize(dev, BUS(nubus), &error_fatal); macfb_mode = (NUBUS_MACFB(dev)->macfb).mode; From 7207a9c3a95a240585e21d08ecc88a6b6ce62faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 14:47:05 +0100 Subject: [PATCH 09/21] hw/m68k: Set graphic display dimensions generically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a dimension is not set, have the machine init code (q800_machine_init) set the default values. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Mark Cave-Ayland Message-Id: <20260216213121.47122-6-philmd@linaro.org> --- hw/m68k/q800.c | 6 +++--- system/globals-target.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index ba32da2fa4..ded531394e 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -560,9 +560,9 @@ static void q800_machine_init(MachineState *machine) TYPE_NUBUS_MACFB); dev = DEVICE(&m->macfb); qdev_prop_set_uint32(dev, "slot", 9); - qdev_prop_set_uint32(dev, "width", graphic_width); - qdev_prop_set_uint32(dev, "height", graphic_height); - qdev_prop_set_uint8(dev, "depth", graphic_depth); + qdev_prop_set_uint32(dev, "width", graphic_width ?: 800); + qdev_prop_set_uint32(dev, "height", graphic_height ?: 600); + qdev_prop_set_uint8(dev, "depth", graphic_depth ?: 8); qdev_realize(dev, BUS(nubus), &error_fatal); macfb_mode = (NUBUS_MACFB(dev)->macfb).mode; diff --git a/system/globals-target.c b/system/globals-target.c index 989720591e..e3f7d846ac 100644 --- a/system/globals-target.c +++ b/system/globals-target.c @@ -14,9 +14,9 @@ int graphic_width = 1024; int graphic_height = 768; int graphic_depth = 8; #elif defined(TARGET_M68K) -int graphic_width = 800; -int graphic_height = 600; -int graphic_depth = 8; +int graphic_width; +int graphic_height; +int graphic_depth; #else int graphic_width = 800; int graphic_height = 600; From 37ad735f6b4ebdaaa952927ab9f96c9b857b7785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 15:33:42 +0100 Subject: [PATCH 10/21] hw/sparc: Set graphic display dimensions generically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a dimension is not set, have the machine init code set the default values. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Mark Cave-Ayland Message-Id: <20260216213121.47122-7-philmd@linaro.org> --- hw/sparc/sun4m.c | 9 +++++++++ hw/sparc64/sun4u.c | 10 ++++++++++ system/globals-target.c | 6 +----- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 0c0d658d30..a17bdb3692 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -892,6 +892,15 @@ static void sun4m_hw_init(MachineState *machine) hwdef->esp_base, slavio_irq[18], hwdef->le_base, slavio_irq[16], &hostid); + if (!graphic_width) { + graphic_width = 1024; + } + if (!graphic_height) { + graphic_height = 768; + } + if (!graphic_depth) { + graphic_depth = 8; + } if (graphic_depth != 8 && graphic_depth != 24) { error_report("Unsupported depth: %d", graphic_depth); exit (1); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 5d7787fc1a..b8bda1eb81 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -666,6 +666,16 @@ static void sun4uv_init(MemoryRegion *address_space_mem, sysbus_mmio_get_region(s, 0)); nvram = NVRAM(dev); + if (!graphic_width) { + graphic_width = 1024; + } + if (!graphic_height) { + graphic_height = 768; + } + if (!graphic_depth) { + graphic_depth = 8; + } + initrd_size = 0; initrd_addr = 0; kernel_size = sun4u_load_kernel(machine->kernel_filename, diff --git a/system/globals-target.c b/system/globals-target.c index e3f7d846ac..17a27a0621 100644 --- a/system/globals-target.c +++ b/system/globals-target.c @@ -9,11 +9,7 @@ #include "qemu/osdep.h" #include "system/system.h" -#ifdef TARGET_SPARC -int graphic_width = 1024; -int graphic_height = 768; -int graphic_depth = 8; -#elif defined(TARGET_M68K) +#if defined(TARGET_SPARC) || defined(TARGET_M68K) int graphic_width; int graphic_height; int graphic_depth; From af2f0774cc43fc3055f8e90a50163095d3cdf998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 16:00:15 +0100 Subject: [PATCH 11/21] hw/ppc: Set graphic display dimensions generically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a dimension is not set, have the machine init code set the default values. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260216213121.47122-8-philmd@linaro.org> --- hw/ppc/mac_newworld.c | 9 +++++++++ hw/ppc/mac_oldworld.c | 9 +++++++++ hw/ppc/prep.c | 9 +++++++++ hw/ppc/spapr.c | 9 +++++++++ system/globals-target.c | 6 ------ 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 7275563a15..3680d96ed3 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -432,6 +432,15 @@ static void ppc_core99_init(MachineState *machine) pci_vga_init(pci_bus); + if (!graphic_width) { + graphic_width = 800; + } + if (!graphic_height) { + graphic_height = 600; + } + if (!graphic_depth) { + graphic_depth = 32; + } if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) { graphic_depth = 15; } diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index e679d33898..24d9f2e3d5 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -288,6 +288,15 @@ static void ppc_heathrow_init(MachineState *machine) pci_create_simple(pci_bus, -1, "pci-ohci"); } + if (!graphic_width) { + graphic_width = 800; + } + if (!graphic_height) { + graphic_height = 600; + } + if (!graphic_depth) { + graphic_depth = 32; + } if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) { graphic_depth = 15; } diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index c4efd1d390..e973b34099 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -412,6 +412,15 @@ static void ibm_40p_init(MachineState *machine) fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)machine->ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_PREP); + if (!graphic_width) { + graphic_width = 800; + } + if (!graphic_height) { + graphic_height = 600; + } + if (!graphic_depth) { + graphic_depth = 32; + } fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width); fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height); fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 274f38785f..0ab39dfea6 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1177,6 +1177,15 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset) if (machine->boot_config.has_menu && machine->boot_config.menu) { _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", true))); } + if (!graphic_width) { + graphic_width = 800; + } + if (!graphic_height) { + graphic_height = 600; + } + if (!graphic_depth) { + graphic_depth = 32; + } _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width)); _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height)); _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth)); diff --git a/system/globals-target.c b/system/globals-target.c index 17a27a0621..ffa6c308b5 100644 --- a/system/globals-target.c +++ b/system/globals-target.c @@ -9,12 +9,6 @@ #include "qemu/osdep.h" #include "system/system.h" -#if defined(TARGET_SPARC) || defined(TARGET_M68K) int graphic_width; int graphic_height; int graphic_depth; -#else -int graphic_width = 800; -int graphic_height = 600; -int graphic_depth = 32; -#endif From 32a38529c46e84c22b8d00dc26917f4695a416c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Feb 2026 16:03:44 +0100 Subject: [PATCH 12/21] system/globals: Build as common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all targets have the graphic dimension variables initialized the same way, we can move them to the common file unit, having them built once. Remove the now empty globals-target.c file. The command line '-g WxH[xD]' option is not changed and behaves the same. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-Id: <20260216213121.47122-9-philmd@linaro.org> --- system/globals-target.c | 14 -------------- system/globals.c | 3 +++ system/meson.build | 1 - 3 files changed, 3 insertions(+), 15 deletions(-) delete mode 100644 system/globals-target.c diff --git a/system/globals-target.c b/system/globals-target.c deleted file mode 100644 index ffa6c308b5..0000000000 --- a/system/globals-target.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Global variables that should not exist (target specific) - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * SPDX-License-Identifier: MIT - */ - -#include "qemu/osdep.h" -#include "system/system.h" - -int graphic_width; -int graphic_height; -int graphic_depth; diff --git a/system/globals.c b/system/globals.c index c33f6ed390..34fd3ce9c7 100644 --- a/system/globals.c +++ b/system/globals.c @@ -49,6 +49,9 @@ bool enable_cpu_pm; int autostart = 1; int vga_interface_type = VGA_NONE; bool vga_interface_created; +int graphic_width; +int graphic_height; +int graphic_depth; Chardev *parallel_hds[MAX_PARALLEL_PORTS]; QEMUOptionRom option_rom[MAX_OPTION_ROMS]; int nb_option_roms; diff --git a/system/meson.build b/system/meson.build index 4b69ef0f5f..035f0ae7de 100644 --- a/system/meson.build +++ b/system/meson.build @@ -1,6 +1,5 @@ specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files( 'arch_init.c', - 'globals-target.c', )]) system_ss.add(files( From fe25b9213ca36074f038a5ad8a3c1474f69eb632 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Fri, 30 Jan 2026 18:00:57 -0800 Subject: [PATCH 13/21] hw/ppc/spapr: extract SPAPR_MAX_RAM_SLOTS in a new header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow to include it from common code (vhost-user, in next commit), else it pulls ppc/cpu.h which has target specifics. Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260131020100.1115203-4-pierrick.bouvier@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/hw/ppc/spapr.h | 8 +------- include/hw/ppc/spapr_common.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 include/hw/ppc/spapr_common.h diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 5476ac7ce7..b022f8dd25 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -4,6 +4,7 @@ #include "qemu/units.h" #include "system/dma.h" #include "hw/core/boards.h" +#include "hw/ppc/spapr_common.h" #include "hw/ppc/spapr_drc.h" #include "hw/mem/pc-dimm.h" #include "hw/ppc/spapr_ovec.h" @@ -946,13 +947,6 @@ int spapr_rtc_import_offset(SpaprRtcState *rtc, int64_t legacy_offset); #define SPAPR_MEMORY_BLOCK_SIZE ((hwaddr)1 << 28) /* 256MB */ -/* - * This defines the maximum number of DIMM slots we can have for sPAPR - * guest. This is not defined by sPAPR but we are defining it to 32 slots - * based on default number of slots provided by PowerPC kernel. - */ -#define SPAPR_MAX_RAM_SLOTS 32 - /* 1GB alignment for hotplug memory region */ #define SPAPR_DEVICE_MEM_ALIGN (1 * GiB) diff --git a/include/hw/ppc/spapr_common.h b/include/hw/ppc/spapr_common.h new file mode 100644 index 0000000000..a315b68580 --- /dev/null +++ b/include/hw/ppc/spapr_common.h @@ -0,0 +1,17 @@ +/* + * Common definitions for PPC sPAPR + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_SPAPR_COMMON_H +#define HW_SPAPR_COMMON_H + +/* + * The maximum number of DIMM slots we can have for sPAPR guest. + * This is not defined by sPAPR but we are defining it to 32 slots + * based on default number of slots provided by PowerPC kernel. + */ +#define SPAPR_MAX_RAM_SLOTS 32 + +#endif /* HW_SPAPR_COMMON_H */ From 029125efe47d977ccc2684921a7400b42d644090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 19 Feb 2026 17:18:07 +0000 Subject: [PATCH 14/21] hw/alpha: remove unused includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Bennée Reviewed-by: Pierrick Bouvier Message-ID: <20260219171810.602667-12-alex.bennee@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/alpha/dp264.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 5e64528431..98219f0456 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -16,8 +16,6 @@ #include "hw/rtc/mc146818rtc.h" #include "hw/ide/pci.h" #include "hw/isa/superio.h" -#include "net/net.h" -#include "qemu/cutils.h" #include "qemu/datadir.h" static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) From 703bc80f553f19993eaaee249f53386d38f42122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 19 Feb 2026 17:18:10 +0000 Subject: [PATCH 15/21] hw/core/cpu: expand cpu_reset function docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a hint to the developer that this should only be called from a reset chain. Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Reviewed-by: Pierrick Bouvier Message-ID: <20260219171810.602667-15-alex.bennee@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/hw/core/cpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index ef20cb356a..89934b8efe 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -815,6 +815,9 @@ void cpu_list_remove(CPUState *cpu); /** * cpu_reset: * @cpu: The CPU whose state is to be reset. + * + * You should refrain from calling this during CPU realization and + * make sure this is called from the reset logic instead. */ void cpu_reset(CPUState *cpu); From fa084473179a17b7baf92d47d7171386bfbd35eb Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Tue, 27 Jan 2026 18:38:49 +0100 Subject: [PATCH 16/21] hw/net/rtl8139: Remove ineffective parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The do_interrupt parameter for rtl8139_do_receive was originally added in commit 6cadb320c7 to avoid generating interrupt when receiving in loopback mode. Later commit 5311fb805a changed this so that this parameter became ineffective and now this parameter is unused and always 1. If this turns out to be a problem maybe there's a better way to fix this so remove the do_interrupt parameter for now to simplify code. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260127173849.588F25969F0@zero.eik.bme.hu> Signed-off-by: Philippe Mathieu-Daudé --- hw/net/rtl8139.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 9fd00574d2..2ad6338ebe 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -815,7 +815,8 @@ static bool rtl8139_can_receive(NetClientState *nc) return avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow); } -static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt) +static ssize_t rtl8139_receive(NetClientState *nc, + const uint8_t *buf, size_t size_) { RTL8139State *s = qemu_get_nic_opaque(nc); PCIDevice *d = PCI_DEVICE(s); @@ -1173,20 +1174,11 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t } s->IntrStatus |= RxOK; - - if (do_interrupt) - { - rtl8139_update_irq(s); - } + rtl8139_update_irq(s); return size_; } -static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - return rtl8139_do_receive(nc, buf, size, 1); -} - static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) { s->RxBufferSize = bufferSize; @@ -1745,7 +1737,7 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s) } static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, - int do_interrupt, const uint8_t *dot1q_buf) + const uint8_t *dot1q_buf) { struct iovec *iov = NULL; struct iovec vlan_iov[3]; @@ -1828,7 +1820,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) s->TxStatus[descriptor] |= TxHostOwns; s->TxStatus[descriptor] |= TxStatOK; - rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL); + rtl8139_transfer_frame(s, txbuffer, txsize, NULL); DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize, descriptor); @@ -2246,7 +2238,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) DPRINTF("+++ C+ mode TSO transferring packet size " "%d\n", tso_send_size); rtl8139_transfer_frame(s, saved_buffer, tso_send_size, - 0, (uint8_t *) dot1q_buffer); + (uint8_t *)dot1q_buffer); /* add transferred count to TCP sequence number */ stl_be_p(&p_tcp_hdr->th_seq, @@ -2323,8 +2315,8 @@ skip_offload: DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size); - rtl8139_transfer_frame(s, saved_buffer, saved_size, 1, - (uint8_t *) dot1q_buffer); + rtl8139_transfer_frame(s, saved_buffer, saved_size, + (uint8_t *)dot1q_buffer); /* restore card space if there was no recursion and reset offset */ if (!s->cplus_txbuffer) From 387ee5d2be300b104c317aa7f86a4c24652c6f3e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 Feb 2026 14:09:13 +0000 Subject: [PATCH 17/21] hw/net/rocker: Don't keep pointer to h_proto as uint16_t* in OfDpaFlowPktFields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rocker_of_dpa.c we assume that the h_proto field in an eth_header struct is aligned, and we copy its address into a uint16_t* in the OfDpaFlowPktFields struct which we then dereference later. This isn't a safe assumption; it will also result in compilation failures with gcc if we mark the eth_header struct as QEMU_PACKED because gcc will not let you take the address of an unaligned struct field. Make the h_proto field in OfDpaFlowPktFields a void*, and make all the places where we previously read through that pointer instead use a new accessor function which allows for the possible lack of alignment. (Compare commit 5814c084679 "hw/net/virtio-net.c: Don't assume IP length field is aligned" which fixed a similar problem elsewhere for an ip_header field.) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki Message-ID: <20260212140917.1443253-2-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/net/rocker/rocker_of_dpa.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 16b9bc7a4b..814f19afc5 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -143,7 +143,7 @@ typedef struct of_dpa_flow { typedef struct of_dpa_flow_pkt_fields { uint32_t tunnel_id; struct eth_header *ethhdr; - uint16_t *h_proto; + void *h_proto; /* pointer to unaligned uint16_t data */ struct vlan_header *vlanhdr; struct ip_header *ipv4hdr; struct ip6_header *ipv6hdr; @@ -196,6 +196,11 @@ typedef struct of_dpa_group { }; } OfDpaGroup; +static uint16_t of_dpa_flow_pkt_h_proto(const OfDpaFlowPktFields *fields) +{ + return lduw_he_p(fields->h_proto); +} + static int of_dpa_mask2prefix(uint32_t mask) { return 32 - ctz32(ntohl(mask)); @@ -395,7 +400,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc, fields->ethhdr = iov->iov_base; fields->h_proto = &fields->ethhdr->h_proto; - if (ntohs(*fields->h_proto) == ETH_P_VLAN) { + if (ntohs(of_dpa_flow_pkt_h_proto(fields) == ETH_P_VLAN)) { sofar += sizeof(struct vlan_header); if (iov->iov_len < sofar) { DPRINTF("flow_pkt_parse underrun on vlan_header\n"); @@ -405,7 +410,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc, fields->h_proto = &fields->vlanhdr->h_proto; } - switch (ntohs(*fields->h_proto)) { + switch (ntohs(of_dpa_flow_pkt_h_proto(fields))) { case ETH_P_IP: sofar += sizeof(struct ip_header); if (iov->iov_len < sofar) { @@ -547,7 +552,7 @@ static void of_dpa_term_mac_build_match(OfDpaFlowContext *fc, { match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC; match->value.in_pport = fc->in_pport; - match->value.eth.type = *fc->fields.h_proto; + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields); match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest, sizeof(match->value.eth.dst.a)); @@ -643,7 +648,7 @@ static void of_dpa_unicast_routing_build_match(OfDpaFlowContext *fc, OfDpaFlowMatch *match) { match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING; - match->value.eth.type = *fc->fields.h_proto; + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields); if (fc->fields.ipv4hdr) { match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst; } @@ -672,7 +677,7 @@ of_dpa_multicast_routing_build_match(OfDpaFlowContext *fc, OfDpaFlowMatch *match) { match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING; - match->value.eth.type = *fc->fields.h_proto; + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields); match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; if (fc->fields.ipv4hdr) { match->value.ipv4.addr.src = fc->fields.ipv4hdr->ip_src; @@ -713,7 +718,7 @@ static void of_dpa_acl_build_match(OfDpaFlowContext *fc, sizeof(match->value.eth.src.a)); memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest, sizeof(match->value.eth.dst.a)); - match->value.eth.type = *fc->fields.h_proto; + match->value.eth.type = of_dpa_flow_pkt_h_proto(&fc->fields); match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci; match->value.width = FLOW_KEY_WIDTH(eth.type); if (fc->fields.ipv4hdr) { From 3609630e7910f04a007e48e4520c04fbb942658e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 Feb 2026 14:09:14 +0000 Subject: [PATCH 18/21] hw/net/rocker: Don't assume h_proto is aligned in eth_strip_vlan_ex() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In eth_strip_vlan_ex() we take a pointer to the eth_header h_proto field into a local uint16_t* variable, and then later in the function we dereference that pointer. This isn't safe, because the eth_header struct may not be aligned, and if we mark the struct as QEMU_PACKED then gcc will complain about taking the address of a field in a packed struct. Instead, make the local variable be a void* and use the appropriate functions for accessing 16 bits of possibly unaligned data through it. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki Message-ID: <20260212140917.1443253-3-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- net/eth.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/eth.c b/net/eth.c index 3f680cc033..12ec316e24 100644 --- a/net/eth.c +++ b/net/eth.c @@ -274,7 +274,7 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index, uint16_t *payload_offset, uint16_t *tci) { struct vlan_header vlan_hdr; - uint16_t *new_ehdr_proto; + void *new_ehdr_proto; size_t new_ehdr_size; size_t copied; @@ -298,7 +298,7 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index, return 0; } - if (copied < new_ehdr_size || be16_to_cpu(*new_ehdr_proto) != vet) { + if (copied < new_ehdr_size || lduw_be_p(new_ehdr_proto) != vet) { return 0; } @@ -308,7 +308,7 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index, return 0; } - *new_ehdr_proto = vlan_hdr.h_proto; + stw_he_p(new_ehdr_proto, vlan_hdr.h_proto); *payload_offset = iovoff + new_ehdr_size + sizeof(vlan_hdr); *tci = be16_to_cpu(vlan_hdr.h_tci); From 42ada5daf959bc60beb4b4335dfbdc9eb8ee9b41 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 Feb 2026 14:09:15 +0000 Subject: [PATCH 19/21] net: mark struct eth_header as QEMU_PACKED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eth_header is not actually guaranteed to be aligned. We attempt to deal with this in some places such as net_checksum_calculate() by using lduw_be_p() and so on to access the fields, but this is not sufficient to be correct, because even accessing a byte member within a misaligned struct is undefined behaviour. The clang sanitizer will emit an error like this if you run the sifive_u_mmc functional test with sanitizers enabled: ../../net/checksum.c:78:47: runtime error: member access within misaligned address 0x561f52f35011 for type 'struct eth_header', which requires 2 byte alignment 0x561f52f35011: note: pointer points here 00 00 00 00 33 33 00 00 00 16 52 54 00 12 34 56 86 dd 60 00 00 00 00 24 00 01 00 00 00 00 00 00 ^ #0 0x561f20608459 in net_checksum_calculate /home/pm215/qemu/build/clang/../../net/checksum.c:78:47 #1 0x561f20117bfa in gem_transmit /home/pm215/qemu/build/clang/../../hw/net/cadence_gem.c:1386:21 #2 0x561f20115c61 in gem_write /home/pm215/qemu/build/clang/../../hw/net/cadence_gem.c:1650:13 SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../../net/checksum.c:78:47 Fix this by marking the eth_header struct as QEMU_PACKED, so that the compiler knows it might be unaligned and will generate the right code for accessing fields. This is similar to commit f8b94b4c520 ("net: mark struct ip_header as QEMU_PACKED") where we fixed this for a different struct defined in this file. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki Message-ID: <20260212140917.1443253-4-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/net/eth.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/eth.h b/include/net/eth.h index 14c34f530f..63f598d7cd 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -39,7 +39,7 @@ struct eth_header { uint8_t h_dest[ETH_ALEN]; /* destination eth addr */ uint8_t h_source[ETH_ALEN]; /* source ether addr */ uint16_t h_proto; /* packet type ID field */ -}; +} QEMU_PACKED; struct vlan_header { uint16_t h_tci; /* priority and VLAN ID */ From 2ca81b0eb3249f66efba6707cc9d6577830e2329 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 Feb 2026 14:09:16 +0000 Subject: [PATCH 20/21] net: mark struct udp_header as QEMU_PACKED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eth_header is not actually guaranteed to be aligned. We attempt to deal with this in some places such as net_checksum_calculate() by using lduw_be_p() and so on to access the fields, but this is not sufficient to be correct, because even accessing a byte member within a misaligned struct is undefined behaviour. The clang sanitizer will emit an error like this if you run the sifive_u_mmc functional test with sanitizers enabled: ../../net/checksum.c:168:24: runtime error: member access within misaligned address 0x5b7a7f829033 for type 'udp_header' (aka 'struct udp_header'), which requires 2 byte alignment 0x5b7a7f829033: note: pointer points here ff ff ff ff 00 44 00 43 01 34 58 54 01 01 06 00 85 95 80 60 00 00 00 00 00 00 00 00 00 00 00 00 ^ #0 0x5b7a71a5887e in net_checksum_calculate /home/pm215/qemu/build/clang/../../net/checksum.c:168:24 #1 0x5b7a7156819a in gem_transmit /home/pm215/qemu/build/clang/../../hw/net/cadence_gem.c:1386:21 #2 0x5b7a71566201 in gem_write /home/pm215/qemu/build/clang/../../hw/net/cadence_gem.c:1650:13 Fix this by marking the udp_header struct as QEMU_PACKED, so that the compiler knows it might be unaligned and will generate the right code for accessing fields. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki Message-ID: <20260212140917.1443253-5-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/net/eth.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/eth.h b/include/net/eth.h index 63f598d7cd..df90ff0837 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -85,7 +85,7 @@ typedef struct udp_header { uint16_t uh_dport; /* destination port */ uint16_t uh_ulen; /* udp length */ uint16_t uh_sum; /* udp checksum */ -} udp_header; +} QEMU_PACKED udp_header; typedef struct ip_pseudo_header { uint32_t ip_src; From 7de8587b5317f0bb5f839e2f55855d6c9ee62835 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 Feb 2026 14:09:17 +0000 Subject: [PATCH 21/21] net: mark struct tcp_header as QEMU_PACKED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eth_header is not actually guaranteed to be aligned. We attempt to deal with this in some places such as net_checksum_calculate() by using lduw_be_p() and so on to access the fields, but this is not sufficient to be correct, because even accessing a byte member within a misaligned struct is undefined behaviour. The clang sanitizer will emit an error like this if you run the sifive_u_mmc functional test with sanitizers enabled: ../../net/checksum.c:144:24: runtime error: member access within misaligned address 0x619a74c32033 for type 'tcp_header' (aka 'struct tcp_header'), which requires 4 byte alignment 0x619a74c32033: note: pointer points here 0a 00 02 02 86 aa 00 16 52 c1 d3 70 00 00 00 00 a0 02 fa f0 00 00 00 00 02 04 05 b4 04 02 08 0a ^ #0 0x619a6ba84794 in net_checksum_calculate /home/pm215/qemu/build/clang/../../net/checksum.c:144:24 #1 0x619a6b5940da in gem_transmit /home/pm215/qemu/build/clang/../../hw/net/cadence_gem.c:1386:21 #2 0x619a6b592141 in gem_write /home/pm215/qemu/build/clang/../../hw/net/cadence_gem.c:1650:13 Fix this by marking the tcp_header struct as QEMU_PACKED. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Akihiko Odaki Message-ID: <20260212140917.1443253-6-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/net/eth.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/eth.h b/include/net/eth.h index df90ff0837..efe270dbfe 100644 --- a/include/net/eth.h +++ b/include/net/eth.h @@ -68,7 +68,7 @@ typedef struct tcp_header { uint16_t th_win; /* window */ uint16_t th_sum; /* checksum */ uint16_t th_urp; /* urgent pointer */ -} tcp_header; +} QEMU_PACKED tcp_header; #define TCP_FLAGS_ONLY(flags) ((flags) & 0x3f)