From 1bc3117abad28d6465ecdb2c944b22943df0e4f3 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 20 Apr 2018 10:48:19 +0200 Subject: [PATCH 1/6] vnc: fix use-after-free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When vnc_client_read() return value is -1 vs is not valid any more. Fixes: d49b87f0d1e0520443a990fc610d0f02bc63c556 Reported-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Tested-by: Marc-André Lureau Tested-by: Philippe Mathieu-Daudé Message-id: 20180420084820.3873-1-kraxel@redhat.com --- ui/vnc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index e164eb798c..5526e54f48 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1539,13 +1539,14 @@ gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED, VncState *vs = opaque; if (condition & G_IO_IN) { if (vnc_client_read(vs) < 0) { - goto end; + /* vs is free()ed here */ + return TRUE; } } if (condition & G_IO_OUT) { vnc_client_write(vs); } -end: + if (vs->disconnecting) { if (vs->ioc_tag != 0) { g_source_remove(vs->ioc_tag); From 62f27922b3f1e0253a6755d2c711cd0bc1e79f18 Mon Sep 17 00:00:00 2001 From: Elie Tournier Date: Fri, 13 Apr 2018 14:58:40 +0100 Subject: [PATCH 2/6] qapi: Parameter gl of DisplayType now accept an enum v2: Rebase on top of master v3: Fix the json format (Eric Blake) Fix a comparison issue (Gerd Hoffmann) Signed-off-by: Elie Tournier Message-id: 20180413135842.21325-2-tournier.elie@gmail.com Signed-off-by: Gerd Hoffmann --- qapi/ui.json | 20 +++++++++++++++++++- vl.c | 10 +++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/qapi/ui.json b/qapi/ui.json index 5d01ad4304..3ad7835992 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1019,6 +1019,24 @@ { 'struct' : 'DisplayGTK', 'data' : { '*grab-on-hover' : 'bool' } } + ## + # @DisplayGLMode: + # + # Display OpenGL mode. + # + # @off: Disable OpenGL (default). + # @on: Use OpenGL, pick context type automatically. + # Would better be named 'auto' but is called 'on' for backward + # compatibility with bool type. + # @core: Use OpenGL with Core (desktop) Context. + # @es: Use OpenGL with ES (embedded systems) Context. + # + # Since: 2.13 + # + ## + { 'enum' : 'DisplayGLMode', + 'data' : [ 'off', 'on', 'core', 'es' ] } + ## # @DisplayType: # @@ -1048,7 +1066,7 @@ 'base' : { 'type' : 'DisplayType', '*full-screen' : 'bool', '*window-close' : 'bool', - '*gl' : 'bool' }, + '*gl' : 'DisplayGLMode' }, 'discriminator' : 'type', 'data' : { 'default' : 'DisplayNoOpts', 'none' : 'DisplayNoOpts', diff --git a/vl.c b/vl.c index 616956adf1..f7804f7a18 100644 --- a/vl.c +++ b/vl.c @@ -2143,9 +2143,9 @@ static void parse_display(const char *p) opts = nextopt; dpy.has_gl = true; if (strstart(opts, "on", &nextopt)) { - dpy.gl = true; + dpy.gl = DISPLAYGL_MODE_ON; } else if (strstart(opts, "off", &nextopt)) { - dpy.gl = false; + dpy.gl = DISPLAYGL_MODE_OFF; } else { goto invalid_sdl_args; } @@ -2186,9 +2186,9 @@ static void parse_display(const char *p) opts = nextopt; dpy.has_gl = true; if (strstart(opts, "on", &nextopt)) { - dpy.gl = true; + dpy.gl = DISPLAYGL_MODE_ON; } else if (strstart(opts, "off", &nextopt)) { - dpy.gl = false; + dpy.gl = DISPLAYGL_MODE_OFF; } else { goto invalid_gtk_args; } @@ -4356,7 +4356,7 @@ int main(int argc, char **argv, char **envp) qemu_display_early_init(&dpy); qemu_console_early_init(); - if (dpy.has_gl && dpy.gl && display_opengl == 0) { + if (dpy.has_gl && dpy.gl != DISPLAYGL_MODE_OFF && display_opengl == 0) { #if defined(CONFIG_OPENGL) error_report("OpenGL is not supported by the display"); #else From 844fd50dbbcfc9e401895274bf4fb8da8e8d3f64 Mon Sep 17 00:00:00 2001 From: Elie Tournier Date: Fri, 13 Apr 2018 14:58:41 +0100 Subject: [PATCH 3/6] sdl: Move DisplayOptions global to sdl2_console Suggested-by: Gerd Hoffmann Signed-off-by: Elie Tournier Message-id: 20180413135842.21325-3-tournier.elie@gmail.com Signed-off-by: Gerd Hoffmann --- include/ui/sdl2.h | 1 + ui/sdl2.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h index 51084e6320..f43eecdbd6 100644 --- a/include/ui/sdl2.h +++ b/include/ui/sdl2.h @@ -14,6 +14,7 @@ struct sdl2_console { DisplayChangeListener dcl; DisplaySurface *surface; + DisplayOptions *opts; SDL_Texture *texture; SDL_Window *real_window; SDL_Renderer *real_renderer; diff --git a/ui/sdl2.c b/ui/sdl2.c index 83b917fa37..da037248c2 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -32,7 +32,6 @@ static int sdl2_num_outputs; static struct sdl2_console *sdl2_console; -static DisplayOptions *opts; static SDL_Surface *guest_sprite_surface; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ @@ -566,7 +565,7 @@ static void handle_windowevent(SDL_Event *ev) break; case SDL_WINDOWEVENT_CLOSE: if (qemu_console_is_graphic(scon->dcl.con)) { - if (opts->has_window_close && !opts->window_close) { + if (scon->opts->has_window_close && !scon->opts->window_close) { allow_close = false; } if (allow_close) { @@ -613,7 +612,7 @@ void sdl2_poll_events(struct sdl2_console *scon) handle_textinput(ev); break; case SDL_QUIT: - if (opts->has_window_close && !opts->window_close) { + if (scon->opts->has_window_close && !scon->opts->window_close) { allow_close = false; } if (allow_close) { @@ -770,7 +769,6 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) SDL_SysWMinfo info; assert(o->type == DISPLAY_TYPE_SDL); - opts = o; #ifdef __linux__ /* on Linux, SDL may use fbcon|directfb|svgalib when run without @@ -806,6 +804,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) return; } sdl2_console = g_new0(struct sdl2_console, sdl2_num_outputs); + sdl2_console->opts = o; for (i = 0; i < sdl2_num_outputs; i++) { QemuConsole *con = qemu_console_lookup_by_index(i); assert(con != NULL); @@ -846,7 +845,8 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) g_free(filename); } - if (opts->has_full_screen && opts->full_screen) { + if (sdl2_console->opts->has_full_screen && + sdl2_console->opts->full_screen) { gui_fullscreen = 1; sdl_grab_start(0); } From 4867e47cb637c6f3549786f1be70793112f96713 Mon Sep 17 00:00:00 2001 From: Elie Tournier Date: Fri, 13 Apr 2018 14:58:42 +0100 Subject: [PATCH 4/6] sdl: Allow OpenGL ES context creation Signed-off-by: Elie Tournier Message-id: 20180413135842.21325-4-tournier.elie@gmail.com [ kraxel: fix indent ] Signed-off-by: Gerd Hoffmann --- qemu-options.hx | 2 +- ui/sdl2-gl.c | 19 +++++++++++++++++-- vl.c | 4 ++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index ca4e412f2f..333dd1f1c8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1240,7 +1240,7 @@ ETEXI DEF("display", HAS_ARG, QEMU_OPTION_display, "-display sdl[,frame=on|off][,alt_grab=on|off][,ctrl_grab=on|off]\n" - " [,window_close=on|off][,gl=on|off]\n" + " [,window_close=on|off][,gl=on|core|es|off]\n" "-display gtk[,grab_on_hover=on|off][,gl=on|off]|\n" "-display vnc=[,]\n" "-display curses\n" diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c index c3683e6b65..83b71853d1 100644 --- a/ui/sdl2-gl.c +++ b/ui/sdl2-gl.c @@ -140,12 +140,27 @@ QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl, SDL_GL_MakeCurrent(scon->real_window, scon->winctx); SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, - SDL_GL_CONTEXT_PROFILE_CORE); + if (scon->opts->gl == DISPLAYGL_MODE_ON || + scon->opts->gl == DISPLAYGL_MODE_CORE) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_CONTEXT_PROFILE_CORE); + } else if (scon->opts->gl == DISPLAYGL_MODE_ES) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_CONTEXT_PROFILE_ES); + } SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver); ctx = SDL_GL_CreateContext(scon->real_window); + + /* If SDL fail to create a GL context and we use the "on" flag, + * then try to fallback to GLES. + */ + if (!ctx && scon->opts->gl == DISPLAYGL_MODE_ON) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_CONTEXT_PROFILE_ES); + ctx = SDL_GL_CreateContext(scon->real_window); + } return (QEMUGLContext)ctx; } diff --git a/vl.c b/vl.c index f7804f7a18..916d2a80a7 100644 --- a/vl.c +++ b/vl.c @@ -2144,6 +2144,10 @@ static void parse_display(const char *p) dpy.has_gl = true; if (strstart(opts, "on", &nextopt)) { dpy.gl = DISPLAYGL_MODE_ON; + } else if (strstart(opts, "core", &nextopt)) { + dpy.gl = DISPLAYGL_MODE_CORE; + } else if (strstart(opts, "es", &nextopt)) { + dpy.gl = DISPLAYGL_MODE_ES; } else if (strstart(opts, "off", &nextopt)) { dpy.gl = DISPLAYGL_MODE_OFF; } else { From 7cd0afe69f3330a104b1462c01156dd8525b9bdd Mon Sep 17 00:00:00 2001 From: Tina Zhang Date: Fri, 27 Apr 2018 17:11:05 +0800 Subject: [PATCH 5/6] console: introduce dpy_gfx_update_full dpy_gfx_update_full is used to do the whole display surface update. This function is proposed by Gerd Hoffmann. Signed-off-by: Tina Zhang Message-id: 1524820266-27079-2-git-send-email-tina.zhang@intel.com Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 1 + ui/console.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/include/ui/console.h b/include/ui/console.h index 37a8d68d29..981b519dde 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -291,6 +291,7 @@ bool dpy_ui_info_supported(QemuConsole *con); int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info); void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h); +void dpy_gfx_update_full(QemuConsole *con); void dpy_gfx_replace_surface(QemuConsole *con, DisplaySurface *surface); void dpy_text_cursor(QemuConsole *con, int x, int y); diff --git a/ui/console.c b/ui/console.c index 3fb2f4e09f..b02510cdca 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1574,6 +1574,16 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) } } +void dpy_gfx_update_full(QemuConsole *con) +{ + if (!con->surface) { + return; + } + dpy_gfx_update(con, 0, 0, + surface_width(con->surface), + surface_height(con->surface)); +} + void dpy_gfx_replace_surface(QemuConsole *con, DisplaySurface *surface) { From 8983e3e35033ecb9234725c2bba65f020824969b Mon Sep 17 00:00:00 2001 From: Tina Zhang Date: Fri, 27 Apr 2018 17:11:06 +0800 Subject: [PATCH 6/6] ui: introduce vfio_display_reset During guest OS reboot, guest framebuffer is invalid. It will cause bugs, if the invalid guest framebuffer is still used by host. This patch is to introduce vfio_display_reset which is invoked during vfio display reset. This vfio_display_reset function is used to release the invalid display resource, disable scanout mode and replace the invalid surface with QemuConsole's DisplaySurafce. This patch can fix the GPU hang issue caused by gd_egl_draw during guest OS reboot. Changes v3->v4: - Move dma-buf based display check into the vfio_display_reset(). (Gerd) Changes v2->v3: - Limit vfio_display_reset to dma-buf based vfio display. (Gerd) Changes v1->v2: - Use dpy_gfx_update_full() update screen after reset. (Gerd) - Remove dpy_gfx_switch_surface(). (Gerd) Signed-off-by: Tina Zhang Message-id: 1524820266-27079-3-git-send-email-tina.zhang@intel.com Signed-off-by: Gerd Hoffmann --- hw/vfio/display.c | 11 +++++++++++ hw/vfio/pci.c | 4 ++++ hw/vfio/pci.h | 1 + 3 files changed, 16 insertions(+) diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 7d727ce910..59c0e5d1d7 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -198,6 +198,17 @@ static void vfio_display_dmabuf_exit(VFIODisplay *dpy) } /* ---------------------------------------------------------------------- */ +void vfio_display_reset(VFIOPCIDevice *vdev) +{ + if (!vdev || !vdev->dpy || !vdev->dpy->con || + !vdev->dpy->dmabuf.primary) { + return; + } + + dpy_gl_scanout_disable(vdev->dpy->con); + vfio_display_dmabuf_exit(vdev->dpy); + dpy_gfx_update_full(vdev->dpy->con); +} static void vfio_display_region_update(void *opaque) { diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index b9bc6cd310..4947fe39a2 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3103,6 +3103,10 @@ static void vfio_pci_reset(DeviceState *dev) vfio_pci_pre_reset(vdev); + if (vdev->display != ON_OFF_AUTO_OFF) { + vfio_display_reset(vdev); + } + if (vdev->resetfn && !vdev->resetfn(vdev)) { goto post_reset; } diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 629c875701..59ab7757a3 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -176,6 +176,7 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, struct vfio_region_info *info, Error **errp); +void vfio_display_reset(VFIOPCIDevice *vdev); int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp); void vfio_display_finalize(VFIOPCIDevice *vdev);