From c9afc732e22b0d7443f7774b7479c28c882c0b30 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:35 +0800 Subject: [PATCH 01/71] hw/misc/aspeed_hace: Ensure HASH_IRQ is always set to prevent firmware hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, if the program encounters an unsupported algorithm, it does not set the HASH_IRQ bit in the status register and send an interrupt to indicate command completion. As a result, the FW gets stuck waiting for a completion signal from the HACE module. Additionally, in do_hash_operation, if an error occurs within the conditional statement, the HASH_IRQ bit is not set in the status register. This causes the firmware to continuously send HASH commands, as it is unaware that the HACE model has completed processing the command. To fix this, the HASH_IRQ bit in the status register must always be set to ensure that the firmware receives an interrupt from the HACE module, preventing it from getting stuck or repeatedly sending HASH commands. Signed-off-by: Jamin Lin Fixes: c5475b3 ("hw: Model ASPEED's Hash and Crypto Engine") Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater (cherry picked from commit fb8e59abbe46957cd599bb9aa9221fad1e4e989e) Signed-off-by: Michael Tokarev --- hw/misc/aspeed_hace.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index d75da33353..96997a03fc 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -301,12 +301,6 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, iov[i - 1].iov_len, false, iov[i - 1].iov_len); } - - /* - * Set status bits to indicate completion. Testing shows hardware sets - * these irrespective of HASH_IRQ_EN. - */ - s->regs[R_STATUS] |= HASH_IRQ; } static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) @@ -390,10 +384,16 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid hash algorithm selection 0x%"PRIx64"\n", __func__, data & ahc->hash_mask); - break; + } else { + do_hash_operation(s, algo, data & HASH_SG_EN, + ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); } - do_hash_operation(s, algo, data & HASH_SG_EN, - ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); + + /* + * Set status bits to indicate completion. Testing shows hardware sets + * these irrespective of HASH_IRQ_EN. + */ + s->regs[R_STATUS] |= HASH_IRQ; if (data & HASH_IRQ_EN) { qemu_irq_raise(s->irq); From 80a03b51b2a679e944c351eadbb391abc2f196e6 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 22 May 2025 10:33:04 +0800 Subject: [PATCH 02/71] hw/arm/aspeed_ast27x0: Fix RAM size detection failure on BE hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On big-endian hosts, the aspeed_ram_capacity_write() function previously passed the address of a 64-bit "data" variable directly to address_space_write(), assuming host and guest endianness matched. However, the data is expected to be written in little-endian format to DRAM. On big-endian hosts, this led to incorrect data being written into DRAM, which caused the guest firmware to misdetect the DRAM size. As a result, U-Boot fails to boot and hangs. - Replaces the "address_space_write()" call with "address_space_stl_le()", which performs an explicit 32-bit little-endian write. - Updating the MemoryRegionOps to restrict access to exactly 4 bytes using .valid.{min,max}_access_size = 4 and .impl.min_access_size = 4. Signed-off-by: Jamin Lin Fixes: 7436db1 ("aspeed/soc: fix incorrect dram size for AST2700") Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250522023305.2486536-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater (cherry picked from commit e6941ac106190490d8b455eedc5b368e6d94d4cc) Signed-off-by: Michael Tokarev --- hw/arm/aspeed_ast27x0.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index dce7255a2c..b810891b16 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -325,8 +325,9 @@ static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data, * If writes the data to the address which is beyond the ram size, * it would write the data to the "address % ram_size". */ - result = address_space_write(&s->dram_as, addr % ram_size, - MEMTXATTRS_UNSPECIFIED, &data, 4); + address_space_stl_le(&s->dram_as, addr % ram_size, data, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed, addr:0x%" HWADDR_PRIx @@ -339,9 +340,10 @@ static const MemoryRegionOps aspeed_ram_capacity_ops = { .read = aspeed_ram_capacity_read, .write = aspeed_ram_capacity_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { - .min_access_size = 1, - .max_access_size = 8, + .min_access_size = 4, + .max_access_size = 4, }, }; From 6eea0cd5114ffc491a8bf73fd682676638f037e2 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:11 +0800 Subject: [PATCH 03/71] ui/gtk: Document scale and coordinate handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existence of multiple scaling factors forces us to deal with various coordinate systems and this would be confusing. It would be beneficial to define the concepts clearly and use consistent representation for variables in different coordinates. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-2-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau (cherry picked from commit 9498e2f7e1a247557cfa0f830a86c398a23c6809) Signed-off-by: Michael Tokarev --- ui/gtk.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index 59bda83da6..582841e031 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -800,6 +800,71 @@ void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget) #endif } +/** + * DOC: Coordinate handling. + * + * We are coping with sizes and positions in various coordinates and the + * handling of these coordinates is somewhat confusing. It would benefit us + * all if we define these coordinates explicitly and clearly. Besides, it's + * also helpful to follow the same naming convention for variables + * representing values in different coordinates. + * + * I. Definitions + * + * - (guest) buffer coordinate: this is the coordinates that the guest will + * see. The x/y offsets and width/height specified in commands sent by + * guest is basically in buffer coordinate. + * + * - (host) pixel coordinate: this is the coordinate in pixel level on the + * host destop. A window/widget of width 300 in pixel coordinate means it + * occupies 300 pixels horizontally. + * + * - (host) logical window coordinate: the existence of global scaling + * factor in desktop level makes this kind of coordinate play a role. It + * always holds that (logical window size) * (global scale factor) = + * (pixel size). + * + * - global scale factor: this is specified in desktop level and is + * typically invariant during the life cycle of the process. Users with + * high-DPI monitors might set this scale, for example, to 2, in order to + * make the UI look larger. + * + * - zooming scale: this can be freely controlled by the QEMU user to zoom + * in/out the guest content. + * + * II. Representation + * + * We'd like to use consistent representation for variables in different + * coordinates: + * - buffer coordinate: prefix fb + * - pixel coordinate: prefix p + * - logical window coordinate: prefix w + * + * For scales: + * - global scale factor: prefix gs + * - zooming scale: prefix scale/s + * + * Example: fbw, pw, ww for width in different coordinates + * + * III. Equation + * + * - fbw * gs * scale_x = pw + * - pw = gs * ww + * + * Consequently we have + * + * - fbw * scale_x = ww + * + * Example: assuming we are running QEMU on a 3840x2160 screen and have set + * global scaling factor to 2, if the guest buffer size is 1920x1080 and the + * zooming scale is 0.5, then we have: + * - fbw = 1920, fbh = 1080 + * - pw = 1920, ph = 1080 + * - ww = 960, wh = 540 + * A bonus of this configuration is that we can achieve pixel to pixel + * presentation of the guest content. + */ + static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) { VirtualConsole *vc = opaque; From 91fec603bdfb07b2339fd14c31abddb608974bb7 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:12 +0800 Subject: [PATCH 04/71] ui/gtk: Use consistent naming for variables in different coordinates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we've documented definitions and presentation of various coordinates, let's enforce the rules. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-3-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau (cherry picked from commit 3a6b314409b42fe7c46c2bd80cfc2a6744d414fe) Signed-off-by: Michael Tokarev --- ui/gtk-egl.c | 12 +++-- ui/gtk-gl-area.c | 14 ++--- ui/gtk.c | 133 ++++++++++++++++++++++++----------------------- 3 files changed, 82 insertions(+), 77 deletions(-) diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index f7a428c86a..947c99334b 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -70,16 +70,18 @@ void gd_egl_draw(VirtualConsole *vc) QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; int fence_fd; #endif - int ww, wh, ws; + int ww, wh, pw, ph, gs; if (!vc->gfx.gls) { return; } window = gtk_widget_get_window(vc->gfx.drawing_area); - ws = gdk_window_get_scale_factor(window); - ww = gdk_window_get_width(window) * ws; - wh = gdk_window_get_height(window) * ws; + gs = gdk_window_get_scale_factor(window); + ww = gdk_window_get_width(window); + wh = gdk_window_get_height(window); + pw = ww * gs; + ph = wh * gs; if (vc->gfx.scanout_mode) { #ifdef CONFIG_GBM @@ -115,7 +117,7 @@ void gd_egl_draw(VirtualConsole *vc) eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, vc->gfx.esurface, vc->gfx.ectx); - surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); + surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph); surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 2c9a0db425..ba9fbec432 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -42,16 +42,16 @@ void gd_gl_area_draw(VirtualConsole *vc) #ifdef CONFIG_GBM QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; #endif - int ww, wh, ws, y1, y2; + int pw, ph, gs, y1, y2; if (!vc->gfx.gls) { return; } gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - ws = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area)); - ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * ws; - wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * ws; + gs = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area)); + pw = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * gs; + ph = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * gs; if (vc->gfx.scanout_mode) { if (!vc->gfx.guest_fb.framebuffer) { @@ -71,11 +71,11 @@ void gd_gl_area_draw(VirtualConsole *vc) glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.guest_fb.framebuffer); /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */ - glViewport(0, 0, ww, wh); + glViewport(0, 0, pw, ph); y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; y2 = vc->gfx.y0_top ? vc->gfx.h : 0; glBlitFramebuffer(0, y1, vc->gfx.w, y2, - 0, 0, ww, wh, + 0, 0, pw, ph, GL_COLOR_BUFFER_BIT, GL_NEAREST); #ifdef CONFIG_GBM if (dmabuf) { @@ -101,7 +101,7 @@ void gd_gl_area_draw(VirtualConsole *vc) } gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); + surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph); surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); } } diff --git a/ui/gtk.c b/ui/gtk.c index 582841e031..956d4ab9d1 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -387,16 +387,16 @@ static void *gd_win32_get_hwnd(VirtualConsole *vc) /** DisplayState Callbacks **/ static void gd_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) + int fbx, int fby, int fbw, int fbh) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); GdkWindow *win; - int x1, x2, y1, y2; - int mx, my; - int fbw, fbh; - int ww, wh; + int wx1, wx2, wy1, wy2; + int wx_offset, wy_offset; + int ww_surface, wh_surface; + int ww_widget, wh_widget; - trace_gd_update(vc->label, x, y, w, h); + trace_gd_update(vc->label, fbx, fby, fbw, fbh); if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { return; @@ -405,35 +405,36 @@ static void gd_update(DisplayChangeListener *dcl, if (vc->gfx.convert) { pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image, NULL, vc->gfx.convert, - x, y, 0, 0, x, y, w, h); + fbx, fby, 0, 0, fbx, fby, fbw, fbh); } - x1 = floor(x * vc->gfx.scale_x); - y1 = floor(y * vc->gfx.scale_y); + wx1 = floor(fbx * vc->gfx.scale_x); + wy1 = floor(fby * vc->gfx.scale_y); - x2 = ceil(x * vc->gfx.scale_x + w * vc->gfx.scale_x); - y2 = ceil(y * vc->gfx.scale_y + h * vc->gfx.scale_y); + wx2 = ceil(fbx * vc->gfx.scale_x + fbw * vc->gfx.scale_x); + wy2 = ceil(fby * vc->gfx.scale_y + fbh * vc->gfx.scale_y); - fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; - fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; + ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x; + wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y; win = gtk_widget_get_window(vc->gfx.drawing_area); if (!win) { return; } - ww = gdk_window_get_width(win); - wh = gdk_window_get_height(win); + ww_widget = gdk_window_get_width(win); + wh_widget = gdk_window_get_height(win); - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; + wx_offset = wy_offset = 0; + if (ww_widget > ww_surface) { + wx_offset = (ww_widget - ww_surface) / 2; } - if (wh > fbh) { - my = (wh - fbh) / 2; + if (wh_widget > wh_surface) { + wy_offset = (wh_widget - wh_surface) / 2; } gtk_widget_queue_draw_area(vc->gfx.drawing_area, - mx + x1, my + y1, (x2 - x1), (y2 - y1)); + wx_offset + wx1, wy_offset + wy1, + (wx2 - wx1), (wy2 - wy1)); } static void gd_refresh(DisplayChangeListener *dcl) @@ -869,8 +870,8 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; - int mx, my; - int ww, wh; + int wx_offset, wy_offset; + int ww_widget, wh_widget, ww_surface, wh_surface; int fbw, fbh; #if defined(CONFIG_OPENGL) @@ -904,46 +905,47 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) fbw = surface_width(vc->gfx.ds); fbh = surface_height(vc->gfx.ds); - ww = gdk_window_get_width(gtk_widget_get_window(widget)); - wh = gdk_window_get_height(gtk_widget_get_window(widget)); + ww_widget = gdk_window_get_width(gtk_widget_get_window(widget)); + wh_widget = gdk_window_get_height(gtk_widget_get_window(widget)); if (s->full_screen) { - vc->gfx.scale_x = (double)ww / fbw; - vc->gfx.scale_y = (double)wh / fbh; + vc->gfx.scale_x = (double)ww_widget / fbw; + vc->gfx.scale_y = (double)wh_widget / fbh; } else if (s->free_scale) { double sx, sy; - sx = (double)ww / fbw; - sy = (double)wh / fbh; + sx = (double)ww_widget / fbw; + sy = (double)wh_widget / fbh; vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy); } - fbw *= vc->gfx.scale_x; - fbh *= vc->gfx.scale_y; + ww_surface = fbw * vc->gfx.scale_x; + wh_surface = fbh * vc->gfx.scale_y; - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; + wx_offset = wy_offset = 0; + if (ww_widget > ww_surface) { + wx_offset = (ww_widget - ww_surface) / 2; } - if (wh > fbh) { - my = (wh - fbh) / 2; + if (wh_widget > wh_surface) { + wy_offset = (wh_widget - wh_surface) / 2; } - cairo_rectangle(cr, 0, 0, ww, wh); + cairo_rectangle(cr, 0, 0, ww_widget, wh_widget); /* Optionally cut out the inner area where the pixmap will be drawn. This avoids 'flashing' since we're not double-buffering. Note we're using the undocumented behaviour of drawing the rectangle from right to left to cut out the whole */ - cairo_rectangle(cr, mx + fbw, my, - -1 * fbw, fbh); + cairo_rectangle(cr, wx_offset + ww_surface, wy_offset, + -1 * ww_surface, wh_surface); cairo_fill(cr); cairo_scale(cr, vc->gfx.scale_x, vc->gfx.scale_y); cairo_set_source_surface(cr, vc->gfx.surface, - mx / vc->gfx.scale_x, my / vc->gfx.scale_y); + wx_offset / vc->gfx.scale_x, + wy_offset / vc->gfx.scale_y); cairo_paint(cr); return TRUE; @@ -954,19 +956,19 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; - int x, y; - int mx, my; - int fbh, fbw; - int ww, wh; + int fbx, fby; + int wx_offset, wy_offset; + int wh_surface, ww_surface; + int ww_widget, wh_widget; if (!vc->gfx.ds) { return TRUE; } - fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; - fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; - ww = gtk_widget_get_allocated_width(widget); - wh = gtk_widget_get_allocated_height(widget); + ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x; + wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y; + ww_widget = gtk_widget_get_allocated_width(widget); + wh_widget = gtk_widget_get_allocated_height(widget); /* * `widget` may not have the same size with the frame buffer. @@ -974,41 +976,42 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, * To achieve that, `vc` will be displayed at (mx, my) * so that it is displayed at the center of the widget. */ - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; + wx_offset = wy_offset = 0; + if (ww_widget > ww_surface) { + wx_offset = (ww_widget - ww_surface) / 2; } - if (wh > fbh) { - my = (wh - fbh) / 2; + if (wh_widget > wh_surface) { + wy_offset = (wh_widget - wh_surface) / 2; } /* * `motion` is reported in `widget` coordinates * so translating it to the coordinates in `vc`. */ - x = (motion->x - mx) / vc->gfx.scale_x; - y = (motion->y - my) / vc->gfx.scale_y; + fbx = (motion->x - wx_offset) / vc->gfx.scale_x; + fby = (motion->y - wy_offset) / vc->gfx.scale_y; - trace_gd_motion_event(ww, wh, gtk_widget_get_scale_factor(widget), x, y); + trace_gd_motion_event(ww_widget, wh_widget, + gtk_widget_get_scale_factor(widget), fbx, fby); if (qemu_input_is_absolute(vc->gfx.dcl.con)) { - if (x < 0 || y < 0 || - x >= surface_width(vc->gfx.ds) || - y >= surface_height(vc->gfx.ds)) { + if (fbx < 0 || fby < 0 || + fbx >= surface_width(vc->gfx.ds) || + fby >= surface_height(vc->gfx.ds)) { return TRUE; } - qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, x, + qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, fbx, 0, surface_width(vc->gfx.ds)); - qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, y, + qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, fby, 0, surface_height(vc->gfx.ds)); qemu_input_event_sync(); } else if (s->last_set && s->ptr_owner == vc) { - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x); - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y); + qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, fbx - s->last_x); + qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, fby - s->last_y); qemu_input_event_sync(); } - s->last_x = x; - s->last_y = y; + s->last_x = fbx; + s->last_y = fby; s->last_set = TRUE; if (!qemu_input_is_absolute(vc->gfx.dcl.con) && s->ptr_owner == vc) { From 43fecc5dde342ec9f04ee8a28d2b09f4cfe1450d Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:13 +0800 Subject: [PATCH 05/71] gtk/ui: Introduce helper gd_update_scale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code snippet updating scale_x/scale_y is general and will be used in next patch. Make it a function. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-4-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau (cherry picked from commit a19665448156f17b52b7f33e7960d57efcfca067) Signed-off-by: Michael Tokarev --- include/ui/gtk.h | 2 ++ ui/gtk.c | 30 +++++++++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index aa3d637029..d3944046db 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -224,4 +224,6 @@ int gd_gl_area_make_current(DisplayGLCtx *dgc, /* gtk-clipboard.c */ void gd_clipboard_init(GtkDisplayState *gd); +void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh); + #endif /* UI_GTK_H */ diff --git a/ui/gtk.c b/ui/gtk.c index 956d4ab9d1..ea3f403b02 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -801,6 +801,24 @@ void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget) #endif } +void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh) +{ + if (!vc) { + return; + } + + if (vc->s->full_screen) { + vc->gfx.scale_x = (double)ww / fbw; + vc->gfx.scale_y = (double)wh / fbh; + } else if (vc->s->free_scale) { + double sx, sy; + + sx = (double)ww / fbw; + sy = (double)wh / fbh; + + vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy); + } +} /** * DOC: Coordinate handling. * @@ -908,17 +926,7 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) ww_widget = gdk_window_get_width(gtk_widget_get_window(widget)); wh_widget = gdk_window_get_height(gtk_widget_get_window(widget)); - if (s->full_screen) { - vc->gfx.scale_x = (double)ww_widget / fbw; - vc->gfx.scale_y = (double)wh_widget / fbh; - } else if (s->free_scale) { - double sx, sy; - - sx = (double)ww_widget / fbw; - sy = (double)wh_widget / fbh; - - vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy); - } + gd_update_scale(vc, ww_widget, wh_widget, fbw, fbh); ww_surface = fbw * vc->gfx.scale_x; wh_surface = fbh * vc->gfx.scale_y; From a5a805068a2ca0dabf71f05c56bdbdba7360f985 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:14 +0800 Subject: [PATCH 06/71] ui/gtk: Update scales in fixed-scale mode when rendering GL area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When gl=on, scale_x and scale_y were set to 1 on startup that didn't reflect the real situation of the scan-out in free scale mode, resulting in incorrect cursor coordinates to be sent when moving the mouse pointer. Simply updating the scales before rendering the image fixes this issue. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-5-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau (cherry picked from commit 8fb072472c38cb1778c5b0bebf535a8b13533857) Signed-off-by: Michael Tokarev --- ui/gtk-gl-area.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index ba9fbec432..db93cd6204 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -43,6 +43,8 @@ void gd_gl_area_draw(VirtualConsole *vc) QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; #endif int pw, ph, gs, y1, y2; + int ww, wh; + int fbw, fbh; if (!vc->gfx.gls) { return; @@ -50,8 +52,14 @@ void gd_gl_area_draw(VirtualConsole *vc) gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); gs = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area)); - pw = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * gs; - ph = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * gs; + fbw = surface_width(vc->gfx.ds); + fbh = surface_height(vc->gfx.ds); + ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area); + wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area); + pw = ww * gs; + ph = wh * gs; + + gd_update_scale(vc, ww, wh, fbw, fbh); if (vc->gfx.scanout_mode) { if (!vc->gfx.guest_fb.framebuffer) { From 613f05a4c653761550b1d5a5ff8993d1f8e22230 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:15 +0800 Subject: [PATCH 07/71] ui/sdl: Consider scaling in mouse event handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using sdl display backend, if the window is scaled, incorrect mouse positions will be reported since scaling is not properly handled. Fix it by transforming the positions from window coordinate to guest buffer coordinate. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-6-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau (cherry picked from commit 30aa105640b0a2a541744b6584d57c9a4b86debd) Signed-off-by: Michael Tokarev --- ui/sdl2.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ui/sdl2.c b/ui/sdl2.c index cda4293a53..b00e421f7f 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -488,14 +488,14 @@ static void handle_mousemotion(SDL_Event *ev) { int max_x, max_y; struct sdl2_console *scon = get_scon_from_window(ev->motion.windowID); + int scr_w, scr_h, surf_w, surf_h, x, y, dx, dy; if (!scon || !qemu_console_is_graphic(scon->dcl.con)) { return; } + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); if (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { - int scr_w, scr_h; - SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); max_x = scr_w - 1; max_y = scr_h - 1; if (gui_grab && !gui_fullscreen @@ -509,9 +509,14 @@ static void handle_mousemotion(SDL_Event *ev) sdl_grab_start(scon); } } + surf_w = surface_width(scon->surface); + surf_h = surface_height(scon->surface); + x = (int64_t)ev->motion.x * surf_w / scr_w; + y = (int64_t)ev->motion.y * surf_h / scr_h; + dx = (int64_t)ev->motion.xrel * surf_w / scr_w; + dy = (int64_t)ev->motion.yrel * surf_h / scr_h; if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { - sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, - ev->motion.x, ev->motion.y, ev->motion.state); + sdl_send_mouse_event(scon, dx, dy, x, y, ev->motion.state); } } @@ -520,12 +525,17 @@ static void handle_mousebutton(SDL_Event *ev) int buttonstate = SDL_GetMouseState(NULL, NULL); SDL_MouseButtonEvent *bev; struct sdl2_console *scon = get_scon_from_window(ev->button.windowID); + int scr_w, scr_h, x, y; if (!scon || !qemu_console_is_graphic(scon->dcl.con)) { return; } bev = &ev->button; + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); + x = (int64_t)bev->x * surface_width(scon->surface) / scr_w; + y = (int64_t)bev->y * surface_height(scon->surface) / scr_h; + if (!gui_grab && !qemu_input_is_absolute(scon->dcl.con)) { if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { /* start grabbing all events */ @@ -537,7 +547,7 @@ static void handle_mousebutton(SDL_Event *ev) } else { buttonstate &= ~SDL_BUTTON(bev->button); } - sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate); + sdl_send_mouse_event(scon, 0, 0, x, y, buttonstate); } } From a610978bc55f0199344a5ba6bc6927f9fef08a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 27 Jan 2025 18:45:47 +0000 Subject: [PATCH 08/71] ui/vnc.c: replace big endian flag with byte order value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will make it easier to do certain comparisons in future if we store G_BIG_ENDIAN/G_LITTLE_ENDIAN directly, instead of a boolean flag, as we can then compare directly to the G_BYTE_ORDER constant. Reviewed-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel P. Berrangé (cherry picked from commit 7ed96710e82c385c6cfc3d064eec7dde20f0f3fd) Signed-off-by: Michael Tokarev --- ui/vnc-enc-tight.c | 2 +- ui/vnc-enc-zrle.c | 2 +- ui/vnc-jobs.c | 2 +- ui/vnc.c | 6 +++--- ui/vnc.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 41f559eb83..f8aaa8f346 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -150,7 +150,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h) * If client is big-endian, color samples begin from the second * byte (offset 1) of a 32-bit pixel value. */ - off = vs->client_be; + off = vs->client_endian == G_BIG_ENDIAN ? 1 : 0; memset(stats, 0, sizeof (stats)); diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c index bd33b89063..97ec6c7119 100644 --- a/ui/vnc-enc-zrle.c +++ b/ui/vnc-enc-zrle.c @@ -255,7 +255,7 @@ static void zrle_write_u8(VncState *vs, uint8_t value) static int zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) { - bool be = vs->client_be; + bool be = vs->client_endian == G_BIG_ENDIAN; size_t bytes; int zywrle_level; diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index fcca7ec632..d3486af9e2 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -188,7 +188,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local) local->lossy_rect = orig->lossy_rect; local->write_pixels = orig->write_pixels; local->client_pf = orig->client_pf; - local->client_be = orig->client_be; + local->client_endian = orig->client_endian; local->tight = orig->tight; local->zlib = orig->zlib; local->hextile = orig->hextile; diff --git a/ui/vnc.c b/ui/vnc.c index 9241caaad9..d47879f579 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -893,7 +893,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) buf[0] = v; break; case 2: - if (vs->client_be) { + if (vs->client_endian == G_BIG_ENDIAN) { buf[0] = v >> 8; buf[1] = v; } else { @@ -903,7 +903,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) break; default: case 4: - if (vs->client_be) { + if (vs->client_endian == G_BIG_ENDIAN) { buf[0] = v >> 24; buf[1] = v >> 16; buf[2] = v >> 8; @@ -2314,7 +2314,7 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel, vs->client_pf.bits_per_pixel = bits_per_pixel; vs->client_pf.bytes_per_pixel = bits_per_pixel / 8; vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel; - vs->client_be = big_endian_flag; + vs->client_endian = big_endian_flag ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; if (!true_color_flag) { send_color_map(vs); diff --git a/ui/vnc.h b/ui/vnc.h index acc53a2cc1..02613aa63a 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -323,7 +323,7 @@ struct VncState VncWritePixels *write_pixels; PixelFormat client_pf; pixman_format_code_t client_format; - bool client_be; + int client_endian; /* G_LITTLE_ENDIAN or G_BIG_ENDIAN */ CaptureVoiceOut *audio_cap; struct audsettings as; From 531cbd8e262d3e59059ea07a72d3aa71c9e94573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 27 Jan 2025 18:48:50 +0000 Subject: [PATCH 09/71] ui/vnc: take account of client byte order in pixman format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The set_pixel_conversion() method is responsible for determining whether the VNC client pixel format matches the server format, and thus whether we can use the fast path "copy" impl for sending pixels, or must use the generic impl with bit swizzling. The VNC server format is set at build time to VNC_SERVER_FB_FORMAT, which corresponds to PIXMAN_x8r8g8b8. The qemu_pixman_get_format() method is then responsible for converting the VNC pixel format into a pixman format. The VNC client pixel shifts are relative to the associated endianness. The pixman formats are always relative to the host native endianness. The qemu_pixman_get_format() method does not take into account the VNC client endianness, and is thus returning a pixman format that is only valid with the host endianness matches that of the VNC client. This has been broken since pixman was introduced to the VNC server: commit 9f64916da20eea67121d544698676295bbb105a7 Author: Gerd Hoffmann Date: Wed Oct 10 13:29:43 2012 +0200 pixman/vnc: use pixman images in vnc. The flaw can be demonstrated using the Tigervnc client by using vncviewer -AutoSelect=0 -PreferredEncoding=raw server:display connecting from a LE client to a QEMU on a BE server, or the reverse. The bug was masked, however, because almost all VNC clients will advertize support for the "tight" encoding and the QEMU VNC server will prefer "tight" if advertized. The tight_pack24 method is responsible for taking a set of pixels which have already been converted into client endianness and then repacking them into the TPIXEL format which the RFB spec defines as "TPIXEL is only 3 bytes long, where the first byte is the red component, the second byte is the green component, and the third byte is the blue component of the pixel color value" IOW, the TPIXEL format is fixed on the wire, regardless of what the VNC client declare as its endianness. Since the VNC pixel encoding code was failing to honour the endian flag of the client, the tight_pack24 method was always operating on data in native endianness. Its impl cancelled out the VNC pixel encoding bug. With the VNC pixel encoding code now fixed, the tight_pack24 method needs to take into account that it is operating on data in client endianness, not native endianness. It thus may need to invert the pixel shifts. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel P. Berrangé (cherry picked from commit 70097442853c389a765c9f6502d861d182b092ae) Signed-off-by: Michael Tokarev --- include/ui/qemu-pixman.h | 4 ++-- ui/qemu-pixman.c | 15 ++++++++------- ui/vnc-enc-tight.c | 2 +- ui/vnc.c | 3 ++- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 193bc046d1..2ca0ed7029 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -75,12 +75,12 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format); pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian); pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format); uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman); -int qemu_pixman_get_type(int rshift, int gshift, int bshift); +int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian); bool qemu_pixman_check_format(DisplayChangeListener *dcl, pixman_format_code_t format); #ifdef CONFIG_PIXMAN -pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf); +pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian); pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, int width); void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 6ef4376f4e..ef4e71da11 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -126,33 +126,34 @@ uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman_format) return 0; } -int qemu_pixman_get_type(int rshift, int gshift, int bshift) +int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian) { int type = PIXMAN_TYPE_OTHER; + bool native_endian = (endian == G_BYTE_ORDER); if (rshift > gshift && gshift > bshift) { if (bshift == 0) { - type = PIXMAN_TYPE_ARGB; + type = native_endian ? PIXMAN_TYPE_ARGB : PIXMAN_TYPE_BGRA; } else { - type = PIXMAN_TYPE_RGBA; + type = native_endian ? PIXMAN_TYPE_RGBA : PIXMAN_TYPE_ABGR; } } else if (rshift < gshift && gshift < bshift) { if (rshift == 0) { - type = PIXMAN_TYPE_ABGR; + type = native_endian ? PIXMAN_TYPE_ABGR : PIXMAN_TYPE_RGBA; } else { - type = PIXMAN_TYPE_BGRA; + type = native_endian ? PIXMAN_TYPE_BGRA : PIXMAN_TYPE_ARGB; } } return type; } #ifdef CONFIG_PIXMAN -pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf) +pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian) { pixman_format_code_t format; int type; - type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift); + type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift, endian); format = PIXMAN_FORMAT(pf->bits_per_pixel, type, pf->abits, pf->rbits, pf->gbits, pf->bbits); if (!pixman_format_supported_source(format)) { diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index f8aaa8f346..a5bdc19ebb 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -891,7 +891,7 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret) buf8 = buf; - if (1 /* FIXME */) { + if (vs->client_endian == G_BYTE_ORDER) { rshift = vs->client_pf.rshift; gshift = vs->client_pf.gshift; bshift = vs->client_pf.bshift; diff --git a/ui/vnc.c b/ui/vnc.c index d47879f579..c96bd8ceea 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2242,7 +2242,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) static void set_pixel_conversion(VncState *vs) { - pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf); + pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf, + vs->client_endian); if (fmt == VNC_SERVER_FB_FORMAT) { vs->write_pixels = vnc_write_pixels_copy; From 9238fd846db22033cd12aca5736a25d69e1a5985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 28 Jan 2025 13:27:25 +0000 Subject: [PATCH 10/71] ui/vnc: fix tight palette pixel encoding for 8/16-bpp formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When sending a tight rectangle with the palette filter, if the client format was 8/16bpp, the colours on big endian hosts are not set as we're sending the wrong bytes. We must first cast the 32-bit colour to a 16/8-bit value, and then send the result. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel P. Berrangé (cherry picked from commit 63d320909220a90647c484263ae5e2f26eb54587) Signed-off-by: Michael Tokarev --- ui/vnc-enc-tight.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index a5bdc19ebb..25c7b2c788 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -1001,16 +1001,24 @@ static int send_mono_rect(VncState *vs, int x, int y, break; } case 2: - vnc_write(vs, &bg, 2); - vnc_write(vs, &fg, 2); + { + uint16_t bg16 = bg; + uint16_t fg16 = fg; + vnc_write(vs, &bg16, 2); + vnc_write(vs, &fg16, 2); tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg); break; + } default: - vnc_write_u8(vs, bg); - vnc_write_u8(vs, fg); + { + uint8_t bg8 = bg; + uint8_t fg8 = fg; + vnc_write_u8(vs, bg8); + vnc_write_u8(vs, fg8); tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg); break; } + } vs->tight->tight.offset = bytes; bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY); From 1702044371d334bfe4e3ffd96378a419bae4f4f7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 29 May 2025 17:45:10 +0100 Subject: [PATCH 11/71] hw/arm: Add missing psci_conduit to NPCM8XX SoC boot info Without psci_conduit, the Linux kernel crashes almost immediately. psci: probing for conduit method from DT. Internal error: Oops - Undefined instruction: 0000000002000000 [#1] PREEMPT SMP Fixes: ae0c4d1a1290 ("hw/arm: Add NPCM8XX SoC") Cc: qemu-stable@nongnu.org Cc: Hao Wu Cc: Peter Maydell Signed-off-by: Guenter Roeck Message-id: 20250315142050.3642741-1-linux@roeck-us.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell (cherry picked from commit e6bc01777e5a4b6ecf3414b21a2d7b4846bf4817) Signed-off-by: Michael Tokarev --- hw/arm/npcm8xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/npcm8xx.c b/hw/arm/npcm8xx.c index f182accc47..e5a1929ed7 100644 --- a/hw/arm/npcm8xx.c +++ b/hw/arm/npcm8xx.c @@ -346,6 +346,7 @@ static struct arm_boot_info npcm8xx_binfo = { .secure_boot = false, .board_id = -1, .board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR, + .psci_conduit = QEMU_PSCI_CONDUIT_SMC, }; void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc) From 21f86e29510a7d8f6daca523ef4d630854c70b4f Mon Sep 17 00:00:00 2001 From: Huaitong Han Date: Thu, 22 May 2025 18:05:48 +0800 Subject: [PATCH 12/71] vhost: Don't set vring call if guest notifier is unused The vring call fd is set even when the guest does not use MSI-X (e.g., in the case of virtio PMD), leading to unnecessary CPU overhead for processing interrupts. The commit 96a3d98d2c("vhost: don't set vring call if no vector") optimized the case where MSI-X is enabled but the queue vector is unset. However, there's an additional case where the guest uses INTx and the INTx_DISABLED bit in the PCI config is set, meaning that no interrupt notifier will actually be used. In such cases, the vring call fd should also be cleared to avoid redundant interrupt handling. Fixes: 96a3d98d2c("vhost: don't set vring call if no vector") Reported-by: Zhiyuan Yuan Signed-off-by: Jidong Xia Signed-off-by: Huaitong Han Message-Id: <20250522100548.212740-1-hanht2@chinatelecom.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit a9403bfcd93025df7b1924d0cf34fbc408955b33) Signed-off-by: Michael Tokarev --- hw/pci/pci.c | 2 +- hw/virtio/virtio-pci.c | 7 ++++++- include/hw/pci/pci.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2844ec5556..503a897528 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1719,7 +1719,7 @@ static void pci_update_mappings(PCIDevice *d) pci_update_vga(d); } -static inline int pci_irq_disabled(PCIDevice *d) +int pci_irq_disabled(PCIDevice *d) { return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 3ca3f849d3..e60ad843fc 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1215,7 +1215,12 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, static bool virtio_pci_query_guest_notifiers(DeviceState *d) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - return msix_enabled(&proxy->pci_dev); + + if (msix_enabled(&proxy->pci_dev)) { + return true; + } else { + return pci_irq_disabled(&proxy->pci_dev); + } } static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 822fbacdf0..7e382552b9 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -668,6 +668,7 @@ void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev); qemu_irq pci_allocate_irq(PCIDevice *pci_dev); void pci_set_irq(PCIDevice *pci_dev, int level); +int pci_irq_disabled(PCIDevice *d); static inline void pci_irq_assert(PCIDevice *pci_dev) { From 325d039d25f3626c0a52075e1d84e504f13e54c2 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 26 May 2025 22:38:20 +0200 Subject: [PATCH 13/71] hw/i386/pc_piix: Fix RTC ISA IRQ wiring of isapc machine Commit 56b1f50e3c10 ("hw/i386/pc: Wire RTC ISA IRQs in south bridges") attempted to refactor RTC IRQ wiring which was previously done in pc_basic_device_init() but forgot about the isapc machine. Fix this by wiring in the code section dedicated exclusively to the isapc machine. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2961 Fixes: 56b1f50e3c10 ("hw/i386/pc: Wire RTC ISA IRQs in south bridges") cc: qemu-stable Signed-off-by: Bernhard Beschow Reviewed-by: Mark Cave-Ayland Message-Id: <20250526203820.1853-1-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 0b006153b7ec66505cb2d231235aa19ca5d2ce37) Signed-off-by: Michael Tokarev --- hw/i386/pc_piix.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 6c91e2d292..7cfa142b11 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -285,6 +285,8 @@ static void pc_init1(MachineState *machine, const char *pci_type) pcms->idebus[0] = qdev_get_child_bus(dev, "ide.0"); pcms->idebus[1] = qdev_get_child_bus(dev, "ide.1"); } else { + uint32_t irq; + isa_bus = isa_bus_new(NULL, system_memory, system_io, &error_abort); isa_bus_register_input_irqs(isa_bus, x86ms->gsi); @@ -292,6 +294,9 @@ static void pc_init1(MachineState *machine, const char *pci_type) x86ms->rtc = isa_new(TYPE_MC146818_RTC); qdev_prop_set_int32(DEVICE(x86ms->rtc), "base_year", 2000); isa_realize_and_unref(x86ms->rtc, isa_bus, &error_fatal); + irq = object_property_get_uint(OBJECT(x86ms->rtc), "irq", + &error_fatal); + isa_connect_gpio_out(ISA_DEVICE(x86ms->rtc), 0, irq); i8257_dma_init(OBJECT(machine), isa_bus, 0); pcms->hpet_enabled = false; From 8399ccb48041be54cec39b0c08494ea01ca84e4c Mon Sep 17 00:00:00 2001 From: Sairaj Kodilkar Date: Fri, 16 May 2025 15:35:34 +0530 Subject: [PATCH 14/71] hw/i386/amd_iommu: Fix device setup failure when PT is on. Commit c1f46999ef506 ("amd_iommu: Add support for pass though mode") introduces the support for "pt" flag by enabling nodma memory when "pt=off". This allowed VFIO devices to successfully register notifiers by using nodma region. But, This also broke things when guest is booted with the iommu=nopt because, devices bypass the IOMMU and use untranslated addresses (IOVA) to perform DMA reads/writes to the nodma memory region, ultimately resulting in a failure to setup the devices in the guest. Fix the above issue by always enabling the amdvi_dev_as->iommu memory region. But this will once again cause VFIO devices to fail while registering the notifiers with AMD IOMMU memory region. Fixes: c1f46999ef506 ("amd_iommu: Add support for pass though mode") Signed-off-by: Sairaj Kodilkar Reviewed-by: Vasant Hegde Message-Id: <20250516100535.4980-2-sarunkod@amd.com> Fixes: c1f46999ef506 ("amd_iommu: Add support for pass though mode") Signed-off-by: Sairaj Kodilkar Reviewed-by: Vasant Hegde (cherry picked from commit 31753d5a336fbb4e9246397f4b90b6f611f27f22) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 5f9b952799..df8ba5d39a 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1426,7 +1426,6 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) AMDVIState *s = opaque; AMDVIAddressSpace **iommu_as, *amdvi_dev_as; int bus_num = pci_bus_num(bus); - X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); iommu_as = s->address_spaces[bus_num]; @@ -1486,15 +1485,8 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) AMDVI_INT_ADDR_FIRST, &amdvi_dev_as->iommu_ir, 1); - if (!x86_iommu->pt_supported) { - memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false); - memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), - true); - } else { - memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), - false); - memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, true); - } + memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false); + memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), true); } return &iommu_as[devfn]->as; } From c3e1181bafaecbcf9deae6a8bb4ad3586e221a3d Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 16 May 2025 15:35:35 +0530 Subject: [PATCH 15/71] hw/i386/amd_iommu: Fix xtsup when vcpus < 255 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If vCPUs > 255 then x86 common code (x86_cpus_init()) call kvm_enable_x2apic(). But if vCPUs <= 255 then the common code won't calls kvm_enable_x2apic(). This is because commit 8c6619f3e692 ("hw/i386/amd_iommu: Simplify non-KVM checks on XTSup feature") removed the call to kvm_enable_x2apic when xtsup is "on", which break things when guest is booted with x2apic mode and there are <= 255 vCPUs. Fix this by adding back kvm_enable_x2apic() call when xtsup=on. Fixes: 8c6619f3e692 ("hw/i386/amd_iommu: Simplify non-KVM checks on XTSup feature") Reported-by: Alejandro Jimenez Tested-by: Tested-by: Alejandro Jimenez Cc: Philippe Mathieu-Daudé Cc: Joao Martins Signed-off-by: Vasant Hegde Signed-off-by: Sairaj Kodilkar Message-Id: <20250516100535.4980-3-sarunkod@amd.com> Fixes: 8c6619f3e692 ("hw/i386/amd_iommu: Simplify non-KVM checks on XTSup feature") Reported-by: Alejandro Jimenez Tested-by: Tested-by: Alejandro Jimenez Cc: Philippe Mathieu-Daudé Cc: Joao Martins Signed-off-by: Vasant Hegde Signed-off-by: Sairaj Kodilkar (cherry picked from commit 0f178860df3489a9d3c19a5f7f024e6aa6c26515) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index df8ba5d39a..af85706b8a 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1649,6 +1649,14 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) exit(EXIT_FAILURE); } + if (s->xtsup) { + if (kvm_irqchip_is_split() && !kvm_enable_x2apic()) { + error_report("AMD IOMMU xtsup=on requires x2APIC support on " + "the KVM side"); + exit(EXIT_FAILURE); + } + } + pci_setup_iommu(bus, &amdvi_iommu_ops, s); amdvi_init(s); } From 47ddae806b9272959965f05b72187bdc933c7d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:24 +0200 Subject: [PATCH 16/71] audio: fix SIGSEGV in AUD_get_buffer_size_out() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As far as the emulated audio devices are concerned the pointer returned by AUD_open_out() is an opaque handle. This includes the NULL pointer. In this case, AUD_get_buffer_size_out() should return a sensible buffer size instead of triggering a segmentation fault. All other public AUD_*_out() and audio_*_out() functions handle this case. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-2-vr_qemu@t-online.de> (cherry picked from commit 5ddd6c8dc849b4af44bd06840c9133d64e62c27c) Signed-off-by: Michael Tokarev --- audio/audio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index 41ee11aaad..70ef22b1a4 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -905,6 +905,10 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size) int AUD_get_buffer_size_out(SWVoiceOut *sw) { + if (!sw) { + return 0; + } + return sw->hw->samples * sw->hw->info.bytes_per_frame; } From 6b12cb6edc09fa28429e72af12517e45b6c7c734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:25 +0200 Subject: [PATCH 17/71] audio: fix size calculation in AUD_get_buffer_size_out() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The buffer size calculated by AUD_get_buffer_size_out() is often incorrect. sw->hw->samples * sw->hw->info.bytes_per_frame is the size of the mixing engine buffer in audio frames multiplied by the size of one frame of the audio backend. Due to resampling or format conversion, the size of the frontend buffer can differ significantly. Return the correct buffer size when the mixing engine is used. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-3-vr_qemu@t-online.de> (cherry picked from commit ccb4fec0e5f233cb61a83b3af59ae11716ea06c0) Signed-off-by: Michael Tokarev --- audio/audio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index 70ef22b1a4..3f5baf0cc6 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -909,6 +909,10 @@ int AUD_get_buffer_size_out(SWVoiceOut *sw) return 0; } + if (audio_get_pdo_out(sw->s->dev)->mixing_engine) { + return sw->resample_buf.size * sw->info.bytes_per_frame; + } + return sw->hw->samples * sw->hw->info.bytes_per_frame; } From 92d08b3c0d19467e2bb6ea079aba82c1e6ead9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:26 +0200 Subject: [PATCH 18/71] hw/audio/asc: fix SIGSEGV in asc_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AUD_open_out() may fail and return NULL. This may then lead to a segmentation fault in memset() below. The memset() behaviour is undefined if the pointer to the destination object is a null pointer. Add the missing error handling code. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Reviewed-by: Mark Cave-Ayland Message-Id: <20250515054429.7385-4-vr_qemu@t-online.de> (cherry picked from commit d009f26a54f573468be721590a19350c224bc730) Signed-off-by: Michael Tokarev --- hw/audio/asc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/audio/asc.c b/hw/audio/asc.c index cc205bf063..b7d0fd8acd 100644 --- a/hw/audio/asc.c +++ b/hw/audio/asc.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" +#include "qapi/error.h" #include "hw/sysbus.h" #include "hw/irq.h" #include "audio/audio.h" @@ -654,6 +655,12 @@ static void asc_realize(DeviceState *dev, Error **errp) s->voice = AUD_open_out(&s->card, s->voice, "asc.out", s, asc_out_cb, &as); + if (!s->voice) { + AUD_remove_card(&s->card); + error_setg(errp, "Initializing audio stream failed"); + return; + } + s->shift = 1; s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift; s->mixbuf = g_malloc0(s->samples << s->shift); From 9f80e4707cb05ab356c69ae8fde8537ef0b5810d Mon Sep 17 00:00:00 2001 From: "Xin Li (Intel)" Date: Fri, 3 Jan 2025 00:48:25 -0800 Subject: [PATCH 19/71] target/i386: Remove FRED dependency on WRMSRNS WRMSRNS doesn't become a required feature for FERD, and Linux has removed the dependency, as such remove it from Qemu. Cc: qemu-stable@nongnu.org Signed-off-by: Xin Li (Intel) Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250103084827.1820007-2-xin@zytor.com Signed-off-by: Paolo Bonzini (cherry picked from commit 0b901459a87a7fdbed36e574aae33e0635a3e9af) Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 5e12cba1b8..2c9517f56d 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1774,10 +1774,6 @@ static FeatureDep feature_dependencies[] = { .from = { FEAT_7_1_EAX, CPUID_7_1_EAX_LKGS }, .to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED }, }, - { - .from = { FEAT_7_1_EAX, CPUID_7_1_EAX_WRMSRNS }, - .to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED }, - }, { .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX }, .to = { FEAT_7_0_ECX, CPUID_7_0_ECX_SGX_LC }, From d8e6f3f885cc9e72a7c298bd7fb830b6f48051cf Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 29 May 2025 16:31:47 -0400 Subject: [PATCH 20/71] iotests: fix 240 Commit 2e8e18c2e463 ("virtio-scsi: add iothread-vq-mapping parameter") removed the limitation that virtio-scsi devices must successfully set the AioContext on their BlockBackends. This was made possible thanks to the QEMU multi-queue block layer. This change broke qemu-iotests 240, which checks that adding a virtio-scsi device with a drive that is already in another AioContext will fail. Update the test to take the relaxed behavior into account. I considered removing this test case entirely, but the code coverage still seems valuable. Fixes: 2e8e18c2e463 ("virtio-scsi: add iothread-vq-mapping parameter") Reported-by: Thomas Huth Signed-off-by: Stefan Hajnoczi Reviewed-by: Eric Blake Tested-by: Eric Blake Message-ID: <20250529203147.180338-1-stefanha@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf (cherry picked from commit 2e887187454e57d04522099d4f04d17137d6e05c) Signed-off-by: Michael Tokarev --- tests/qemu-iotests/240 | 2 -- tests/qemu-iotests/240.out | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 index 9b281e1dc0..f8af9ff648 100755 --- a/tests/qemu-iotests/240 +++ b/tests/qemu-iotests/240 @@ -81,8 +81,6 @@ class TestCase(iotests.QMPTestCase): self.vm.qmp_log('device_del', id='scsi-hd0') self.vm.event_wait('DEVICE_DELETED') - self.vm.qmp_log('device_add', id='scsi-hd1', driver='scsi-hd', drive='hd0', bus="scsi1.0") - self.vm.qmp_log('device_del', id='scsi-hd1') self.vm.event_wait('DEVICE_DELETED') self.vm.qmp_log('blockdev-del', node_name='hd0') diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out index 89ed25e506..10dcc42e06 100644 --- a/tests/qemu-iotests/240.out +++ b/tests/qemu-iotests/240.out @@ -46,10 +46,8 @@ {"execute": "device_add", "arguments": {"bus": "scsi0.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}} {"return": {}} {"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}} -{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}} -{"execute": "device_del", "arguments": {"id": "scsi-hd0"}} {"return": {}} -{"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}} +{"execute": "device_del", "arguments": {"id": "scsi-hd0"}} {"return": {}} {"execute": "device_del", "arguments": {"id": "scsi-hd1"}} {"return": {}} From ab96ea4b4d257919f5d0042eedcb1c3cfa1d0a0c Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Fri, 23 May 2025 09:02:11 +0200 Subject: [PATCH 21/71] hw/core/qdev-properties-system: Add missing return in set_drive_helper() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, changing the 'drive' property of e.g. a scsi-hd object will result in an assertion failure if the aio context of the block node it's replaced with doesn't match the current aio context: > bdrv_replace_child_noperm: Assertion `bdrv_get_aio_context(old_bs) == > bdrv_get_aio_context(new_bs)' failed. The problematic scenario is already detected, but a 'return' statement was missing. Cc: qemu-stable@nongnu.org Fixes: d1a58c176a ("qdev: allow setting drive property for realized device") Signed-off-by: Fiona Ebner Message-ID: <20250523070211.280498-1-f.ebner@proxmox.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf (cherry picked from commit eef2dd03f948a512499775043bdc0c5c88d8a2dd) Signed-off-by: Michael Tokarev --- hw/core/qdev-properties-system.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index a7dde73c29..6b73127123 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -145,6 +145,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name, if (ctx != bdrv_get_aio_context(bs)) { error_setg(errp, "Different aio context is not supported for new " "node"); + return; } blk_replace_bs(blk, bs, errp); From 6276ce6d702bd9a7390942bbc29acaaf03b53c4e Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 4 Jun 2025 14:55:01 +0800 Subject: [PATCH 22/71] hw/loongarch/virt: Fix big endian support with MCFG table With API build_mcfg(), it is not necessary with parameter structure AcpiMcfgInfo to convert to little endian since it is directly used with host native endian. Here remove endian conversion before calling function build_mcfg(). With this patch, bios-tables-test passes to run on big endian host machine S390. Fixes: 735143f10d3e ("hw/loongarch: Add acpi ged support") Cc: qemu-stable@nongnu.org Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250604065502.1114098-2-maobibo@loongson.cn> Signed-off-by: Song Gao (cherry picked from commit 9c55c03c05c1899521ff0c991b9296633d759890) Signed-off-by: Michael Tokarev --- hw/loongarch/virt-acpi-build.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/loongarch/virt-acpi-build.c b/hw/loongarch/virt-acpi-build.c index fced6c445a..24ccb580bd 100644 --- a/hw/loongarch/virt-acpi-build.c +++ b/hw/loongarch/virt-acpi-build.c @@ -575,8 +575,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); { AcpiMcfgInfo mcfg = { - .base = cpu_to_le64(VIRT_PCI_CFG_BASE), - .size = cpu_to_le64(VIRT_PCI_CFG_SIZE), + .base = VIRT_PCI_CFG_BASE, + .size = VIRT_PCI_CFG_SIZE, }; build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id, lvms->oem_table_id); From c902fc66c9508c6fa2ec17510f5ae9241c0859fb Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Mon, 2 Jun 2025 12:46:55 +0100 Subject: [PATCH 23/71] hw/arm/virt: Check bypass iommu is not set for iommu-map DT property default_bus_bypass_iommu tells us whether the bypass_iommu is set for the default PCIe root bus. Make sure we check that before adding the "iommu-map" DT property. Cc: qemu-stable@nongnu.org Fixes: 6d7a85483a06 ("hw/arm/virt: Add default_bus_bypass_iommu machine option") Suggested-by: Eric Auger Signed-off-by: Shameer Kolothum Reviewed-by: Donald Dutile Reviewed-by: Eric Auger Message-id: 20250602114655.42920-1-shameerali.kolothum.thodi@huawei.com Signed-off-by: Peter Maydell (cherry picked from commit f5ec751ee70d7960a97c6c675f69e924d82dc60d) Signed-off-by: Michael Tokarev --- hw/arm/virt.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a96452f17a..0e78616aac 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1492,9 +1492,12 @@ static void create_virtio_iommu_dt_bindings(VirtMachineState *vms) qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle); g_free(node); - qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map", - 0x0, vms->iommu_phandle, 0x0, bdf, - bdf + 1, vms->iommu_phandle, bdf + 1, 0xffff - bdf); + if (!vms->default_bus_bypass_iommu) { + qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map", + 0x0, vms->iommu_phandle, 0x0, bdf, + bdf + 1, vms->iommu_phandle, bdf + 1, + 0xffff - bdf); + } } static void create_pcie(VirtMachineState *vms) @@ -1617,8 +1620,10 @@ static void create_pcie(VirtMachineState *vms) switch (vms->iommu) { case VIRT_IOMMU_SMMUV3: create_smmu(vms, vms->bus); - qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map", - 0x0, vms->iommu_phandle, 0x0, 0x10000); + if (!vms->default_bus_bypass_iommu) { + qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map", + 0x0, vms->iommu_phandle, 0x0, 0x10000); + } break; default: g_assert_not_reached(); From 436b3dd8cc8e8fe67d52716c51781fb0149dd0b2 Mon Sep 17 00:00:00 2001 From: Ethan Chen Date: Fri, 6 Jun 2025 17:57:28 +0800 Subject: [PATCH 24/71] qemu-options.hx: Fix reversed description of icount sleep behavior The documentation for the -icount option incorrectly describes the behavior of the sleep suboption. Based on the actual implementation and system behavior, the effects of sleep=on and sleep=off were inadvertently reversed. This commit updates the description to reflect their intended functionality. Cc: qemu-stable@nongnu.org Fixes: fa647905e6ba ("qemu-options.hx: Fix minor issues in icount documentation") Signed-off-by: Ethan Chen Message-id: 20250606095728.3672832-1-ethan84@andestech.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell (cherry picked from commit e372214e663a4370fe064f7867f402eade37357e) Signed-off-by: Michael Tokarev --- qemu-options.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index dc694a99a3..396eea7ef2 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4936,13 +4936,13 @@ SRST with actual performance. When the virtual cpu is sleeping, the virtual time will advance at - default speed unless ``sleep=on`` is specified. With - ``sleep=on``, the virtual time will jump to the next timer + default speed unless ``sleep=off`` is specified. With + ``sleep=off``, the virtual time will jump to the next timer deadline instantly whenever the virtual cpu goes to sleep mode and will not advance if no timer is enabled. This behavior gives deterministic execution times from the guest point of view. - The default if icount is enabled is ``sleep=off``. - ``sleep=on`` cannot be used together with either ``shift=auto`` + The default if icount is enabled is ``sleep=on``. + ``sleep=off`` cannot be used together with either ``shift=auto`` or ``align=on``. ``align=on`` will activate the delay algorithm which will try to From b7da1f5f5ddd196c7e992b6b7b746c5b54ae1d5a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 5 Jun 2025 15:18:01 +0100 Subject: [PATCH 25/71] hw/arm/mps2: Configure the AN500 CPU with 16 MPU regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AN500 application note documents that it configures the Cortex-M7 CPU to have 16 MPU regions. We weren't doing this in our emulation, so the CPU had only the default 8 MPU regions. Set the mpu-ns-regions property to 16 for this board. This bug doesn't affect any of the other board types we model in this source file, because they all use either the Cortex-M3 or Cortex-M4. Those CPUs do not have an RTL configurable number of MPU regions, and always provide 8 regions if the MPU is built in. Cc: qemu-stable@nongnu.org Reported-by: Corentin GENDRE Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Message-id: 20250605141801.1083266-1-peter.maydell@linaro.org (cherry picked from commit cd38e638c43e4d5d3fd65dd4529c2e6153c9c408) Signed-off-by: Michael Tokarev --- hw/arm/mps2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 3f8db0cab6..313c401eb8 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -224,7 +224,11 @@ static void mps2_common_init(MachineState *machine) switch (mmc->fpga_type) { case FPGA_AN385: case FPGA_AN386: + qdev_prop_set_uint32(armv7m, "num-irq", 32); + break; case FPGA_AN500: + /* The AN500 configures its Cortex-M7 with 16 MPU regions */ + qdev_prop_set_uint32(armv7m, "mpu-ns-regions", 16); qdev_prop_set_uint32(armv7m, "num-irq", 32); break; case FPGA_AN511: From 3cf25f4c71086ec96df7e3b0db7f093a684e6fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Neusch=C3=A4fer?= Date: Fri, 13 Jun 2025 17:59:32 +0200 Subject: [PATCH 26/71] linux-user/arm: Fix return value of SYS_cacheflush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although the emulated cacheflush syscall does nothing, it still needs to return zero to indicate success. Cc: qemu-stable@nongnu.org Signed-off-by: J. Neuschäfer Message-id: 20250613-cache-v1-1-ee9f4a9ba81b@gmx.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell (cherry picked from commit 5ad2b1f443a96444cf3e7a2fbe17aae696201012) Signed-off-by: Michael Tokarev --- linux-user/arm/cpu_loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 7416e3216e..098b54d10e 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -362,6 +362,7 @@ void cpu_loop(CPUARMState *env) switch (n) { case ARM_NR_cacheflush: /* nop */ + env->regs[0] = 0; break; case ARM_NR_set_tls: cpu_set_tls(env, env->regs[0]); From fdd20285ae19cf26c0d8d561684fb8126fa48f22 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 3 Jun 2025 10:48:09 +0800 Subject: [PATCH 27/71] target/loongarch: add check for fcond fcond only has 22 types, add a check for fcond. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2972 Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-Id: <20250603024810.350510-1-gaosong@loongson.cn> (cherry picked from commit e7788da9860c97920c19fa1150806186513ef256) Signed-off-by: Michael Tokarev --- .../loongarch/tcg/insn_trans/trans_fcmp.c.inc | 25 +++++++++++++------ .../loongarch/tcg/insn_trans/trans_vec.c.inc | 16 +++++++++--- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc b/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc index 3babf69e4a..6a2c030a6b 100644 --- a/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_fcmp.c.inc @@ -4,10 +4,15 @@ */ /* bit0(signaling/quiet) bit1(lt) bit2(eq) bit3(un) bit4(neq) */ -static uint32_t get_fcmp_flags(int cond) +static uint32_t get_fcmp_flags(DisasContext *ctx, int cond) { uint32_t flags = 0; + /*check cond , cond =[0-8,10,12] */ + if ((cond > 8) &&(cond != 10) && (cond != 12)) { + return -1; + } + if (cond & 0x1) { flags |= FCMP_LT; } @@ -26,9 +31,14 @@ static uint32_t get_fcmp_flags(int cond) static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) { TCGv var, src1, src2; - uint32_t flags; + uint32_t flags = get_fcmp_flags(ctx, a->fcond >>1); void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + if (flags == -1) { + generate_exception(ctx, EXCCODE_INE); + return true; + } + if (!avail_FP_SP(ctx)) { return false; } @@ -39,8 +49,6 @@ static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) src1 = get_fpr(ctx, a->fj); src2 = get_fpr(ctx, a->fk); fn = (a->fcond & 1 ? gen_helper_fcmp_s_s : gen_helper_fcmp_c_s); - flags = get_fcmp_flags(a->fcond >> 1); - fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); @@ -50,9 +58,14 @@ static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) { TCGv var, src1, src2; - uint32_t flags; + uint32_t flags = get_fcmp_flags(ctx, a->fcond >> 1); void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + if (flags == -1) { + generate_exception(ctx, EXCCODE_INE); + return true; + } + if (!avail_FP_DP(ctx)) { return false; } @@ -63,8 +76,6 @@ static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) src1 = get_fpr(ctx, a->fj); src2 = get_fpr(ctx, a->fk); fn = (a->fcond & 1 ? gen_helper_fcmp_s_d : gen_helper_fcmp_c_d); - flags = get_fcmp_flags(a->fcond >> 1); - fn(var, tcg_env, src1, src2, tcg_constant_i32(flags)); tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd])); diff --git a/target/loongarch/tcg/insn_trans/trans_vec.c.inc b/target/loongarch/tcg/insn_trans/trans_vec.c.inc index dff92772ad..d6f0560349 100644 --- a/target/loongarch/tcg/insn_trans/trans_vec.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_vec.c.inc @@ -4655,19 +4655,23 @@ TRANS(xvslti_du, LASX, do_xcmpi, MO_64, TCG_COND_LTU) static bool do_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) { - uint32_t flags; + uint32_t flags = get_fcmp_flags(ctx, a->fcond >> 1); void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32); TCGv_i32 vd = tcg_constant_i32(a->vd); TCGv_i32 vj = tcg_constant_i32(a->vj); TCGv_i32 vk = tcg_constant_i32(a->vk); TCGv_i32 oprsz = tcg_constant_i32(sz); + if(flags == -1){ + generate_exception(ctx, EXCCODE_INE); + return true; + } + if (!check_vec(ctx, sz)) { return true; } fn = (a->fcond & 1 ? gen_helper_vfcmp_s_s : gen_helper_vfcmp_c_s); - flags = get_fcmp_flags(a->fcond >> 1); fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); return true; @@ -4675,19 +4679,23 @@ static bool do_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) static bool do_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz) { - uint32_t flags; + uint32_t flags = get_fcmp_flags(ctx, a->fcond >> 1); void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32); TCGv_i32 vd = tcg_constant_i32(a->vd); TCGv_i32 vj = tcg_constant_i32(a->vj); TCGv_i32 vk = tcg_constant_i32(a->vk); TCGv_i32 oprsz = tcg_constant_i32(sz); + if (flags == -1) { + generate_exception(ctx, EXCCODE_INE); + return true; + } + if (!check_vec(ctx, sz)) { return true; } fn = (a->fcond & 1 ? gen_helper_vfcmp_s_d : gen_helper_vfcmp_c_d); - flags = get_fcmp_flags(a->fcond >> 1); fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags)); return true; From 46cdfdfe9202c4e58aed99bfbf7e20f514c671cd Mon Sep 17 00:00:00 2001 From: Song Gao Date: Wed, 4 Jun 2025 16:40:05 +0800 Subject: [PATCH 28/71] target/loongarch: fix vldi/xvldi raise wrong error on qemu we got an aborted error ** ERROR:../target/loongarch/tcg/insn_trans/trans_vec.c.inc:3574:vldi_get_value: code should not be reached Bail out! ERROR:../target/loongarch/tcg/insn_trans/trans_vec.c.inc:3574:vldi_get_value: code should not be reached Aborted (core dumped) but on 3A600/3A5000 we got a "Illegal instruction" error. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2971 Fixes: 29bb5d727ff ("target/loongarch: Implement vldi") Cc: qemu-stable@nongnu.org Reviewed-by: Bibo Mao Reviewed-by: Richard Henderson Signed-off-by: Song Gao (cherry picked from commit c2a2e1ad2a749caa864281b1d4dc3f16c3f344f6) Signed-off-by: Michael Tokarev --- target/loongarch/tcg/insn_trans/trans_vec.c.inc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/loongarch/tcg/insn_trans/trans_vec.c.inc b/target/loongarch/tcg/insn_trans/trans_vec.c.inc index d6f0560349..78730029cb 100644 --- a/target/loongarch/tcg/insn_trans/trans_vec.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_vec.c.inc @@ -3465,7 +3465,7 @@ TRANS(xvmsknz_b, LASX, gen_xx, gen_helper_vmsknz_b) static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm) { int mode; - uint64_t data, t; + uint64_t data = 0, t; /* * imm bit [11:8] is mode, mode value is 0-12. @@ -3570,17 +3570,26 @@ static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm) } break; default: - generate_exception(ctx, EXCCODE_INE); g_assert_not_reached(); } return data; } +static bool check_valid_vldi_mode(arg_vldi *a) +{ + return extract32(a->imm, 8, 4) <= 12; +} + static bool gen_vldi(DisasContext *ctx, arg_vldi *a, uint32_t oprsz) { int sel, vece; uint64_t value; + if (!check_valid_vldi_mode(a)) { + generate_exception(ctx, EXCCODE_INE); + return true; + } + if (!check_vec(ctx, oprsz)) { return true; } From 22909a1397ad9679f0ffaba3016a3420ace2da21 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Jun 2025 09:57:53 -0600 Subject: [PATCH 29/71] tcg: Fix constant propagation in tcg_reg_alloc_dup The scalar constant must be replicated for dup. Cc: qemu-stable@nongnu.org Fixes: bab1671f0fa ("tcg: Manually expand INDEX_op_dup_vec") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3002 Signed-off-by: Richard Henderson (cherry picked from commit 0d0fc3f4658937fb81fcc16a89738e83bd8d4795) Signed-off-by: Michael Tokarev --- tcg/tcg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index dfd48b8264..b1a7465df2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -4927,7 +4927,7 @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op) if (its->val_type == TEMP_VAL_CONST) { /* Propagate constant via movi -> dupi. */ - tcg_target_ulong val = its->val; + tcg_target_ulong val = dup_const(vece, its->val); if (IS_DEAD_ARG(1)) { temp_dead(s, its); } From ed4bad29e7dd437f7a8168dbe04b15909d945de9 Mon Sep 17 00:00:00 2001 From: Solomon Tan Date: Tue, 1 Jul 2025 15:08:25 +0100 Subject: [PATCH 30/71] target/arm: Make RETA[AB] UNDEF when pauth is not implemented MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the Arm A-profile A64 Instruction Set Architecture, RETA[AB] should be decoded as UNDEF if the pauth feature is not implemented. We got this right in the initial implementation, but accidentally dropped the feature-check when we converted these insns to decodetree. Cc: qemu-stable@nongnu.org Fixes: 0ebbe9021254f ("target/arm: Convert BRA[AB]Z, BLR[AB]Z, RETA[AB] to decodetree") Signed-off-by: Solomon Tan Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-id: 20250616171549.59190-1-root@wjsota.com Signed-off-by: Peter Maydell (cherry picked from commit 9a3bf0e0ab628de7051b41a88c4628aa9e4d311b) Signed-off-by: Michael Tokarev --- target/arm/tcg/translate-a64.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 39014325df..f6e88eb5f7 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -1821,6 +1821,10 @@ static bool trans_RETA(DisasContext *s, arg_reta *a) { TCGv_i64 dst; + if (!dc_isar_feature(aa64_pauth, s)) { + return false; + } + dst = auth_branch_target(s, cpu_reg(s, 30), cpu_X[31], !a->m); gen_a64_set_pc(s, dst); s->base.is_jmp = DISAS_JUMP; From 5df7910a237ccb8ebd31f45d4216f3765c6010ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Jul 2025 15:08:33 +0100 Subject: [PATCH 31/71] target/arm: Correct KVM & HVF dtb_compatible value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Linux kernel knows how to parse "arm,armv8", not "arm,arm-v8". See arch/arm64/boot/dts/foundation-v8.dts: https://github.com/torvalds/linux/commit/90556ca1ebdd Cc: qemu-stable@nongnu.org Fixes: 26861c7ce06 ("target-arm: Add minimal KVM AArch64 support") Fixes: 585df85efea ("hvf: arm: Implement -cpu host") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250623121845.7214-10-philmd@linaro.org Signed-off-by: Peter Maydell (cherry picked from commit a412575837b6a46584fba891e3706e87bd09a3e6) (Mjt: context fix in target/arm/kvm.c) Signed-off-by: Michael Tokarev --- target/arm/hvf/hvf.c | 2 +- target/arm/kvm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 2439af63a0..01e26a9726 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -878,7 +878,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) hv_vcpu_exit_t *exit; int i; - ahcf->dtb_compatible = "arm,arm-v8"; + ahcf->dtb_compatible = "arm,armv8"; ahcf->features = (1ULL << ARM_FEATURE_V8) | (1ULL << ARM_FEATURE_NEON) | (1ULL << ARM_FEATURE_AARCH64) | diff --git a/target/arm/kvm.c b/target/arm/kvm.c index da30bdbb23..e1b87116db 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -305,7 +305,7 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) } ahcf->target = init.target; - ahcf->dtb_compatible = "arm,arm-v8"; + ahcf->dtb_compatible = "arm,armv8"; err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0, ARM64_SYS_REG(3, 0, 0, 4, 0)); From fb9bad329cadba1f09642bb20a5ed2ce709b9dc3 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Fri, 27 Jun 2025 12:25:11 +0100 Subject: [PATCH 32/71] virtio-gpu: support context init multiple timeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Venus and later native contexts have their own fence context along with multiple timelines within. Fences wtih VIRTIO_GPU_FLAG_INFO_RING_IDX in the flags must be dispatched to be created on the target context. Fence signaling also has to be handled on the specific timeline within that target context. Before this change, venus fencing is completely broken if the host driver doesn't support implicit fencing with external memory objects. Frames can go backwards along with random artifacts on screen if the host driver doesn't attach an implicit fence to the render target. The symptom could be hidden by certain guest wsi backend that waits on a venus native VkFence object for the actual payload with limited present modes or under special configs. e.g. x11 mailbox or xwayland. After this change, everything related to venus fencing starts making sense. Confirmed this via guest and host side perfetto tracing. Cc: qemu-stable@nongnu.org Fixes: 94d0ea1c1928 ("virtio-gpu: Support Venus context") Signed-off-by: Yiwei Zhang Reviewed-by: Dmitry Osipenko Message-Id: <20250518152651.334115-1-zzyiwei@gmail.com> [AJB: remove version history from commit message] Tested-by: Dmitry Osipenko Signed-off-by: Alex Bennée Reviewed-by: Akihiko Odaki Message-ID: <20250627112512.1880708-16-alex.bennee@linaro.org> (cherry picked from commit 1fa2ffdbec55d84326e22f046bc3e26322836f5a) Signed-off-by: Michael Tokarev --- hw/display/virtio-gpu-virgl.c | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 145a0b3879..94ddc01f91 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -970,6 +970,15 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, } trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type); +#if VIRGL_VERSION_MAJOR >= 1 + if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX) { + virgl_renderer_context_create_fence(cmd->cmd_hdr.ctx_id, + VIRGL_RENDERER_FENCE_FLAG_MERGEABLE, + cmd->cmd_hdr.ring_idx, + cmd->cmd_hdr.fence_id); + return; + } +#endif virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type); } @@ -983,6 +992,11 @@ static void virgl_write_fence(void *opaque, uint32_t fence) * the guest can end up emitting fences out of order * so we should check all fenced cmds not just the first one. */ +#if VIRGL_VERSION_MAJOR >= 1 + if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX) { + continue; + } +#endif if (cmd->cmd_hdr.fence_id > fence) { continue; } @@ -997,6 +1011,29 @@ static void virgl_write_fence(void *opaque, uint32_t fence) } } +#if VIRGL_VERSION_MAJOR >= 1 +static void virgl_write_context_fence(void *opaque, uint32_t ctx_id, + uint32_t ring_idx, uint64_t fence_id) { + VirtIOGPU *g = opaque; + struct virtio_gpu_ctrl_command *cmd, *tmp; + + QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) { + if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX && + cmd->cmd_hdr.ctx_id == ctx_id && cmd->cmd_hdr.ring_idx == ring_idx && + cmd->cmd_hdr.fence_id <= fence_id) { + trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id); + virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + QTAILQ_REMOVE(&g->fenceq, cmd, next); + g_free(cmd); + g->inflight--; + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { + trace_virtio_gpu_dec_inflight_fences(g->inflight); + } + } + } +} +#endif + static virgl_renderer_gl_context virgl_create_context(void *opaque, int scanout_idx, struct virgl_renderer_gl_ctx_param *params) @@ -1031,11 +1068,18 @@ static int virgl_make_context_current(void *opaque, int scanout_idx, } static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = { +#if VIRGL_VERSION_MAJOR >= 1 + .version = 3, +#else .version = 1, +#endif .write_fence = virgl_write_fence, .create_gl_context = virgl_create_context, .destroy_gl_context = virgl_destroy_context, .make_current = virgl_make_context_current, +#if VIRGL_VERSION_MAJOR >= 1 + .write_context_fence = virgl_write_context_fence, +#endif }; static void virtio_gpu_print_stats(void *opaque) From b8f48f40334cb54df36e796b1e825a9061e0fbce Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 25 Jun 2025 10:27:51 +0200 Subject: [PATCH 33/71] hw/s390x/ccw-device: Fix memory leak in loadparm setter Commit bdf12f2a fixed the setter for the "loadparm" machine property, which gets a string from a visitor, passes it to s390_ipl_fmt_loadparm() and then forgot to free it. It left another instance of the same problem unfixed in the "loadparm" device property. Fix it. Signed-off-by: Kevin Wolf Message-ID: <20250625082751.24896-1-kwolf@redhat.com> Reviewed-by: Eric Farman Reviewed-by: Halil Pasic Tested-by: Thomas Huth Signed-off-by: Thomas Huth (cherry picked from commit 78e3781541209b3dcd6f4bb66adf3a3e504b88a4) (Mjt: bdf12f2a is 8efe1592 in stable-10.0 branch) Signed-off-by: Michael Tokarev --- hw/s390x/ccw-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c index 1ea9934f6c..a5ee9dc84d 100644 --- a/hw/s390x/ccw-device.c +++ b/hw/s390x/ccw-device.c @@ -57,7 +57,7 @@ static void ccw_device_set_loadparm(Object *obj, Visitor *v, Error **errp) { CcwDevice *dev = CCW_DEVICE(obj); - char *val; + g_autofree char *val = NULL; int index; index = object_property_get_int(obj, "bootindex", NULL); From 83b48a500f2f96f9403f7d255d9c58c623342542 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jul 2025 08:19:24 -0600 Subject: [PATCH 34/71] target/arm: Fix SME vs AdvSIMD exception priority We failed to raise an exception when sme_excp_el == 0 and fp_excp_el == 1. Cc: qemu-stable@nongnu.org Fixes: 3d74825f4d6 ("target/arm: Add SME enablement checks") Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20250704142112.1018902-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell (cherry picked from commit f9b0f69304071384b12912bf9dd78e9ffd261cec) Signed-off-by: Michael Tokarev --- target/arm/tcg/translate-a64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index f6e88eb5f7..aebf313e38 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -1499,7 +1499,8 @@ bool sme_enabled_check(DisasContext *s) * to be zero when fp_excp_el has priority. This is because we need * sme_excp_el by itself for cpregs access checks. */ - if (!s->fp_excp_el || s->sme_excp_el < s->fp_excp_el) { + if (s->sme_excp_el + && (!s->fp_excp_el || s->sme_excp_el <= s->fp_excp_el)) { bool ret = sme_access_check(s); s->fp_access_checked = (ret ? 1 : -1); return ret; From 0e5f0d87f8e07d72688537282e19881cb9a323e6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jul 2025 08:19:25 -0600 Subject: [PATCH 35/71] target/arm: Fix sve_access_check for SME Do not assume SME implies SVE. Ensure that the non-streaming check is present along the SME path, since it is not implied by sme_*_enabled_check. Cc: qemu-stable@nongnu.org Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20250704142112.1018902-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell (cherry picked from commit b4b2e070f41dd8774a70c6186141678558d79a38) Signed-off-by: Michael Tokarev --- target/arm/tcg/translate-a64.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index aebf313e38..8d3a8d7a25 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -1392,11 +1392,8 @@ static bool fp_access_check_only(DisasContext *s) return true; } -static bool fp_access_check(DisasContext *s) +static bool nonstreaming_check(DisasContext *s) { - if (!fp_access_check_only(s)) { - return false; - } if (s->sme_trap_nonstreaming && s->is_nonstreaming) { gen_exception_insn(s, 0, EXCP_UDEF, syn_smetrap(SME_ET_Streaming, false)); @@ -1405,6 +1402,11 @@ static bool fp_access_check(DisasContext *s) return true; } +static bool fp_access_check(DisasContext *s) +{ + return fp_access_check_only(s) && nonstreaming_check(s); +} + /* * Return <0 for non-supported element sizes, with MO_16 controlled by * FEAT_FP16; return 0 for fp disabled; otherwise return >0 for success. @@ -1455,14 +1457,24 @@ static int fp_access_check_vector_hsd(DisasContext *s, bool is_q, MemOp esz) */ bool sve_access_check(DisasContext *s) { - if (s->pstate_sm || !dc_isar_feature(aa64_sve, s)) { + if (dc_isar_feature(aa64_sme, s)) { bool ret; - assert(dc_isar_feature(aa64_sme, s)); - ret = sme_sm_enabled_check(s); + if (s->pstate_sm) { + ret = sme_enabled_check(s); + } else if (dc_isar_feature(aa64_sve, s)) { + goto continue_sve; + } else { + ret = sme_sm_enabled_check(s); + } + if (ret) { + ret = nonstreaming_check(s); + } s->sve_access_checked = (ret ? 1 : -1); return ret; } + + continue_sve: if (s->sve_excp_el) { /* Assert that we only raise one exception per instruction. */ assert(!s->sve_access_checked); From c76ec8d575fb8194a59908d25828286702390903 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jul 2025 08:19:26 -0600 Subject: [PATCH 36/71] target/arm: Fix 128-bit element ZIP, UZP, TRN We missed the instructions UDEF when the vector size is too small. We missed marking the instructions non-streaming with SME. Cc: qemu-stable@nongnu.org Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20250704142112.1018902-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell (cherry picked from commit e6ffd009c7710a8cc98094897fa0af609c114683) Signed-off-by: Michael Tokarev --- target/arm/tcg/translate-sve.c | 43 ++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index d23be477b4..40d3a032d6 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -2352,6 +2352,23 @@ TRANS_FEAT(PUNPKHI, aa64_sve, do_perm_pred2, a, 1, gen_helper_sve_punpk_p) *** SVE Permute - Interleaving Group */ +static bool do_interleave_q(DisasContext *s, gen_helper_gvec_3 *fn, + arg_rrr_esz *a, int data) +{ + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + if (vsz < 32) { + unallocated_encoding(s); + } else { + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vsz, vsz, data, fn); + } + } + return true; +} + static gen_helper_gvec_3 * const zip_fns[4] = { gen_helper_sve_zip_b, gen_helper_sve_zip_h, gen_helper_sve_zip_s, gen_helper_sve_zip_d, @@ -2361,11 +2378,11 @@ TRANS_FEAT(ZIP1_z, aa64_sve, gen_gvec_ool_arg_zzz, TRANS_FEAT(ZIP2_z, aa64_sve, gen_gvec_ool_arg_zzz, zip_fns[a->esz], a, vec_full_reg_size(s) / 2) -TRANS_FEAT(ZIP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, - gen_helper_sve2_zip_q, a, 0) -TRANS_FEAT(ZIP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, - gen_helper_sve2_zip_q, a, - QEMU_ALIGN_DOWN(vec_full_reg_size(s), 32) / 2) +TRANS_FEAT_NONSTREAMING(ZIP1_q, aa64_sve_f64mm, do_interleave_q, + gen_helper_sve2_zip_q, a, 0) +TRANS_FEAT_NONSTREAMING(ZIP2_q, aa64_sve_f64mm, do_interleave_q, + gen_helper_sve2_zip_q, a, + QEMU_ALIGN_DOWN(vec_full_reg_size(s), 32) / 2) static gen_helper_gvec_3 * const uzp_fns[4] = { gen_helper_sve_uzp_b, gen_helper_sve_uzp_h, @@ -2377,10 +2394,10 @@ TRANS_FEAT(UZP1_z, aa64_sve, gen_gvec_ool_arg_zzz, TRANS_FEAT(UZP2_z, aa64_sve, gen_gvec_ool_arg_zzz, uzp_fns[a->esz], a, 1 << a->esz) -TRANS_FEAT(UZP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, - gen_helper_sve2_uzp_q, a, 0) -TRANS_FEAT(UZP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, - gen_helper_sve2_uzp_q, a, 16) +TRANS_FEAT_NONSTREAMING(UZP1_q, aa64_sve_f64mm, do_interleave_q, + gen_helper_sve2_uzp_q, a, 0) +TRANS_FEAT_NONSTREAMING(UZP2_q, aa64_sve_f64mm, do_interleave_q, + gen_helper_sve2_uzp_q, a, 16) static gen_helper_gvec_3 * const trn_fns[4] = { gen_helper_sve_trn_b, gen_helper_sve_trn_h, @@ -2392,10 +2409,10 @@ TRANS_FEAT(TRN1_z, aa64_sve, gen_gvec_ool_arg_zzz, TRANS_FEAT(TRN2_z, aa64_sve, gen_gvec_ool_arg_zzz, trn_fns[a->esz], a, 1 << a->esz) -TRANS_FEAT(TRN1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, - gen_helper_sve2_trn_q, a, 0) -TRANS_FEAT(TRN2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz, - gen_helper_sve2_trn_q, a, 16) +TRANS_FEAT_NONSTREAMING(TRN1_q, aa64_sve_f64mm, do_interleave_q, + gen_helper_sve2_trn_q, a, 0) +TRANS_FEAT_NONSTREAMING(TRN2_q, aa64_sve_f64mm, do_interleave_q, + gen_helper_sve2_trn_q, a, 16) /* *** SVE Permute Vector - Predicated Group From 9af1de0c4be21a37188af0a27b1b5c250004281c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jul 2025 08:19:30 -0600 Subject: [PATCH 37/71] target/arm: Fix PSEL size operands to tcg_gen_gvec_ands Gvec only operates on size 8 and multiples of 16. Predicates may be any multiple of 2. Round up the size using the appropriate function. Cc: qemu-stable@nongnu.org Fixes: 598ab0b24c0 ("target/arm: Implement PSEL") Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20250704142112.1018902-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell (cherry picked from commit 3801c5b75ffc60957265513338e8fd5f8b6ce8a1) Signed-off-by: Michael Tokarev --- target/arm/tcg/translate-sve.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index 40d3a032d6..b6fa0b67b1 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -7282,6 +7282,7 @@ static bool trans_PSEL(DisasContext *s, arg_psel *a) tcg_gen_neg_i64(tmp, tmp); /* Apply to either copy the source, or write zeros. */ + pl = size_for_gvec(pl); tcg_gen_gvec_ands(MO_64, pred_full_reg_offset(s, a->pd), pred_full_reg_offset(s, a->pn), tmp, pl, pl); return true; From 9a98db505f20d2e221ef086423483e028ed11937 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jul 2025 08:19:31 -0600 Subject: [PATCH 38/71] target/arm: Fix f16_dotadd vs nan selection Implement FPProcessNaNs4 within f16_dotadd, rather than simply letting NaNs propagate through the function. Cc: qemu-stable@nongnu.org Fixes: 3916841ac75 ("target/arm: Implement FMOPA, FMOPS (widening)") Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20250704142112.1018902-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell (cherry picked from commit cfc688c00ade84f6b32c7814b52c217f1d3b5eb1) Signed-off-by: Michael Tokarev --- target/arm/tcg/sme_helper.c | 62 +++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index dcc48e43db..a4992301b1 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -1005,25 +1005,55 @@ static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, * - we have pre-set-up copy of s_std which is set to round-to-odd, * for the multiply (see below) */ - float64 e1r = float16_to_float64(e1 & 0xffff, true, s_f16); - float64 e1c = float16_to_float64(e1 >> 16, true, s_f16); - float64 e2r = float16_to_float64(e2 & 0xffff, true, s_f16); - float64 e2c = float16_to_float64(e2 >> 16, true, s_f16); - float64 t64; + float16 h1r = e1 & 0xffff; + float16 h1c = e1 >> 16; + float16 h2r = e2 & 0xffff; + float16 h2c = e2 >> 16; float32 t32; - /* - * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. - */ - t64 = float64_mul(e1r, e2r, s_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std); + /* C.f. FPProcessNaNs4 */ + if (float16_is_any_nan(h1r) || float16_is_any_nan(h1c) || + float16_is_any_nan(h2r) || float16_is_any_nan(h2c)) { + float16 t16; - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, s_std); + if (float16_is_signaling_nan(h1r, s_f16)) { + t16 = h1r; + } else if (float16_is_signaling_nan(h1c, s_f16)) { + t16 = h1c; + } else if (float16_is_signaling_nan(h2r, s_f16)) { + t16 = h2r; + } else if (float16_is_signaling_nan(h2c, s_f16)) { + t16 = h2c; + } else if (float16_is_any_nan(h1r)) { + t16 = h1r; + } else if (float16_is_any_nan(h1c)) { + t16 = h1c; + } else if (float16_is_any_nan(h2r)) { + t16 = h2r; + } else { + t16 = h2c; + } + t32 = float16_to_float32(t16, true, s_f16); + } else { + float64 e1r = float16_to_float64(h1r, true, s_f16); + float64 e1c = float16_to_float64(h1c, true, s_f16); + float64 e2r = float16_to_float64(h2r, true, s_f16); + float64 e2c = float16_to_float64(h2c, true, s_f16); + float64 t64; + + /* + * The ARM pseudocode function FPDot performs both multiplies + * and the add with a single rounding operation. Emulate this + * by performing the first multiply in round-to-odd, then doing + * the second multiply as fused multiply-add, and rounding to + * float32 all in one step. + */ + t64 = float64_mul(e1r, e2r, s_odd); + t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std); + + /* This conversion is exact, because we've already rounded. */ + t32 = float64_to_float32(t64, s_std); + } /* The final accumulation step is not fused. */ return float32_add(sum, t32, s_std); From 005184da9d95f81ea6022e3f2e1dd95a881948be Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jul 2025 08:19:32 -0600 Subject: [PATCH 39/71] target/arm: Fix bfdotadd_ebf vs nan selection Implement FPProcessNaNs4 within bfdotadd_ebf, rather than simply letting NaNs propagate through the function. Cc: qemu-stable@nongnu.org Fixes: 0e1850182a1 ("target/arm: Implement FPCR.EBF=1 semantics for bfdotadd()") Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20250704142112.1018902-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell (cherry picked from commit bf020eaa6741711902a425016e2c7585f222562d) Signed-off-by: Michael Tokarev --- target/arm/tcg/vec_helper.c | 75 ++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index 986eaf8ffa..3b7f308803 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -2989,31 +2989,62 @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst, float_status *fpst_odd) { - /* - * Compare f16_dotadd() in sme_helper.c, but here we have - * bfloat16 inputs. In particular that means that we do not - * want the FPCR.FZ16 flush semantics, so we use the normal - * float_status for the input handling here. - */ - float64 e1r = float32_to_float64(e1 << 16, fpst); - float64 e1c = float32_to_float64(e1 & 0xffff0000u, fpst); - float64 e2r = float32_to_float64(e2 << 16, fpst); - float64 e2c = float32_to_float64(e2 & 0xffff0000u, fpst); - float64 t64; + float32 s1r = e1 << 16; + float32 s1c = e1 & 0xffff0000u; + float32 s2r = e2 << 16; + float32 s2c = e2 & 0xffff0000u; float32 t32; - /* - * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. - */ - t64 = float64_mul(e1r, e2r, fpst_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst); + /* C.f. FPProcessNaNs4 */ + if (float32_is_any_nan(s1r) || float32_is_any_nan(s1c) || + float32_is_any_nan(s2r) || float32_is_any_nan(s2c)) { + if (float32_is_signaling_nan(s1r, fpst)) { + t32 = s1r; + } else if (float32_is_signaling_nan(s1c, fpst)) { + t32 = s1c; + } else if (float32_is_signaling_nan(s2r, fpst)) { + t32 = s2r; + } else if (float32_is_signaling_nan(s2c, fpst)) { + t32 = s2c; + } else if (float32_is_any_nan(s1r)) { + t32 = s1r; + } else if (float32_is_any_nan(s1c)) { + t32 = s1c; + } else if (float32_is_any_nan(s2r)) { + t32 = s2r; + } else { + t32 = s2c; + } + /* + * FPConvertNaN(FPProcessNaN(t32)) will be done as part + * of the final addition below. + */ + } else { + /* + * Compare f16_dotadd() in sme_helper.c, but here we have + * bfloat16 inputs. In particular that means that we do not + * want the FPCR.FZ16 flush semantics, so we use the normal + * float_status for the input handling here. + */ + float64 e1r = float32_to_float64(s1r, fpst); + float64 e1c = float32_to_float64(s1c, fpst); + float64 e2r = float32_to_float64(s2r, fpst); + float64 e2c = float32_to_float64(s2c, fpst); + float64 t64; - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, fpst); + /* + * The ARM pseudocode function FPDot performs both multiplies + * and the add with a single rounding operation. Emulate this + * by performing the first multiply in round-to-odd, then doing + * the second multiply as fused multiply-add, and rounding to + * float32 all in one step. + */ + t64 = float64_mul(e1r, e2r, fpst_odd); + t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst); + + /* This conversion is exact, because we've already rounded. */ + t32 = float64_to_float32(t64, fpst); + } /* The final accumulation step is not fused. */ return float32_add(sum, t32, fpst); From cae6ddfd7e6297d728ab6678d69e721fc38d345d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Jun 2025 14:03:15 +0100 Subject: [PATCH 40/71] target/i386: fix TB exit logic in gen_movl_seg() when writing to SS Before commit e54ef98c8a ("target/i386: do not trigger IRQ shadow for LSS"), any write to SS in gen_movl_seg() would cause a TB exit. The changes introduced by this commit were intended to restrict the DISAS_EOB_INHIBIT_IRQ exit to the case where inhibit_irq is true, but missed that a DISAS_EOB_NEXT exit can still be required when writing to SS and inhibit_irq is false. Comparing the PE(s) && !VM86(s) section with the logic in x86_update_hflags(), we can see that the DISAS_EOB_NEXT exit is still required for the !CODE32 case when writing to SS in gen_movl_seg() because any change to the SS flags can affect hflags. Similarly we can see that the existing CODE32 case is still correct since a change to any of DS, ES and SS can affect hflags. Finally for the gen_op_movl_seg_real() case an explicit TB exit is not needed because the segment register selector does not affect hflags. Update the logic in gen_movl_seg() so that a write to SS with inhibit_irq set to false where PE(s) && !VM86(s) will generate a DISAS_EOB_NEXT exit along with the inline comment. This has the effect of allowing Win98SE to boot in QEMU once again. Signed-off-by: Mark Cave-Ayland Fixes: e54ef98c8a ("target/i386: do not trigger IRQ shadow for LSS") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2987 Link: https://lore.kernel.org/r/20250611130315.383151-1-mark.cave-ayland@ilande.co.uk Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini (cherry picked from commit 0f1d6606c28d0ae81a1b311972c5c54e5e867bf0) Fixes: 0f1d6606c2 ("target/i386: do not trigger IRQ shadow for LSS" in 10.0.x) Signed-off-by: Michael Tokarev --- target/i386/tcg/translate.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 50cf56175f..7e590ef79c 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2000,8 +2000,11 @@ static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src, bool inhibit tcg_gen_trunc_tl_i32(sel, src); gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel); - /* For move to DS/ES/SS, the addseg or ss32 flags may change. */ - if (CODE32(s) && seg_reg < R_FS) { + /* + * For moves to SS, the SS32 flag may change. For CODE32 only, changes + * to SS, DS and ES may change the ADDSEG flags. + */ + if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) { s->base.is_jmp = DISAS_EOB_NEXT; } } else { From fe000c4648b37782f4981fc386fec670304404a9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 4 Jul 2025 17:56:36 +0100 Subject: [PATCH 41/71] target/arm: Don't enforce NSE,NS check for EL3->EL3 returns In the Arm ARM, rule R_TYTWB that defines illegal exception return cases includes the case: If FEAT_RME is implemented, then if SCR_EL3.{NSE, NS} is {1, 0}, an exception return from EL3 to a lower Exception level Our implementation of this check fails to check that the return is to a lower exception level, so it will incorrectly fire on EL3->EL3 exception returns. Fix the check condition. This requires us to move it further down in the function to a point where we know the new_el value. Fixes: 35aa6715ddcd9 ("target/arm: Catch illegal-exception-return from EL3 with bad NSE/NS") Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3016 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20250704165636.261888-1-peter.maydell@linaro.org (cherry picked from commit c563cd7e61d074f58eef413322144461dd243716) Signed-off-by: Michael Tokarev --- target/arm/tcg/helper-a64.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 9244848efe..be0935d194 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -653,15 +653,6 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) spsr &= ~PSTATE_SS; } - /* - * FEAT_RME forbids return from EL3 with an invalid security state. - * We don't need an explicit check for FEAT_RME here because we enforce - * in scr_write() that you can't set the NSE bit without it. - */ - if (cur_el == 3 && (env->cp15.scr_el3 & (SCR_NS | SCR_NSE)) == SCR_NSE) { - goto illegal_return; - } - new_el = el_from_spsr(spsr); if (new_el == -1) { goto illegal_return; @@ -673,6 +664,17 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) goto illegal_return; } + /* + * FEAT_RME forbids return from EL3 to a lower exception level + * with an invalid security state. + * We don't need an explicit check for FEAT_RME here because we enforce + * in scr_write() that you can't set the NSE bit without it. + */ + if (cur_el == 3 && new_el < 3 && + (env->cp15.scr_el3 & (SCR_NS | SCR_NSE)) == SCR_NSE) { + goto illegal_return; + } + if (new_el != 0 && arm_el_is_aa64(env, new_el) != return_to_aa64) { /* Return to an EL which is configured for a different register width */ goto illegal_return; From 676bc0f4a726627598e6f1d5979ee863191b54ba Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sun, 29 Jun 2025 22:48:50 +0200 Subject: [PATCH 42/71] hw/arm/fsl-imx8mp: Wire VIRQ and VFIQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows to run KVM guests inside the imx8mp-evk machine. Fixes: a4eefc69b237 ("hw/arm: Add i.MX 8M Plus EVK board") CC: qemu-stable Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell (cherry picked from commit 930180f3b9a292639eb894f1ca846683834ed4b7) Signed-off-by: Michael Tokarev --- hw/arm/fsl-imx8mp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c index 82edf61082..d775aa934a 100644 --- a/hw/arm/fsl-imx8mp.c +++ b/hw/arm/fsl-imx8mp.c @@ -356,6 +356,10 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); sysbus_connect_irq(gicsbd, i + ms->smp.cpus, qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); + sysbus_connect_irq(gicsbd, i + 2 * ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); + sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); } } From 1714828a56f150327cc05b242cabba4c3f891677 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 10 Jul 2025 12:31:23 +0100 Subject: [PATCH 43/71] linux-user: Implement fchmodat2 syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fchmodat2 syscall is new from Linux 6.6; it is like the existing fchmodat syscall except that it takes a flags parameter. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3019 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250710113123.1109461-1-peter.maydell@linaro.org> (cherry picked from commit 6a3e132a1be8c9e649967a4eb341d00731be7f51) Signed-off-by: Michael Tokarev --- linux-user/syscall.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8bfe4912e1..9b397bac7e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -789,6 +789,10 @@ safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff, int, outfd, loff_t *, poutoff, size_t, length, unsigned int, flags) #endif +#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2) +safe_syscall4(int, fchmodat2, int, dfd, const char *, filename, + unsigned short, mode, unsigned int, flags) +#endif /* We do ioctl like this rather than via safe_syscall3 to preserve the * "third argument might be integer or pointer or not present" behaviour of @@ -10709,6 +10713,15 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, ret = get_errno(fchmodat(arg1, p, arg3, 0)); unlock_user(p, arg2, 0); return ret; +#endif +#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2) + case TARGET_NR_fchmodat2: + if (!(p = lock_user_string(arg2))) { + return -TARGET_EFAULT; + } + ret = get_errno(safe_fchmodat2(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); + return ret; #endif case TARGET_NR_getpriority: /* Note that negative values are valid for getpriority, so we must From 1759558915c5052f560737061ca6333a16a924f5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 10 Jul 2025 17:43:54 +0100 Subject: [PATCH 44/71] linux-user: Check for EFAULT failure in nanosleep target_to_host_timespec() returns an error if the memory the guest passed us isn't actually readable. We check for this everywhere except the callsite in the TARGET_NR_nanosleep case, so this mistake was caught by a Coverity heuristic. Add the missing error checks to the calls that convert between the host and target timespec structs. Coverity: CID 1507104 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250710164355.1296648-1-peter.maydell@linaro.org> (cherry picked from commit c4828cb8502d0b2adc39b9cde93df7d2886df897) Signed-off-by: Michael Tokarev --- linux-user/syscall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9b397bac7e..a8eea5dd52 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11639,10 +11639,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, case TARGET_NR_nanosleep: { struct timespec req, rem; - target_to_host_timespec(&req, arg1); + if (target_to_host_timespec(&req, arg1)) { + return -TARGET_EFAULT; + } ret = get_errno(safe_nanosleep(&req, &rem)); if (is_error(ret) && arg2) { - host_to_target_timespec(arg2, &rem); + if (host_to_target_timespec(arg2, &rem)) { + return -TARGET_EFAULT; + } } } return ret; From a4e31f5d8ec90a16a250fc39d807f79ce9d99760 Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Fri, 14 Mar 2025 08:47:42 -0400 Subject: [PATCH 45/71] linux-user: Hold the fd-trans lock across fork If another thread is holding target_fd_trans_lock during a fork, then the lock becomes permanently locked in the child and the emulator deadlocks at the next interaction with the fd-trans table. As with other locks, acquire the lock in fork_start() and release it in fork_end(). Cc: qemu-stable@nongnu.org Signed-off-by: Geoffrey Thomas Fixes: c093364f4d91 "fd-trans: Fix race condition on reallocation of the translation table." Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2846 Buglink: https://github.com/astral-sh/uv/issues/6105 Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250314124742.4965-1-geofft@ldpreload.com> (cherry picked from commit e4e839b2eeea5745c48ce47144c7842eb7cd455f) Signed-off-by: Michael Tokarev --- linux-user/fd-trans.h | 10 ++++++++++ linux-user/main.c | 2 ++ 2 files changed, 12 insertions(+) diff --git a/linux-user/fd-trans.h b/linux-user/fd-trans.h index 910faaf237..e14f96059c 100644 --- a/linux-user/fd-trans.h +++ b/linux-user/fd-trans.h @@ -36,6 +36,16 @@ static inline void fd_trans_init(void) qemu_mutex_init(&target_fd_trans_lock); } +static inline void fd_trans_prefork(void) +{ + qemu_mutex_lock(&target_fd_trans_lock); +} + +static inline void fd_trans_postfork(void) +{ + qemu_mutex_unlock(&target_fd_trans_lock); +} + static inline TargetFdDataFunc fd_trans_target_to_host_data(int fd) { if (fd < 0) { diff --git a/linux-user/main.c b/linux-user/main.c index e2ec5970be..2cd867491b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -149,12 +149,14 @@ void fork_start(void) cpu_list_lock(); qemu_plugin_user_prefork_lock(); gdbserver_fork_start(); + fd_trans_prefork(); } void fork_end(pid_t pid) { bool child = pid == 0; + fd_trans_postfork(); qemu_plugin_user_postfork(child); mmap_fork_end(child); if (child) { From b4ead907261c0a7228e43feb087c3b543da3620f Mon Sep 17 00:00:00 2001 From: "Chaney, Ben" Date: Mon, 16 Jun 2025 20:56:50 +0000 Subject: [PATCH 46/71] migration: Don't sync volatile memory after migration completes Syncing volatile memory provides no benefit, instead it can cause performance issues in some cases. Only sync memory that is marked as non-volatile after migration completes on destination. Signed-off-by: Ben Chaney Fixes: bd108a44bc29 (migration: ram: Switch to ram block writeback) Link: https://lore.kernel.org/r/1CC43F59-336F-4A12-84AD-DB89E0A17A95@akamai.com Signed-off-by: Peter Xu (cherry picked from commit 983899eab4939dc4dff67fa4d822c5b4df7eae21) Signed-off-by: Michael Tokarev --- migration/ram.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index 424df6d9f1..a0784d99b2 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3598,7 +3598,9 @@ static int ram_load_cleanup(void *opaque) RAMBlock *rb; RAMBLOCK_FOREACH_NOT_IGNORED(rb) { - qemu_ram_block_writeback(rb); + if (memory_region_is_nonvolatile(rb->mr)) { + qemu_ram_block_writeback(rb); + } } xbzrle_load_cleanup(); From c49db93c360762587daf67a274a17749bc60ebe1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 11 Jul 2025 15:12:17 +0100 Subject: [PATCH 47/71] linux-user: Use qemu_set_cloexec() to mark pidfd as FD_CLOEXEC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the linux-user do_fork() function we try to set the FD_CLOEXEC flag on a pidfd like this: fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL) | FD_CLOEXEC); This has two problems: (1) it doesn't check errors, which Coverity complains about (2) we use F_GETFL when we mean F_GETFD Deal with both of these problems by using qemu_set_cloexec() instead. That function will assert() if the fcntls fail, which is fine (we are inside fork_start()/fork_end() so we know nothing can mess around with our file descriptors here, and we just got this one from pidfd_open()). (As we are touching the if() statement here, we correct the indentation.) Coverity: CID 1508111 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Daniel P. Berrangé Signed-off-by: Richard Henderson Message-ID: <20250711141217.1429412-1-peter.maydell@linaro.org> (cherry picked from commit d6390204c61e148488f034d1f79be35cd3318d93) Signed-off-by: Michael Tokarev --- linux-user/syscall.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a8eea5dd52..3a25abfaca 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6746,10 +6746,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, int pid_child = ret; pid_fd = pidfd_open(pid_child, 0); if (pid_fd >= 0) { - fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL) - | FD_CLOEXEC); + qemu_set_cloexec(pid_fd); } else { - pid_fd = 0; + pid_fd = 0; } #endif put_user_u32(pid_fd, parent_tidptr); From a655b6548fe2196031a3f325c5a4df7df65ff4cd Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 2 Jul 2025 08:03:19 +0200 Subject: [PATCH 48/71] accel/kvm: Adjust the note about the minimum required kernel version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 126e7f78036 ("kvm: require KVM_CAP_IOEVENTFD and KVM_CAP_IOEVENTFD_ANY_LENGTH") we require at least kernel 4.5 to be able to use KVM. Adjust the upgrade_note accordingly. While we're at it, remove the text about kvm-kmod and the SourceForge URL since this is not actively maintained anymore. Fixes: 126e7f78036 ("kvm: require KVM_CAP_IOEVENTFD and KVM_CAP_IOEVENTFD_ANY_LENGTH") Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev (cherry picked from commit f180e367fce44b336105a11a62edf9610b6b2a06) --- accel/kvm/kvm-all.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 951e8214e0..d6002b631e 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2556,8 +2556,7 @@ static int kvm_init(MachineState *ms) { MachineClass *mc = MACHINE_GET_CLASS(ms); static const char upgrade_note[] = - "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n" - "(see http://sourceforge.net/projects/kvm).\n"; + "Please upgrade to at least kernel 4.5.\n"; const struct { const char *name; int num; From 6624ff39720c954081706822da15bc806ea4c318 Mon Sep 17 00:00:00 2001 From: Anastasia Belova Date: Mon, 2 Jun 2025 11:57:17 +0300 Subject: [PATCH 49/71] net: fix buffer overflow in af_xdp_umem_create() s->pool has n_descs elements so maximum i should be n_descs - 1. Fix the upper bound. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: cb039ef3d9 ("net: add initial support for AF_XDP network backend") Cc: qemu-stable@nongnu.org Reviewed-by: Ilya Maximets Signed-off-by: Anastasia Belova Signed-off-by: Jason Wang (cherry picked from commit 110d0fa2d4d1f754242f6775baec43776a9adb35) Signed-off-by: Michael Tokarev --- net/af-xdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/af-xdp.c b/net/af-xdp.c index 01c5fb914e..d022534d76 100644 --- a/net/af-xdp.c +++ b/net/af-xdp.c @@ -323,7 +323,7 @@ static int af_xdp_umem_create(AFXDPState *s, int sock_fd, Error **errp) s->pool = g_new(uint64_t, n_descs); /* Fill the pool in the opposite order, because it's a LIFO queue. */ - for (i = n_descs; i >= 0; i--) { + for (i = n_descs - 1; i >= 0; i--) { s->pool[i] = i * XSK_UMEM__DEFAULT_FRAME_SIZE; } s->n_pool = n_descs; From f272f318c02a4e41a91f1c87d677c44427a2ed89 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 30 May 2025 14:18:53 +0900 Subject: [PATCH 50/71] virtio-net: Add queues for RSS during migration virtio_net_pre_load_queues() inspects vdev->guest_features to tell if VIRTIO_NET_F_RSS or VIRTIO_NET_F_MQ is enabled to infer the required number of queues. This works for VIRTIO_NET_F_MQ but it doesn't for VIRTIO_NET_F_RSS because only the lowest 32 bits of vdev->guest_features is set at the point and VIRTIO_NET_F_RSS uses bit 60 while VIRTIO_NET_F_MQ uses bit 22. Instead of inferring the required number of queues from vdev->guest_features, use the number loaded from the vm state. This change also has a nice side effect to remove a duplicate peer queue pair change by circumventing virtio_net_set_multiqueue(). Also update the comment in include/hw/virtio/virtio.h to prevent an implementation of pre_load_queues() from refering to any fields being loaded during migration by accident in the future. Fixes: 8c49756825da ("virtio-net: Add only one queue pair when realizing") Tested-by: Lei Yang Cc: qemu-stable@nongnu.org Signed-off-by: Akihiko Odaki Signed-off-by: Jason Wang (cherry picked from commit adda0ad56bd28d5a809051cbd190fda5798ec4e4) Signed-off-by: Michael Tokarev --- hw/net/virtio-net.c | 11 ++++------- hw/virtio/virtio.c | 14 +++++++------- include/hw/virtio/virtio.h | 10 ++++++++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index bd37651dab..5f908e5bca 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -3021,11 +3021,10 @@ static void virtio_net_del_queue(VirtIONet *n, int index) virtio_del_queue(vdev, index * 2 + 1); } -static void virtio_net_change_num_queue_pairs(VirtIONet *n, int new_max_queue_pairs) +static void virtio_net_change_num_queues(VirtIONet *n, int new_num_queues) { VirtIODevice *vdev = VIRTIO_DEVICE(n); int old_num_queues = virtio_get_num_queues(vdev); - int new_num_queues = new_max_queue_pairs * 2 + 1; int i; assert(old_num_queues >= 3); @@ -3061,16 +3060,14 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) int max = multiqueue ? n->max_queue_pairs : 1; n->multiqueue = multiqueue; - virtio_net_change_num_queue_pairs(n, max); + virtio_net_change_num_queues(n, max * 2 + 1); virtio_net_set_queue_pairs(n); } -static int virtio_net_pre_load_queues(VirtIODevice *vdev) +static int virtio_net_pre_load_queues(VirtIODevice *vdev, uint32_t n) { - virtio_net_set_multiqueue(VIRTIO_NET(vdev), - virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_RSS) || - virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MQ)); + virtio_net_change_num_queues(VIRTIO_NET(vdev), n); return 0; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 755260981e..ec54573feb 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3257,13 +3257,6 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) config_len--; } - if (vdc->pre_load_queues) { - ret = vdc->pre_load_queues(vdev); - if (ret) { - return ret; - } - } - num = qemu_get_be32(f); if (num > VIRTIO_QUEUE_MAX) { @@ -3271,6 +3264,13 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) return -1; } + if (vdc->pre_load_queues) { + ret = vdc->pre_load_queues(vdev, num); + if (ret) { + return ret; + } + } + for (i = 0; i < num; i++) { vdev->vq[i].vring.num = qemu_get_be32(f); if (k->has_variable_vring_alignment) { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 6386910280..14c2afed33 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -210,8 +210,14 @@ struct VirtioDeviceClass { void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); int (*start_ioeventfd)(VirtIODevice *vdev); void (*stop_ioeventfd)(VirtIODevice *vdev); - /* Called before loading queues. Useful to add queues before loading. */ - int (*pre_load_queues)(VirtIODevice *vdev); + /* + * Called before loading queues. + * If the number of queues change at runtime, use @n to know the + * number and add or remove queues accordingly. + * Note that this function is called in the middle of loading vmsd; + * no assumption should be made on states being loaded from vmsd. + */ + int (*pre_load_queues)(VirtIODevice *vdev, uint32_t n); /* Saving and loading of a device; trying to deprecate save/load * use vmsd for new devices. */ From 10a9eedc2049ae977aadd77c973ef4f8522b01a2 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:20 +0000 Subject: [PATCH 51/71] amd_iommu: Fix Miscellaneous Information Register 0 encoding The definitions encoding the maximum Virtual, Physical, and Guest Virtual Address sizes supported by the IOMMU are using incorrect offsets i.e. the VASize and GVASize offsets are switched. The value in the GVAsize field is also modified, since it was incorrectly encoded. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Co-developed-by: Ethan MILON Signed-off-by: Ethan MILON Signed-off-by: Alejandro Jimenez Message-Id: <20250617150427.20585-2-alejandro.j.jimenez@oracle.com> Reviewed-by: Vasant Hegde Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 091c7d7924f33781c2fb8e7297dc54971e0c3785) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 28125130c6..921f7e1a4f 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -196,9 +196,9 @@ #define AMDVI_PAGE_SHIFT_4K 12 #define AMDVI_PAGE_MASK_4K (~((1ULL << AMDVI_PAGE_SHIFT_4K) - 1)) -#define AMDVI_MAX_VA_ADDR (48UL << 5) -#define AMDVI_MAX_PH_ADDR (40UL << 8) -#define AMDVI_MAX_GVA_ADDR (48UL << 15) +#define AMDVI_MAX_GVA_ADDR (2UL << 5) +#define AMDVI_MAX_PH_ADDR (40UL << 8) +#define AMDVI_MAX_VA_ADDR (48UL << 15) /* Completion Wait data size */ #define AMDVI_COMPLETION_DATA_SIZE 8 From 1ca9d2e0c2916174e50e6dd9fdce783ff1f33bdb Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:21 +0000 Subject: [PATCH 52/71] amd_iommu: Fix Device ID decoding for INVALIDATE_IOTLB_PAGES command The DeviceID bits are extracted using an incorrect offset in the call to amdvi_iotlb_remove_page(). This field is read (correctly) earlier, so use the value already retrieved for devid. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-3-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit c63b8d1425ba8b3b08ee4f7346457fd8a7f12a24) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index af85706b8a..de55074b21 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -508,7 +508,7 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd) static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd) { - uint16_t devid = extract64(cmd[0], 0, 16); + uint16_t devid = cpu_to_le16(extract64(cmd[0], 0, 16)); if (extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 1) || extract64(cmd[1], 6, 6)) { amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), @@ -521,7 +521,7 @@ static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd) &devid); } else { amdvi_iotlb_remove_page(s, cpu_to_le64(extract64(cmd[1], 12, 52)) << 12, - cpu_to_le16(extract64(cmd[1], 0, 16))); + devid); } trace_amdvi_iotlb_inval(); } From d1ea4a1b0effc5f6658688bc7a5c17a245b78fb5 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:22 +0000 Subject: [PATCH 53/71] amd_iommu: Update bitmasks representing DTE reserved fields The DTE validation method verifies that all bits in reserved DTE fields are unset. Update them according to the latest definition available in AMD I/O Virtualization Technology (IOMMU) Specification - Section 2.2.2.1 Device Table Entry Format. Remove the magic numbers and use a macro helper to generate bitmasks covering the specified ranges for better legibility. Note that some reserved fields specify that events are generated when they contain non-zero bits, or checks are skipped under certain configurations. This change only updates the reserved masks, checks for special conditions are not yet implemented. Cc: qemu-stable@nongnu.org Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-4-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit ff3dcb3bf652912466dcc1cd10d3267f185c212e) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.c | 7 ++++--- hw/i386/amd_iommu.h | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index de55074b21..69d69a9b2d 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -848,9 +848,10 @@ static inline uint64_t amdvi_get_perms(uint64_t entry) static bool amdvi_validate_dte(AMDVIState *s, uint16_t devid, uint64_t *dte) { - if ((dte[0] & AMDVI_DTE_LOWER_QUAD_RESERVED) - || (dte[1] & AMDVI_DTE_MIDDLE_QUAD_RESERVED) - || (dte[2] & AMDVI_DTE_UPPER_QUAD_RESERVED) || dte[3]) { + if ((dte[0] & AMDVI_DTE_QUAD0_RESERVED) || + (dte[1] & AMDVI_DTE_QUAD1_RESERVED) || + (dte[2] & AMDVI_DTE_QUAD2_RESERVED) || + (dte[3] & AMDVI_DTE_QUAD3_RESERVED)) { amdvi_log_illegaldevtab_error(s, devid, s->devtab + devid * AMDVI_DEVTAB_ENTRY_SIZE, 0); diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 921f7e1a4f..60af62bef6 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -25,6 +25,8 @@ #include "hw/i386/x86-iommu.h" #include "qom/object.h" +#define GENMASK64(h, l) (((~0ULL) >> (63 - (h) + (l))) << (l)) + /* Capability registers */ #define AMDVI_CAPAB_BAR_LOW 0x04 #define AMDVI_CAPAB_BAR_HIGH 0x08 @@ -162,9 +164,10 @@ #define AMDVI_FEATURE_PC (1ULL << 9) /* Perf counters */ /* reserved DTE bits */ -#define AMDVI_DTE_LOWER_QUAD_RESERVED 0x80300000000000fc -#define AMDVI_DTE_MIDDLE_QUAD_RESERVED 0x0000000000000100 -#define AMDVI_DTE_UPPER_QUAD_RESERVED 0x08f0000000000000 +#define AMDVI_DTE_QUAD0_RESERVED (GENMASK64(6, 2) | GENMASK64(63, 63)) +#define AMDVI_DTE_QUAD1_RESERVED 0 +#define AMDVI_DTE_QUAD2_RESERVED GENMASK64(53, 52) +#define AMDVI_DTE_QUAD3_RESERVED (GENMASK64(14, 0) | GENMASK64(53, 48)) /* AMDVI paging mode */ #define AMDVI_GATS_MODE (2ULL << 12) From caaa64850876a71c46ba0a3c9f5925e8cc49c600 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:23 +0000 Subject: [PATCH 54/71] amd_iommu: Fix masks for various IOMMU MMIO Registers Address various issues with definitions of the MMIO registers e.g. for the Device Table Address Register, the size mask currently encompasses reserved bits [11:9], so change it to only extract the bits [8:0] encoding size. Convert masks to use GENMASK64 for consistency, and make unrelated definitions independent. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-5-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 108e10ff69099c3ebe147f505246be7c2ad2a499) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 60af62bef6..ef8dc726f1 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -68,34 +68,34 @@ #define AMDVI_MMIO_SIZE 0x4000 -#define AMDVI_MMIO_DEVTAB_SIZE_MASK ((1ULL << 12) - 1) -#define AMDVI_MMIO_DEVTAB_BASE_MASK (((1ULL << 52) - 1) & ~ \ - AMDVI_MMIO_DEVTAB_SIZE_MASK) +#define AMDVI_MMIO_DEVTAB_SIZE_MASK GENMASK64(8, 0) +#define AMDVI_MMIO_DEVTAB_BASE_MASK GENMASK64(51, 12) + #define AMDVI_MMIO_DEVTAB_ENTRY_SIZE 32 #define AMDVI_MMIO_DEVTAB_SIZE_UNIT 4096 /* some of this are similar but just for readability */ #define AMDVI_MMIO_CMDBUF_SIZE_BYTE (AMDVI_MMIO_COMMAND_BASE + 7) #define AMDVI_MMIO_CMDBUF_SIZE_MASK 0x0f -#define AMDVI_MMIO_CMDBUF_BASE_MASK AMDVI_MMIO_DEVTAB_BASE_MASK -#define AMDVI_MMIO_CMDBUF_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f) -#define AMDVI_MMIO_CMDBUF_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK +#define AMDVI_MMIO_CMDBUF_BASE_MASK GENMASK64(51, 12) +#define AMDVI_MMIO_CMDBUF_HEAD_MASK GENMASK64(18, 4) +#define AMDVI_MMIO_CMDBUF_TAIL_MASK GENMASK64(18, 4) #define AMDVI_MMIO_EVTLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7) -#define AMDVI_MMIO_EVTLOG_SIZE_MASK AMDVI_MMIO_CMDBUF_SIZE_MASK -#define AMDVI_MMIO_EVTLOG_BASE_MASK AMDVI_MMIO_CMDBUF_BASE_MASK -#define AMDVI_MMIO_EVTLOG_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f) -#define AMDVI_MMIO_EVTLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK +#define AMDVI_MMIO_EVTLOG_SIZE_MASK 0x0f +#define AMDVI_MMIO_EVTLOG_BASE_MASK GENMASK64(51, 12) +#define AMDVI_MMIO_EVTLOG_HEAD_MASK GENMASK64(18, 4) +#define AMDVI_MMIO_EVTLOG_TAIL_MASK GENMASK64(18, 4) -#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7) -#define AMDVI_MMIO_PPRLOG_HEAD_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK -#define AMDVI_MMIO_PPRLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK -#define AMDVI_MMIO_PPRLOG_BASE_MASK AMDVI_MMIO_EVTLOG_BASE_MASK -#define AMDVI_MMIO_PPRLOG_SIZE_MASK AMDVI_MMIO_EVTLOG_SIZE_MASK +#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_PPR_BASE + 7) +#define AMDVI_MMIO_PPRLOG_SIZE_MASK 0x0f +#define AMDVI_MMIO_PPRLOG_BASE_MASK GENMASK64(51, 12) +#define AMDVI_MMIO_PPRLOG_HEAD_MASK GENMASK64(18, 4) +#define AMDVI_MMIO_PPRLOG_TAIL_MASK GENMASK64(18, 4) #define AMDVI_MMIO_EXCL_ENABLED_MASK (1ULL << 0) #define AMDVI_MMIO_EXCL_ALLOW_MASK (1ULL << 1) -#define AMDVI_MMIO_EXCL_LIMIT_MASK AMDVI_MMIO_DEVTAB_BASE_MASK +#define AMDVI_MMIO_EXCL_LIMIT_MASK GENMASK64(51, 12) #define AMDVI_MMIO_EXCL_LIMIT_LOW 0xfff /* mmio control register flags */ @@ -132,14 +132,14 @@ #define AMDVI_DEV_TRANSLATION_VALID (1ULL << 1) #define AMDVI_DEV_MODE_MASK 0x7 #define AMDVI_DEV_MODE_RSHIFT 9 -#define AMDVI_DEV_PT_ROOT_MASK 0xffffffffff000 +#define AMDVI_DEV_PT_ROOT_MASK GENMASK64(51, 12) #define AMDVI_DEV_PT_ROOT_RSHIFT 12 #define AMDVI_DEV_PERM_SHIFT 61 #define AMDVI_DEV_PERM_READ (1ULL << 61) #define AMDVI_DEV_PERM_WRITE (1ULL << 62) /* Device table entry bits 64:127 */ -#define AMDVI_DEV_DOMID_ID_MASK ((1ULL << 16) - 1) +#define AMDVI_DEV_DOMID_ID_MASK GENMASK64(15, 0) /* Event codes and flags, as stored in the info field */ #define AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY (0x1U << 12) @@ -197,7 +197,7 @@ #define AMDVI_PAGE_SIZE (1ULL << AMDVI_PAGE_SHIFT) #define AMDVI_PAGE_SHIFT_4K 12 -#define AMDVI_PAGE_MASK_4K (~((1ULL << AMDVI_PAGE_SHIFT_4K) - 1)) +#define AMDVI_PAGE_MASK_4K GENMASK64(63, 12) #define AMDVI_MAX_GVA_ADDR (2UL << 5) #define AMDVI_MAX_PH_ADDR (40UL << 8) From 18e70a46c3171feac4f80a6a3d4748a519160616 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:24 +0000 Subject: [PATCH 55/71] amd_iommu: Fix mask to retrieve Interrupt Table Root Pointer from DTE Fix an off-by-one error in the definition of AMDVI_IR_PHYS_ADDR_MASK. The current definition masks off the most significant bit of the Interrupt Table Root ptr i.e. it only generates a mask with bits [50:6] set. See the AMD I/O Virtualization Technology (IOMMU) Specification for the Interrupt Table Root Pointer[51:6] field in the Device Table Entry format. Cc: qemu-stable@nongnu.org Fixes: b44159fe0078 ("x86_iommu/amd: Add interrupt remap support when VAPIC is not enabled") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-6-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 123cf4bdd378f746dfa2f5415ba084148dded3e3) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index ef8dc726f1..2e390f808d 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -231,7 +231,7 @@ #define AMDVI_IR_INTCTL_PASS 1 #define AMDVI_IR_INTCTL_REMAP 2 -#define AMDVI_IR_PHYS_ADDR_MASK (((1ULL << 45) - 1) << 6) +#define AMDVI_IR_PHYS_ADDR_MASK GENMASK64(51, 6) /* MSI data 10:0 bits (section 2.2.5.1 Fig 14) */ #define AMDVI_IRTE_OFFSET 0x7ff From 90c635c926c13187aa13575af489dd76de737341 Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:25 +0000 Subject: [PATCH 56/71] amd_iommu: Fix the calculation for Device Table size Correctly calculate the Device Table size using the format encoded in the Device Table Base Address Register (MMIO Offset 0000h). Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-7-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 67d3077ee403472d45794399e97c9f329242fce9) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 69d69a9b2d..06df344575 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -665,8 +665,8 @@ static inline void amdvi_handle_devtab_write(AMDVIState *s) uint64_t val = amdvi_readq(s, AMDVI_MMIO_DEVICE_TABLE); s->devtab = (val & AMDVI_MMIO_DEVTAB_BASE_MASK); - /* set device table length */ - s->devtab_len = ((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1 * + /* set device table length (i.e. number of entries table can hold) */ + s->devtab_len = (((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1) * (AMDVI_MMIO_DEVTAB_SIZE_UNIT / AMDVI_MMIO_DEVTAB_ENTRY_SIZE)); } From fc1ad5124f5407437d0720fc51db6d88013add1a Mon Sep 17 00:00:00 2001 From: Alejandro Jimenez Date: Tue, 17 Jun 2025 15:04:26 +0000 Subject: [PATCH 57/71] amd_iommu: Remove duplicated definitions No functional change. Signed-off-by: Alejandro Jimenez Reviewed-by: Vasant Hegde Message-Id: <20250617150427.20585-8-alejandro.j.jimenez@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 5959b641c98b5ae9677e2c1d89902dac31b344d9) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 2e390f808d..04e3ad072e 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -206,10 +206,6 @@ /* Completion Wait data size */ #define AMDVI_COMPLETION_DATA_SIZE 8 -#define AMDVI_COMMAND_SIZE 16 -/* Completion Wait data size */ -#define AMDVI_COMPLETION_DATA_SIZE 8 - #define AMDVI_COMMAND_SIZE 16 #define AMDVI_INT_ADDR_FIRST 0xfee00000 From 787a817cd5691802d9ad69aa1bd969df615b47a9 Mon Sep 17 00:00:00 2001 From: Ethan Milon Date: Tue, 17 Jun 2025 15:04:27 +0000 Subject: [PATCH 58/71] amd_iommu: Fix truncation of oldval in amdvi_writeq The variable `oldval` was incorrectly declared as a 32-bit `uint32_t`. This could lead to truncation and incorrect behavior where the upper read-only 32 bits are significant. Fix the type of `oldval` to match the return type of `ldq_le_p()`. Cc: qemu-stable@nongnu.org Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU") Signed-off-by: Ethan Milon Message-Id: <20250617150427.20585-9-alejandro.j.jimenez@oracle.com> Reviewed-by: Vasant Hegde Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 5788929e05e18ed5f76dc8ade4210f022c9ba5a1) Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 06df344575..f773653487 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -140,7 +140,7 @@ static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val) { uint64_t romask = ldq_le_p(&s->romask[addr]); uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]); - uint32_t oldval = ldq_le_p(&s->mmior[addr]); + uint64_t oldval = ldq_le_p(&s->mmior[addr]); stq_le_p(&s->mmior[addr], ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask)); } From e50ca171e2889ef2653bbf566caf9263ed3b970a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 25 Jun 2025 10:50:19 +0200 Subject: [PATCH 59/71] file-posix: Fix aio=threads performance regression after enablign FUA For aio=threads, we're currently not implementing REQ_FUA in any useful way, but just do a separate raw_co_flush_to_disk() call. This changes behaviour compared to the old state, which used bdrv_co_flush() with its optimisations. As a quick fix, call bdrv_co_flush() again like before. Eventually, we can use pwritev2() to make use of RWF_DSYNC if available, but we'll still have to keep this code path as a fallback, so this fix is required either way. While the fix itself is a one-liner, some new graph locking annotations are needed to convince TSA that the locking is correct. Cc: qemu-stable@nongnu.org Fixes: 984a32f17e8d ("file-posix: Support FUA writes") Buglink: https://issues.redhat.com/browse/RHEL-96854 Reported-by: Tingting Mao Signed-off-by: Kevin Wolf Message-ID: <20250625085019.27735-1-kwolf@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf (cherry picked from commit d402da1360c2240e81f0e5fc80ddbfc6238e0da8) Signed-off-by: Michael Tokarev --- block/file-posix.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 56d1972d15..796553bafd 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2484,9 +2484,9 @@ static inline bool raw_check_linux_aio(BDRVRawState *s) } #endif -static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, - uint64_t bytes, QEMUIOVector *qiov, int type, - int flags) +static int coroutine_fn GRAPH_RDLOCK +raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, uint64_t bytes, + QEMUIOVector *qiov, int type, int flags) { BDRVRawState *s = bs->opaque; RawPosixAIOData acb; @@ -2545,7 +2545,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, ret = raw_thread_pool_submit(handle_aiocb_rw, &acb); if (ret == 0 && (flags & BDRV_REQ_FUA)) { /* TODO Use pwritev2() instead if it's available */ - ret = raw_co_flush_to_disk(bs); + ret = bdrv_co_flush(bs); } goto out; /* Avoid the compiler err of unused label */ @@ -2580,16 +2580,16 @@ out: return ret; } -static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, - int64_t bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +static int coroutine_fn GRAPH_RDLOCK +raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, + QEMUIOVector *qiov, BdrvRequestFlags flags) { return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_READ, flags); } -static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, - int64_t bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +static int coroutine_fn GRAPH_RDLOCK +raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, + QEMUIOVector *qiov, BdrvRequestFlags flags) { return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_WRITE, flags); } @@ -3525,10 +3525,11 @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op, #endif #if defined(CONFIG_BLKZONED) -static int coroutine_fn raw_co_zone_append(BlockDriverState *bs, - int64_t *offset, - QEMUIOVector *qiov, - BdrvRequestFlags flags) { +static int coroutine_fn GRAPH_RDLOCK +raw_co_zone_append(BlockDriverState *bs, + int64_t *offset, + QEMUIOVector *qiov, + BdrvRequestFlags flags) { assert(flags == 0); int64_t zone_size_mask = bs->bl.zone_size - 1; int64_t iov_len = 0; From 2533500b4a0fa32737c90852103593f07fceeebf Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Sun, 18 May 2025 13:54:20 -0400 Subject: [PATCH 60/71] roms: re-remove execute bit from hppa-firmware* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was fixed in c9d77526bddba0803a1fa982fb59ec98057150f9 for 9.2.0 but regressed in db34be329162cf6b06192703065e6c1010dbe3c5 in 10.0.0 When the bit is present, rpmbuild complains about missing ELF build-id Signed-off-by: Cole Robinson Reviewed-by: Daniel P. Berrangé Acked-by: Helge Deller Message-ID: <52d0edfbb9b2f63a866f0065a721f3a95da6f8ba.1747590860.git.crobinso@redhat.com> Signed-off-by: Philippe Mathieu-Daudé (cherry picked from commit a598090ebaeb930ce33c2df0d80d87da13be8848) Signed-off-by: Michael Tokarev --- pc-bios/hppa-firmware.img | Bin pc-bios/hppa-firmware64.img | Bin 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 pc-bios/hppa-firmware.img mode change 100755 => 100644 pc-bios/hppa-firmware64.img diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img old mode 100755 new mode 100644 diff --git a/pc-bios/hppa-firmware64.img b/pc-bios/hppa-firmware64.img old mode 100755 new mode 100644 From 12e88c0c6c9448ab383258f1e477c211cf407350 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 3 Jun 2025 13:13:36 +0200 Subject: [PATCH 61/71] vhost: Fix used memslot tracking when destroying a vhost device When we unplug a vhost device, we end up calling vhost_dev_cleanup() where we do a memory_listener_unregister(). This memory_listener_unregister() call will end up disconnecting the listener from the address space through listener_del_address_space(). In that process, we effectively communicate the removal of all memory regions from that listener, resulting in region_del() + commit() callbacks getting triggered. So in case of vhost, we end up calling vhost_commit() with no remaining memory slots (0). In vhost_commit() we end up overwriting the global variables used_memslots / used_shared_memslots, used for detecting the number of free memslots. With used_memslots / used_shared_memslots set to 0 by vhost_commit() during device removal, we'll later assume that the other vhost devices still have plenty of memslots left when calling vhost_get_free_memslots(). Let's fix it by simply removing the global variables and depending only on the actual per-device count. Easy to reproduce by adding two vhost-user devices to a VM and then hot-unplugging one of them. While at it, detect unexpected underflows in vhost_get_free_memslots() and issue a warning. Reported-by: yuanminghao Link: https://lore.kernel.org/qemu-devel/20241121060755.164310-1-yuanmh12@chinatelecom.cn/ Fixes: 2ce68e4cf5be ("vhost: add vhost_has_free_slot() interface") Cc: Igor Mammedov Cc: Michael S. Tsirkin Cc: Stefano Garzarella Signed-off-by: David Hildenbrand Message-Id: <20250603111336.1858888-1-david@redhat.com> Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 9f749129e2629b19f424df106c92c5a5647e396c) Signed-off-by: Michael Tokarev --- hw/virtio/vhost.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 6aa72fd434..99d31cc1b4 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -47,12 +47,6 @@ static struct vhost_log *vhost_log[VHOST_BACKEND_TYPE_MAX]; static struct vhost_log *vhost_log_shm[VHOST_BACKEND_TYPE_MAX]; static QLIST_HEAD(, vhost_dev) vhost_log_devs[VHOST_BACKEND_TYPE_MAX]; -/* Memslots used by backends that support private memslots (without an fd). */ -static unsigned int used_memslots; - -/* Memslots used by backends that only support shared memslots (with an fd). */ -static unsigned int used_shared_memslots; - static QLIST_HEAD(, vhost_dev) vhost_devices = QLIST_HEAD_INITIALIZER(vhost_devices); @@ -74,15 +68,15 @@ unsigned int vhost_get_free_memslots(void) QLIST_FOREACH(hdev, &vhost_devices, entry) { unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev); - unsigned int cur_free; + unsigned int cur_free = r - hdev->mem->nregions; - if (hdev->vhost_ops->vhost_backend_no_private_memslots && - hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) { - cur_free = r - used_shared_memslots; + if (unlikely(r < hdev->mem->nregions)) { + warn_report_once("used (%u) vhost backend memory slots exceed" + " the device limit (%u).", hdev->mem->nregions, r); + free = 0; } else { - cur_free = r - used_memslots; + free = MIN(free, cur_free); } - free = MIN(free, cur_free); } return free; } @@ -666,13 +660,6 @@ static void vhost_commit(MemoryListener *listener) dev->mem = g_realloc(dev->mem, regions_size); dev->mem->nregions = dev->n_mem_sections; - if (dev->vhost_ops->vhost_backend_no_private_memslots && - dev->vhost_ops->vhost_backend_no_private_memslots(dev)) { - used_shared_memslots = dev->mem->nregions; - } else { - used_memslots = dev->mem->nregions; - } - for (i = 0; i < dev->n_mem_sections; i++) { struct vhost_memory_region *cur_vmr = dev->mem->regions + i; struct MemoryRegionSection *mrs = dev->mem_sections + i; @@ -1619,15 +1606,11 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); /* - * The listener we registered properly updated the corresponding counter. - * So we can trust that these values are accurate. + * The listener we registered properly setup the number of required + * memslots in vhost_commit(). */ - if (hdev->vhost_ops->vhost_backend_no_private_memslots && - hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) { - used = used_shared_memslots; - } else { - used = used_memslots; - } + used = hdev->mem->nregions; + /* * We assume that all reserved memslots actually require a real memslot * in our vhost backend. This might not be true, for example, if the From 2df7954daa523748e1067713d52a6baa334d3dc6 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 3 Jun 2025 18:18:28 +0900 Subject: [PATCH 62/71] ui/vnc: Do not copy z_stream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vnc_worker_thread_loop() copies z_stream stored in its local VncState to the persistent VncState, and the copied one is freed with deflateEnd() later. However, deflateEnd() refuses to operate with a copied z_stream and returns Z_STREAM_ERROR, leaking the allocated memory. Avoid copying the zlib state to fix the memory leak. Fixes: bd023f953e5e ("vnc: threaded VNC server") Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250603-zlib-v3-1-20b857bd8d05@rsg.ci.i.u-tokyo.ac.jp> (cherry picked from commit aef22331b5a4670f42638a5f63a26e93bf779aae) Signed-off-by: Michael Tokarev --- ui/vnc-enc-zlib.c | 30 +++++++++++++++--------------- ui/vnc.c | 13 ++++++++++--- ui/vnc.h | 2 +- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c index 900ae5b30f..52e9193eab 100644 --- a/ui/vnc-enc-zlib.c +++ b/ui/vnc-enc-zlib.c @@ -48,21 +48,21 @@ void vnc_zlib_zfree(void *x, void *addr) static void vnc_zlib_start(VncState *vs) { - buffer_reset(&vs->zlib.zlib); + buffer_reset(&vs->zlib->zlib); // make the output buffer be the zlib buffer, so we can compress it later - vs->zlib.tmp = vs->output; - vs->output = vs->zlib.zlib; + vs->zlib->tmp = vs->output; + vs->output = vs->zlib->zlib; } static int vnc_zlib_stop(VncState *vs) { - z_streamp zstream = &vs->zlib.stream; + z_streamp zstream = &vs->zlib->stream; int previous_out; // switch back to normal output/zlib buffers - vs->zlib.zlib = vs->output; - vs->output = vs->zlib.tmp; + vs->zlib->zlib = vs->output; + vs->output = vs->zlib->tmp; // compress the zlib buffer @@ -85,24 +85,24 @@ static int vnc_zlib_stop(VncState *vs) return -1; } - vs->zlib.level = vs->tight->compression; + vs->zlib->level = vs->tight->compression; zstream->opaque = vs; } - if (vs->tight->compression != vs->zlib.level) { + if (vs->tight->compression != vs->zlib->level) { if (deflateParams(zstream, vs->tight->compression, Z_DEFAULT_STRATEGY) != Z_OK) { return -1; } - vs->zlib.level = vs->tight->compression; + vs->zlib->level = vs->tight->compression; } // reserve memory in output buffer - buffer_reserve(&vs->output, vs->zlib.zlib.offset + 64); + buffer_reserve(&vs->output, vs->zlib->zlib.offset + 64); // set pointers - zstream->next_in = vs->zlib.zlib.buffer; - zstream->avail_in = vs->zlib.zlib.offset; + zstream->next_in = vs->zlib->zlib.buffer; + zstream->avail_in = vs->zlib->zlib.offset; zstream->next_out = vs->output.buffer + vs->output.offset; zstream->avail_out = vs->output.capacity - vs->output.offset; previous_out = zstream->avail_out; @@ -147,8 +147,8 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) void vnc_zlib_clear(VncState *vs) { - if (vs->zlib.stream.opaque) { - deflateEnd(&vs->zlib.stream); + if (vs->zlib->stream.opaque) { + deflateEnd(&vs->zlib->stream); } - buffer_free(&vs->zlib.zlib); + buffer_free(&vs->zlib->zlib); } diff --git a/ui/vnc.c b/ui/vnc.c index c96bd8ceea..ca02ff872a 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -56,6 +56,11 @@ #include "io/dns-resolver.h" #include "monitor/monitor.h" +typedef struct VncConnection { + VncState vs; + VncZlib zlib; +} VncConnection; + #define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT #define VNC_REFRESH_INTERVAL_INC 50 #define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE @@ -1364,7 +1369,7 @@ void vnc_disconnect_finish(VncState *vs) vs->magic = 0; g_free(vs->zrle); g_free(vs->tight); - g_free(vs); + g_free(container_of(vs, VncConnection, vs)); } size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error *err) @@ -3243,11 +3248,13 @@ static void vnc_refresh(DisplayChangeListener *dcl) static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, bool skipauth, bool websocket) { - VncState *vs = g_new0(VncState, 1); + VncConnection *vc = g_new0(VncConnection, 1); + VncState *vs = &vc->vs; bool first_client = QTAILQ_EMPTY(&vd->clients); int i; trace_vnc_client_connect(vs, sioc); + vs->zlib = &vc->zlib; vs->zrle = g_new0(VncZrle, 1); vs->tight = g_new0(VncTight, 1); vs->magic = VNC_MAGIC; @@ -3270,7 +3277,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, #ifdef CONFIG_PNG buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc); #endif - buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc); + buffer_init(&vc->zlib.zlib, "vnc-zlib/%p", sioc); buffer_init(&vs->zrle->zrle, "vnc-zrle/%p", sioc); buffer_init(&vs->zrle->fb, "vnc-zrle-fb/%p", sioc); buffer_init(&vs->zrle->zlib, "vnc-zrle-zlib/%p", sioc); diff --git a/ui/vnc.h b/ui/vnc.h index 02613aa63a..82b883bb69 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -340,7 +340,7 @@ struct VncState * update vnc_async_encoding_start() */ VncTight *tight; - VncZlib zlib; + VncZlib *zlib; VncHextile hextile; VncZrle *zrle; VncZywrle zywrle; From d0975531586742ec2eff8796b7ba93bc4858e63d Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Thu, 17 Jul 2025 06:23:26 +0300 Subject: [PATCH 63/71] i386/cpu: Fix cpu number overflow in CPUID.01H.EBX[23:16] The legacy topology enumerated by CPUID.1.EBX[23:16] is defined in SDM Vol2: Bits 23-16: Maximum number of addressable IDs for logical processors in this physical package. When threads_per_socket > 255, it will 1) overwrite bits[31:24] which is apic_id, 2) bits [23:16] get truncated. Specifically, if launching the VM with -smp 256, the value written to EBX[23:16] is 0 because of data overflow. If the guest only supports legacy topology, without V2 Extended Topology enumerated by CPUID.0x1f or Extended Topology enumerated by CPUID.0x0b to support over 255 CPUs, the return of the kernel invoking cpu_smt_allowed() is false and APs (application processors) will fail to bring up. Then only CPU 0 is online, and others are offline. For example, launch VM via: qemu-system-x86_64 -M q35,accel=kvm,kernel-irqchip=split \ -cpu qemu64,cpuid-0xb=off -smp 256 -m 32G \ -drive file=guest.img,if=none,id=virtio-disk0,format=raw \ -device virtio-blk-pci,drive=virtio-disk0,bootindex=1 --nographic The guest shows: CPU(s): 256 On-line CPU(s) list: 0 Off-line CPU(s) list: 1-255 To avoid this issue caused by overflow, limit the max value written to EBX[23:16] to 255 as the HW does. Cc: qemu-stable@nongnu.org Reviewed-by: Xiaoyao Li Signed-off-by: Qian Wen Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250714080859.1960104-6-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini (cherry picked from commit a62fef58299562aae6667b8d8552247423e886b3) (Mjt: fixup for 10.0.x series due to missing v10.0.0-2217-gf985a1195b "i386/cpu: Fix number of addressable IDs field for CPUID.01H.EBX[23:16]") Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 2c9517f56d..4603b2b98b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6828,7 +6828,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } *edx = env->features[FEAT_1_EDX]; if (threads_per_pkg > 1) { - *ebx |= threads_per_pkg << 16; + /* Fixup overflow: max value for bits 23-16 is 255. */ + *ebx |= MIN(threads_per_pkg, 255) << 16; } if (!cpu->enable_pmu) { *ecx &= ~CPUID_EXT_PDCM; From 18224789994e0276a626a4e4e5554695857bd998 Mon Sep 17 00:00:00 2001 From: Qian Wen Date: Mon, 14 Jul 2025 16:08:58 +0800 Subject: [PATCH 64/71] i386/cpu: Fix overflow of cache topology fields in CPUID.04H According to SDM, CPUID.0x4:EAX[31:26] indicates the Maximum number of addressable IDs for processor cores in the physical package. If we launch over 64 cores VM, the 6-bit field will overflow, and the wrong core_id number will be reported. Since the HW reports 0x3f when the intel processor has over 64 cores, limit the max value written to EAX[31:26] to 63, so max num_cores should be 64. For EAX[14:25], though at present Q35 supports up to 4096 CPUs, by constructing a specific topology, the width of the APIC ID can be extended beyond 12 bits. For example, using `-smp threads=33,cores=9, modules=9` results in a die level offset of 6 + 4 + 4 = 14 bits, which can also cause overflow. check and honor the maximum value for EAX[14:25] as well. In addition, for host-cache-info case, also apply the same checks and fixes. Reviewed-by: Xiaoyao Li Signed-off-by: Qian Wen Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250714080859.1960104-7-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini (cherry picked from commit 3e86124e7cb9b66e07fb992667865a308f16fcf2) Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 4603b2b98b..0480ad4ab1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -283,11 +283,17 @@ static void encode_cache_cpuid4(CPUCacheInfo *cache, assert(cache->size == cache->line_size * cache->associativity * cache->partitions * cache->sets); + /* + * The following fields have bit-width limitations, so consider the + * maximum values to avoid overflow: + * Bits 25-14: maximum 4095. + * Bits 31-26: maximum 63. + */ *eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) | (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) | - (max_core_ids_in_package(topo_info) << 26) | - (max_thread_ids_for_cache(topo_info, cache->share_level) << 14); + (MIN(max_core_ids_in_package(topo_info), 63) << 26) | + (MIN(max_thread_ids_for_cache(topo_info, cache->share_level), 4095) << 14); assert(cache->line_size > 0); assert(cache->partitions > 0); @@ -6867,13 +6873,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); *eax &= ~0xFC000000; - *eax |= max_core_ids_in_package(topo_info) << 26; + *eax |= MIN(max_core_ids_in_package(topo_info), 63) << 26; if (host_vcpus_per_cache > threads_per_pkg) { *eax &= ~0x3FFC000; /* Share the cache at package level. */ - *eax |= max_thread_ids_for_cache(topo_info, - CPU_TOPOLOGY_LEVEL_SOCKET) << 14; + *eax |= MIN(max_thread_ids_for_cache(topo_info, + CPU_TOPOLOGY_LEVEL_SOCKET), 4095) << 14; } } } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { From 82517381c54d87985994ad597d274e3f2e18a484 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Jul 2025 16:08:59 +0800 Subject: [PATCH 65/71] i386/cpu: Honor maximum value for CPUID.8000001DH.EAX[25:14] CPUID.8000001DH:EAX[25:14] is "NumSharingCache", and the number of logical processors sharing this cache is the value of this field incremented by 1. Because of its width limitation, the maximum value currently supported is 4095. Though at present Q35 supports up to 4096 CPUs, by constructing a specific topology, the width of the APIC ID can be extended beyond 12 bits. For example, using `-smp threads=33,cores=9,modules=9` results in a die level offset of 6 + 4 + 4 = 14 bits, which can also cause overflow. Check and honor the maximum value as CPUID.04H did. Cc: Babu Moger Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250714080859.1960104-8-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini (cherry picked from commit 5d21ee453ad8e3f95f75e542cb3b35c5bb7cf23a) Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 0480ad4ab1..b768d8ea33 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -496,7 +496,8 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, *eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) | (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0); - *eax |= max_thread_ids_for_cache(topo_info, cache->share_level) << 14; + /* Bits 25:14 - NumSharingCache: maximum 4095. */ + *eax |= MIN(max_thread_ids_for_cache(topo_info, cache->share_level), 4095) << 14; assert(cache->line_size > 0); assert(cache->partitions > 0); From 24778b1c7ee7aca9721ed4757b0e0df0c16390f7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Jul 2025 10:19:36 +0200 Subject: [PATCH 66/71] target/i386: do not expose ARCH_CAPABILITIES on AMD CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KVM emulates the ARCH_CAPABILITIES on x86 for both Intel and AMD cpus, although the IA32_ARCH_CAPABILITIES MSR is an Intel-specific MSR and it makes no sense to emulate it on AMD. As a consequence, VMs created on AMD with qemu -cpu host and using KVM will advertise the ARCH_CAPABILITIES feature and provide the IA32_ARCH_CAPABILITIES MSR. This can cause issues (like Windows BSOD) as the guest OS might not expect this MSR to exist on such cpus (the AMD documentation specifies that ARCH_CAPABILITIES feature and MSR are not defined on the AMD architecture). A fix was proposed in KVM code, however KVM maintainers don't want to change this behavior that exists for 6+ years and suggest changes to be done in QEMU instead. Therefore, hide the bit from "-cpu host": migration of -cpu host guests is only possible between identical host kernel and QEMU versions, therefore this is not a problematic breakage. If a future AMD machine does include the MSR, that would re-expose the Windows guest bug; but it would not be KVM/QEMU's problem at that point, as we'd be following a genuine physical CPU impl. Reported-by: Alexandre Chartre Suggested-by: Daniel P. Berrangé Reviewed-by: Xiaoyao Li Signed-off-by: Paolo Bonzini (cherry picked from commit d3a24134e37d57abd3e7445842cda2717f49e96d) Signed-off-by: Michael Tokarev --- target/i386/kvm/kvm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 6c749d4ee8..141694f803 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -500,8 +500,12 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, * Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts. * We can detect the bug by checking if MSR_IA32_ARCH_CAPABILITIES is * returned by KVM_GET_MSR_INDEX_LIST. + * + * But also, because Windows does not like ARCH_CAPABILITIES on AMD + * mcahines at all, do not show the fake ARCH_CAPABILITIES MSR that + * KVM sets up. */ - if (!has_msr_arch_capabs) { + if (!has_msr_arch_capabs || !(edx & CPUID_7_0_EDX_ARCH_CAPABILITIES)) { ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES; } } else if (function == 7 && index == 1 && reg == R_EAX) { From 9561a8c14049a851bb5b83d92707bec2d6692052 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 14 Jul 2025 17:55:20 +0100 Subject: [PATCH 67/71] hw/net/npcm_gmac.c: Send the right data for second packet in a row The transmit loop in gmac_try_send_next_packet() is constructed in a way that means it will send incorrect data if it it sends more than one packet. The function assembles the outbound data in a dynamically allocated block of memory which is pointed to by tx_send_buffer. We track the first point in this block of memory which is not yet used with the prev_buf_size offset, initially zero. We track the size of the packet we're sending with the length variable, also initially zero. As we read chunks of data out of guest memory, we write them to tx_send_buffer[prev_buf_size], and then increment both prev_buf_size and length. (We might dynamically reallocate the buffer if needed.) When we send a packet, we checksum and send length bytes, starting at tx_send_buffer, and then we reset length to 0. This gives the right data for the first packet. But we don't reset prev_buf_size. This means that if we process more descriptors with further data for the next packet, that data will continue to accumulate at offset prev_buf_size, i.e. after the data for the first packet. But when we transmit that second packet, we send length bytes from tx_send_buffer, so we will send a packet which has the length of the second packet but the data of the first one. The fix for this is to also clear prev_buf_size after the packet has been sent -- we never need the data from packet one after we've sent it, so we can write packet two's data starting at the beginning of the buffer. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Signed-off-by: Jason Wang (cherry picked from commit 871a6e5b339f0b5e71925ec7d3f452944a1c82d3) Signed-off-by: Michael Tokarev --- hw/net/npcm_gmac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c index e1fb383772..d4dba630ac 100644 --- a/hw/net/npcm_gmac.c +++ b/hw/net/npcm_gmac.c @@ -615,6 +615,7 @@ static void gmac_try_send_next_packet(NPCMGMACState *gmac) trace_npcm_gmac_packet_sent(DEVICE(gmac)->canonical_path, length); buf = tx_send_buffer; length = 0; + prev_buf_size = 0; } /* step 6 */ From 08fa61a3652e36e6966bc6a3473f7a333c4058a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 4 Jun 2025 16:47:31 +0100 Subject: [PATCH 68/71] ui: fix setting client_endian field defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a VNC client sends a "set pixel format" message, the 'client_endian' field will get initialized, however, it is valid to omit this message if the client wants to use the server's native pixel format. In the latter scenario nothing is initializing the 'client_endian' field, so it remains set to 0, matching neither G_LITTLE_ENDIAN nor G_BIG_ENDIAN. This then results in pixel format conversion routines taking the wrong code paths. This problem existed before the 'client_be' flag was changed into the 'client_endian' value, but the lack of initialization meant it semantically defaulted to little endian, so only big endian systems would potentially be exposed to incorrect pixel translation. The 'virt-viewer' / 'remote-viewer' apps always send a "set pixel format" message so aren't exposed to any problems, but the classical 'vncviewer' app will show the problem easily. Fixes: 7ed96710e82c385c6cfc3d064eec7dde20f0f3fd Reported-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Signed-off-by: Daniel P. Berrangé (cherry picked from commit 3ac6daa9e1c5d7dae2a3cd1c6a388174b462f3e8) Signed-off-by: Michael Tokarev --- ui/vnc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/vnc.c b/ui/vnc.c index ca02ff872a..a6bf8442d5 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2336,6 +2336,7 @@ static void pixel_format_message (VncState *vs) { char pad[3] = { 0, 0, 0 }; vs->client_pf = qemu_default_pixelformat(32); + vs->client_endian = G_BYTE_ORDER; vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */ vnc_write_u8(vs, vs->client_pf.depth); /* depth */ From 3341f5cd5c391c6b460f2f70cc694ca5ef3b2191 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jul 2025 10:07:52 +0100 Subject: [PATCH 69/71] target/arm: Correct encoding of Debug Communications Channel registers We don't implement the Debug Communications Channel (DCC), but we do attempt to provide dummy versions of its system registers so that software that tries to access them doesn't fall over. However, we got the tx/rx register definitions wrong. These should be: AArch32: DBGDTRTX p14 0 c0 c5 0 (on writes) DBGDTRRX p14 0 c0 c5 0 (on reads) AArch64: DBGDTRTX_EL0 2 3 0 5 0 (on writes) DBGDTRRX_EL0 2 3 0 5 0 (on reads) DBGDTR_EL0 2 3 0 4 0 (reads and writes) where DBGDTRTX and DBGDTRRX are effectively different names for the same 32-bit register, which has tx behaviour on writes and rx behaviour on reads. The AArch64-only DBGDTR_EL0 is a 64-bit wide register whose top and bottom halves map to the DBGDTRRX and DBGDTRTX registers. Currently we have just one cpreg struct, which: * calls itself DBGDTR_EL0 * uses the DBGDTRTX_EL0/DBGDTRRX_EL0 encoding * is marked as ARM_CP_STATE_BOTH but has the wrong opc1 value for AArch32 * is implemented as RAZ/WI Correct the encoding so: * we name the DBGDTRTX/DBGDTRRX register correctly * we split it into AA64 and AA32 versions so we can get the AA32 encoding right * we implement DBGDTR_EL0 at its correct encoding Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2986 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20250708141049.778361-1-peter.maydell@linaro.org (cherry picked from commit 655659a74a36b63e33d2dc969d3c44beb1b008b3) Signed-off-by: Michael Tokarev --- target/arm/debug_helper.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index a9a619ba6b..79c0e8eaff 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -986,11 +986,20 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, .access = PL1_RW, .accessfn = access_tdcc, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* DBGDTRTX_EL0/DBGDTRRX_EL0 depend on direction */ - { .name = "DBGDTR_EL0", .state = ARM_CP_STATE_BOTH, .cp = 14, + /* Architecturally DBGDTRTX is named DBGDTRRX when used for reads */ + { .name = "DBGDTRTX_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 5, .opc2 = 0, .access = PL0_RW, .accessfn = access_tdcc, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "DBGDTRTX", .state = ARM_CP_STATE_AA32, .cp = 14, + .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, + .access = PL0_RW, .accessfn = access_tdcc, + .type = ARM_CP_CONST, .resetvalue = 0 }, + /* This is AArch64-only and is a combination of DBGDTRTX and DBGDTRRX */ + { .name = "DBGDTR_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 4, .opc2 = 0, + .access = PL0_RW, .accessfn = access_tdcc, + .type = ARM_CP_CONST, .resetvalue = 0 }, /* * OSECCR_EL1 provides a mechanism for an operating system * to access the contents of EDECCR. EDECCR is not implemented though, From a5ac9803d513586eefe6c7613b3c3bcc1b9e5943 Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Tue, 15 Jul 2025 00:01:39 +0800 Subject: [PATCH 70/71] hvf: arm: Emulate ICC_RPR_EL1 accesses properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a2260983c655 ("hvf: arm: Add support for GICv3") added GICv3 support by implementing emulation for a few system registers. ICC_RPR_EL1 was defined but not plugged in the sysreg handlers (for no good reason). Fix it. Fixes: a2260983c655 ("hvf: arm: Add support for GICv3") Signed-off-by: Zenghui Yu Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250714160139.10404-3-zenghui.yu@linux.dev Signed-off-by: Peter Maydell (cherry picked from commit e6da704b711d5d731e4d933ad56cbbc25ee0a825) Signed-off-by: Michael Tokarev --- target/arm/hvf/hvf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 01e26a9726..8a4a41d15b 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1352,6 +1352,7 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint64_t *val) case SYSREG_ICC_IGRPEN0_EL1: case SYSREG_ICC_IGRPEN1_EL1: case SYSREG_ICC_PMR_EL1: + case SYSREG_ICC_RPR_EL1: case SYSREG_ICC_SGI0R_EL1: case SYSREG_ICC_SGI1R_EL1: case SYSREG_ICC_SRE_EL1: @@ -1666,6 +1667,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_ICC_IGRPEN0_EL1: case SYSREG_ICC_IGRPEN1_EL1: case SYSREG_ICC_PMR_EL1: + case SYSREG_ICC_RPR_EL1: case SYSREG_ICC_SGI0R_EL1: case SYSREG_ICC_SGI1R_EL1: case SYSREG_ICC_SRE_EL1: From 66d21643c2b8f2bec969a80ccea09667c77151ee Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Tue, 22 Jul 2025 20:46:10 +0300 Subject: [PATCH 71/71] Update version for 10.0.3 release Signed-off-by: Michael Tokarev --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7e2df97fe5..6a7144d304 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -10.0.2 +10.0.3