From 330ef31deb2e5461cff907488b710f5bd9cd2327 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Tue, 8 Oct 2024 16:50:13 +0400 Subject: ui/win32: fix potential use-after-free with dbus shared memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DisplaySurface may be free before the pixman image is freed, since the image is refcounted and used by different objects, including pending dbus messages. Furthermore, setting the destroy function in create_displaysurface_from() isn't appropriate, as it may not be used, and may be overriden as in ramfb. Set the destroy function when the shared handle is set, use the HANDLE directly for destroy data, using a single common helper qemu_pixman_win32_image_destroy(). Signed-off-by: Marc-André Lureau Reviewed-by: Akihiko Odaki Message-ID: <20241008125028.1177932-5-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'hw/display/virtio-gpu.c') diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 3281842bfe..017a0f170c 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -238,16 +238,6 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat, return height * stride; } -#ifdef WIN32 -static void -win32_pixman_image_destroy(pixman_image_t *image, void *data) -{ - HANDLE handle = data; - - qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn); -} -#endif - static void virtio_gpu_resource_create_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -308,7 +298,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, bits, c2d.height ? res->hostmem / c2d.height : 0); #ifdef WIN32 if (res->image) { - pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle); + pixman_image_set_destroy_function(res->image, qemu_pixman_win32_image_destroy, res->handle); } #endif } @@ -1327,7 +1317,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, return -EINVAL; } #ifdef WIN32 - pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle); + pixman_image_set_destroy_function(res->image, qemu_pixman_win32_image_destroy, res->handle); #endif res->addrs = g_new(uint64_t, res->iov_cnt); -- cgit 1.4.1 From 1bfb726112ea4fda07c988f08df32d1eebb9abec Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Tue, 8 Oct 2024 16:50:18 +0400 Subject: ui/pixman: generalize shared_image_destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Learn to free memfd-allocated shared memory. Signed-off-by: Marc-André Lureau Reviewed-by: Akihiko Odaki Message-ID: <20241008125028.1177932-10-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu.c | 4 ++-- include/ui/qemu-pixman.h | 2 +- ui/console.c | 2 +- ui/qemu-pixman.c | 20 ++++++++++++-------- 4 files changed, 16 insertions(+), 12 deletions(-) (limited to 'hw/display/virtio-gpu.c') diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 017a0f170c..77f6e76f23 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -298,7 +298,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, bits, c2d.height ? res->hostmem / c2d.height : 0); #ifdef WIN32 if (res->image) { - pixman_image_set_destroy_function(res->image, qemu_pixman_win32_image_destroy, res->handle); + pixman_image_set_destroy_function(res->image, qemu_pixman_shared_image_destroy, res->handle); } #endif } @@ -1317,7 +1317,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, return -EINVAL; } #ifdef WIN32 - pixman_image_set_destroy_function(res->image, qemu_pixman_win32_image_destroy, res->handle); + pixman_image_set_destroy_function(res->image, qemu_pixman_shared_image_destroy, res->handle); #endif res->addrs = g_new(uint64_t, res->iov_cnt); diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index e3dd72b9e3..a97f56d09a 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -97,7 +97,7 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph, void qemu_pixman_image_unref(pixman_image_t *image); -void qemu_pixman_win32_image_destroy(pixman_image_t *image, void *data); +void qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data); G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref) diff --git a/ui/console.c b/ui/console.c index 8f416ff0b9..fdd76c2be4 100644 --- a/ui/console.c +++ b/ui/console.c @@ -487,7 +487,7 @@ DisplaySurface *qemu_create_displaysurface(int width, int height) #ifdef WIN32 qemu_displaysurface_win32_set_handle(surface, handle, 0); pixman_image_set_destroy_function(surface->image, - qemu_pixman_win32_image_destroy, handle); + qemu_pixman_shared_image_destroy, handle); #endif return surface; } diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 3870e1a215..46a91e7f7a 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -6,6 +6,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "ui/console.h" +#include "qemu/memfd.h" #include "standard-headers/drm/drm_fourcc.h" #include "trace.h" @@ -269,16 +270,19 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph, } #endif /* CONFIG_PIXMAN */ -#ifdef WIN32 void -qemu_pixman_win32_image_destroy(pixman_image_t *image, void *data) +qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data) { + void *ptr = pixman_image_get_data(image); + +#ifdef WIN32 HANDLE handle = data; - qemu_win32_map_free( - pixman_image_get_data(image), - handle, - &error_warn - ); -} + qemu_win32_map_free(ptr, handle, &error_warn); +#else + int shmfd = GPOINTER_TO_INT(data); + size_t size = pixman_image_get_height(image) * pixman_image_get_stride(image); + + qemu_memfd_free(ptr, size, shmfd); #endif +} -- cgit 1.4.1 From 5f899c34af1dbb0f621287faf9bcfb60fa237543 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Tue, 8 Oct 2024 16:50:26 +0400 Subject: virtio-gpu: allocate shareable 2d resources on !win32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to what was done in commit 9462ff46 ("virtio-gpu/win32: allocate shareable 2d resources/images") for win32, allocate resource memory with memfd, so the associated display surface memory can be shared with a different process. Signed-off-by: Marc-André Lureau Reviewed-by: Akihiko Odaki Message-ID: <20241008125028.1177932-18-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu.c | 39 +++++++++++++++++++++++++++------------ include/hw/virtio/virtio-gpu.h | 2 ++ 2 files changed, 29 insertions(+), 12 deletions(-) (limited to 'hw/display/virtio-gpu.c') diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 77f6e76f23..23ebefa59c 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -28,6 +28,7 @@ #include "hw/virtio/virtio-bus.h" #include "hw/qdev-properties.h" #include "qemu/log.h" +#include "qemu/memfd.h" #include "qemu/module.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -238,6 +239,20 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat, return height * stride; } +static void +resource_set_image_destroy(struct virtio_gpu_simple_resource *res) +{ + if (!res) { + return; + } +#ifdef WIN32 + void *data = res->handle; +#else + void *data = GINT_TO_POINTER(res->shmfd); +#endif + pixman_image_set_destroy_function(res->image, qemu_pixman_shared_image_destroy, data); +} + static void virtio_gpu_resource_create_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -287,25 +302,21 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, void *bits = NULL; #ifdef WIN32 bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); +#else + bits = qemu_memfd_alloc("virtio-gpu-res", res->hostmem, 0, &res->shmfd, &error_warn); +#endif if (!bits) { goto end; } -#endif res->image = pixman_image_create_bits( pformat, c2d.width, c2d.height, bits, c2d.height ? res->hostmem / c2d.height : 0); -#ifdef WIN32 - if (res->image) { - pixman_image_set_destroy_function(res->image, qemu_pixman_shared_image_destroy, res->handle); - } -#endif + resource_set_image_destroy(res); } -#ifdef WIN32 end: -#endif if (!res->image) { qemu_log_mask(LOG_GUEST_ERROR, "%s: resource creation failed %d %d %d\n", @@ -678,6 +689,8 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g, scanout->ds = qemu_create_displaysurface_pixman(rect); #ifdef WIN32 qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset); +#else + qemu_displaysurface_set_shmfd(scanout->ds, res->shmfd, fb->offset); #endif pixman_image_unref(rect); @@ -1303,11 +1316,13 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, res->hostmem = calc_image_hostmem(pformat, res->width, res->height); #ifdef WIN32 bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); +#else + bits = qemu_memfd_alloc("virtio-gpu-res", res->hostmem, 0, &res->shmfd, &error_warn); +#endif if (!bits) { g_free(res); return -EINVAL; } -#endif res->image = pixman_image_create_bits( pformat, res->width, res->height, @@ -1316,9 +1331,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, g_free(res); return -EINVAL; } -#ifdef WIN32 - pixman_image_set_destroy_function(res->image, qemu_pixman_shared_image_destroy, res->handle); -#endif + resource_set_image_destroy(res); res->addrs = g_new(uint64_t, res->iov_cnt); res->iov = g_new(struct iovec, res->iov_cnt); @@ -1453,6 +1466,8 @@ static int virtio_gpu_post_load(void *opaque, int version_id) scanout->ds = qemu_create_displaysurface_pixman(res->image); #ifdef WIN32 qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0); +#else + qemu_displaysurface_set_shmfd(scanout->ds, res->shmfd, 0); #endif dpy_gfx_replace_surface(scanout->con, scanout->ds); } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7a59379f5a..7509d13265 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -53,6 +53,8 @@ struct virtio_gpu_simple_resource { pixman_image_t *image; #ifdef WIN32 HANDLE handle; +#else + int shmfd; #endif uint64_t hostmem; -- cgit 1.4.1 From 1ff788db9781615be745671ebdb2eb82c137c5b8 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Tue, 8 Oct 2024 16:50:27 +0400 Subject: ui: refactor using a common qemu_pixman_shareable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a common shareable type for win32 & unix, and helper functions. This simplify the code as it avoids a lot of #ifdef'ery. Note: if it helps review, commits could be reordered to introduce the common type before introducing shareable memory for unix. Suggested-by: Akihiko Odaki Signed-off-by: Marc-André Lureau Reviewed-by: Akihiko Odaki Message-ID: <20241008125028.1177932-19-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu.c | 72 ++++++++++--------------------------- include/hw/virtio/virtio-gpu.h | 6 +--- include/ui/qemu-pixman.h | 24 ++++++++++++- include/ui/surface.h | 20 ++++------- ui/console.c | 80 ++++++++++++++---------------------------- ui/dbus-listener.c | 12 +++---- ui/qemu-pixman.c | 68 ++++++++++++++++++++++++++++++----- 7 files changed, 142 insertions(+), 140 deletions(-) (limited to 'hw/display/virtio-gpu.c') diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 23ebefa59c..49fd803393 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -239,20 +239,6 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat, return height * stride; } -static void -resource_set_image_destroy(struct virtio_gpu_simple_resource *res) -{ - if (!res) { - return; - } -#ifdef WIN32 - void *data = res->handle; -#else - void *data = GINT_TO_POINTER(res->shmfd); -#endif - pixman_image_set_destroy_function(res->image, qemu_pixman_shared_image_destroy, data); -} - static void virtio_gpu_resource_create_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -299,21 +285,17 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height); if (res->hostmem + g->hostmem < g->conf_max_hostmem) { - void *bits = NULL; -#ifdef WIN32 - bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); -#else - bits = qemu_memfd_alloc("virtio-gpu-res", res->hostmem, 0, &res->shmfd, &error_warn); -#endif - if (!bits) { + if (!qemu_pixman_image_new_shareable( + &res->image, + &res->share_handle, + "virtio-gpu res", + pformat, + c2d.width, + c2d.height, + c2d.height ? res->hostmem / c2d.height : 0, + &error_warn)) { goto end; } - res->image = pixman_image_create_bits( - pformat, - c2d.width, - c2d.height, - bits, c2d.height ? res->hostmem / c2d.height : 0); - resource_set_image_destroy(res); } end: @@ -687,11 +669,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g, /* realloc the surface ptr */ scanout->ds = qemu_create_displaysurface_pixman(rect); -#ifdef WIN32 - qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset); -#else - qemu_displaysurface_set_shmfd(scanout->ds, res->shmfd, fb->offset); -#endif + qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, fb->offset); pixman_image_unref(rect); dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con, @@ -1287,7 +1265,6 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, VirtIOGPU *g = opaque; struct virtio_gpu_simple_resource *res; uint32_t resource_id, pformat; - void *bits = NULL; int i; g->hostmem = 0; @@ -1314,24 +1291,17 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, } res->hostmem = calc_image_hostmem(pformat, res->width, res->height); -#ifdef WIN32 - bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); -#else - bits = qemu_memfd_alloc("virtio-gpu-res", res->hostmem, 0, &res->shmfd, &error_warn); -#endif - if (!bits) { - g_free(res); - return -EINVAL; - } - res->image = pixman_image_create_bits( - pformat, - res->width, res->height, - bits, res->height ? res->hostmem / res->height : 0); - if (!res->image) { + if (!qemu_pixman_image_new_shareable(&res->image, + &res->share_handle, + "virtio-gpu res", + pformat, + res->width, + res->height, + res->height ? res->hostmem / res->height : 0, + &error_warn)) { g_free(res); return -EINVAL; } - resource_set_image_destroy(res); res->addrs = g_new(uint64_t, res->iov_cnt); res->iov = g_new(struct iovec, res->iov_cnt); @@ -1464,11 +1434,7 @@ static int virtio_gpu_post_load(void *opaque, int version_id) return -EINVAL; } scanout->ds = qemu_create_displaysurface_pixman(res->image); -#ifdef WIN32 - qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0); -#else - qemu_displaysurface_set_shmfd(scanout->ds, res->shmfd, 0); -#endif + qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, 0); dpy_gfx_replace_surface(scanout->con, scanout->ds); } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7509d13265..e343110e23 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -51,11 +51,7 @@ struct virtio_gpu_simple_resource { unsigned int iov_cnt; uint32_t scanout_bitmask; pixman_image_t *image; -#ifdef WIN32 - HANDLE handle; -#else - int shmfd; -#endif + qemu_pixman_shareable share_handle; uint64_t hostmem; uint64_t blob_size; diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index a97f56d09a..193bc046d1 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -12,6 +12,8 @@ #include "pixman-minimal.h" #endif +#include "qapi/error.h" + /* * pixman image formats are defined to be native endian, * that means host byte order on qemu. So we go define @@ -97,7 +99,27 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph, void qemu_pixman_image_unref(pixman_image_t *image); -void qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data); +#ifdef WIN32 +typedef HANDLE qemu_pixman_shareable; +#define SHAREABLE_NONE (NULL) +#define SHAREABLE_TO_PTR(handle) (handle) +#define PTR_TO_SHAREABLE(ptr) (ptr) +#else +typedef int qemu_pixman_shareable; +#define SHAREABLE_NONE (-1) +#define SHAREABLE_TO_PTR(handle) GINT_TO_POINTER(handle) +#define PTR_TO_SHAREABLE(ptr) GPOINTER_TO_INT(ptr) +#endif + +bool qemu_pixman_image_new_shareable( + pixman_image_t **image, + qemu_pixman_shareable *handle, + const char *name, + pixman_format_code_t format, + int width, + int height, + int rowstride_bytes, + Error **errp); G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref) diff --git a/include/ui/surface.h b/include/ui/surface.h index 37d03be4af..f16f7be8be 100644 --- a/include/ui/surface.h +++ b/include/ui/surface.h @@ -23,13 +23,8 @@ typedef struct DisplaySurface { GLenum gltype; GLuint texture; #endif -#ifdef WIN32 - HANDLE handle; - uint32_t handle_offset; -#else - int shmfd; - uint32_t shmfd_offset; -#endif + qemu_pixman_shareable share_handle; + uint32_t share_handle_offset; } DisplaySurface; PixelFormat qemu_default_pixelformat(int bpp); @@ -40,13 +35,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image); DisplaySurface *qemu_create_placeholder_surface(int w, int h, const char *msg); -#ifdef WIN32 -void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, - HANDLE h, uint32_t offset); -#else -void qemu_displaysurface_set_shmfd(DisplaySurface *surface, - int shmfd, uint32_t offset); -#endif + +void qemu_displaysurface_set_share_handle(DisplaySurface *surface, + qemu_pixman_shareable handle, + uint32_t offset); DisplaySurface *qemu_create_displaysurface(int width, int height); void qemu_free_displaysurface(DisplaySurface *surface); diff --git a/ui/console.c b/ui/console.c index 3a2aaba3c7..5165f17125 100644 --- a/ui/console.c +++ b/ui/console.c @@ -453,61 +453,26 @@ qemu_graphic_console_init(Object *obj) { } -#ifdef WIN32 -void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, - HANDLE h, uint32_t offset) +void qemu_displaysurface_set_share_handle(DisplaySurface *surface, + qemu_pixman_shareable handle, + uint32_t offset) { - assert(!surface->handle); + assert(surface->share_handle == SHAREABLE_NONE); - surface->handle = h; - surface->handle_offset = offset; -} -#else -void qemu_displaysurface_set_shmfd(DisplaySurface *surface, - int shmfd, uint32_t offset) -{ - assert(surface->shmfd == -1); + surface->share_handle = handle; + surface->share_handle_offset = offset; - surface->shmfd = shmfd; - surface->shmfd_offset = offset; } -#endif DisplaySurface *qemu_create_displaysurface(int width, int height) { - DisplaySurface *surface; - void *bits = NULL; -#ifdef WIN32 - HANDLE handle = NULL; -#else - int shmfd = -1; -#endif - trace_displaysurface_create(width, height); -#ifdef WIN32 - bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort); -#else - bits = qemu_memfd_alloc("displaysurface", width * height * 4, 0, &shmfd, &error_abort); -#endif - - surface = qemu_create_displaysurface_from( + return qemu_create_displaysurface_from( width, height, PIXMAN_x8r8g8b8, - width * 4, bits + width * 4, NULL ); - surface->flags = QEMU_ALLOCATED_FLAG; - -#ifdef WIN32 - qemu_displaysurface_win32_set_handle(surface, handle, 0); - void *data = handle; -#else - qemu_displaysurface_set_shmfd(surface, shmfd, 0); - void *data = GINT_TO_POINTER(shmfd); -#endif - pixman_image_set_destroy_function(surface->image, qemu_pixman_shared_image_destroy, data); - - return surface; } DisplaySurface *qemu_create_displaysurface_from(int width, int height, @@ -517,14 +482,25 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, DisplaySurface *surface = g_new0(DisplaySurface, 1); trace_displaysurface_create_from(surface, width, height, format); -#ifndef WIN32 - surface->shmfd = -1; -#endif - surface->image = pixman_image_create_bits(format, - width, height, - (void *)data, linesize); - assert(surface->image != NULL); + surface->share_handle = SHAREABLE_NONE; + if (data) { + surface->image = pixman_image_create_bits(format, + width, height, + (void *)data, linesize); + } else { + qemu_pixman_image_new_shareable(&surface->image, + &surface->share_handle, + "displaysurface", + format, + width, + height, + linesize, + &error_abort); + surface->flags = QEMU_ALLOCATED_FLAG; + } + + assert(surface->image != NULL); return surface; } @@ -533,9 +509,7 @@ DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image) DisplaySurface *surface = g_new0(DisplaySurface, 1); trace_displaysurface_create_pixman(surface); -#ifndef WIN32 - surface->shmfd = -1; -#endif + surface->share_handle = SHAREABLE_NONE; surface->image = pixman_image_ref(image); return surface; diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index ec47946282..99738e769b 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -336,13 +336,13 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl) return true; } - if (!ddl->can_share_map || !ddl->ds->handle) { + if (!ddl->can_share_map || !ddl->ds->share_handle) { return false; } success = DuplicateHandle( GetCurrentProcess(), - ddl->ds->handle, + ddl->ds->share_handle, ddl->peer_process, &target_handle, FILE_MAP_READ | SECTION_QUERY, @@ -359,7 +359,7 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl) if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync( ddl->map_proxy, GPOINTER_TO_UINT(target_handle), - ddl->ds->handle_offset, + ddl->ds->share_handle_offset, surface_width(ddl->ds), surface_height(ddl->ds), surface_stride(ddl->ds), @@ -453,13 +453,13 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl) return true; } - if (!ddl->can_share_map || ddl->ds->shmfd == -1) { + if (!ddl->can_share_map || ddl->ds->share_handle == SHAREABLE_NONE) { return false; } ddl_discard_display_messages(ddl); fd_list = g_unix_fd_list_new(); - if (g_unix_fd_list_append(fd_list, ddl->ds->shmfd, &err) != 0) { + if (g_unix_fd_list_append(fd_list, ddl->ds->share_handle, &err) != 0) { g_debug("Failed to setup scanout map fdlist: %s", err->message); ddl->can_share_map = false; return false; @@ -468,7 +468,7 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl) if (!qemu_dbus_display1_listener_unix_map_call_scanout_map_sync( ddl->map_proxy, g_variant_new_handle(0), - ddl->ds->shmfd_offset, + ddl->ds->share_handle_offset, surface_width(ddl->ds), surface_height(ddl->ds), surface_stride(ddl->ds), diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 46a91e7f7a..6ef4376f4e 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -270,19 +270,71 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph, } #endif /* CONFIG_PIXMAN */ -void -qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data) +static void * +qemu_pixman_shareable_alloc(const char *name, size_t size, + qemu_pixman_shareable *handle, + Error **errp) { - void *ptr = pixman_image_get_data(image); - #ifdef WIN32 - HANDLE handle = data; + return qemu_win32_map_alloc(size, handle, errp); +#else + return qemu_memfd_alloc(name, size, 0, handle, errp); +#endif +} +static void +qemu_pixman_shareable_free(qemu_pixman_shareable handle, + void *ptr, size_t size) +{ +#ifdef WIN32 qemu_win32_map_free(ptr, handle, &error_warn); #else - int shmfd = GPOINTER_TO_INT(data); + qemu_memfd_free(ptr, size, handle); +#endif +} + +static void +qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data) +{ + qemu_pixman_shareable handle = PTR_TO_SHAREABLE(data); + void *ptr = pixman_image_get_data(image); size_t size = pixman_image_get_height(image) * pixman_image_get_stride(image); - qemu_memfd_free(ptr, size, shmfd); -#endif + qemu_pixman_shareable_free(handle, ptr, size); +} + +bool +qemu_pixman_image_new_shareable(pixman_image_t **image, + qemu_pixman_shareable *handle, + const char *name, + pixman_format_code_t format, + int width, + int height, + int rowstride_bytes, + Error **errp) +{ + ERRP_GUARD(); + size_t size = height * rowstride_bytes; + void *bits = NULL; + + g_return_val_if_fail(image != NULL, false); + g_return_val_if_fail(handle != NULL, false); + + bits = qemu_pixman_shareable_alloc(name, size, handle, errp); + if (!bits) { + return false; + } + + *image = pixman_image_create_bits(format, width, height, bits, rowstride_bytes); + if (!*image) { + error_setg(errp, "Failed to allocate image"); + qemu_pixman_shareable_free(*handle, bits, size); + return false; + } + + pixman_image_set_destroy_function(*image, + qemu_pixman_shared_image_destroy, + SHAREABLE_TO_PTR(*handle)); + + return true; } -- cgit 1.4.1