:p
atchew
Login
Hi all, I am working to implement virtgpu S3 function on Xen. Currently on Xen, if we start a guest who enables virtgpu, and then run "echo mem > /sys/power/state" to suspend guest. And run "sudo xl trigger <guest id> s3resume" to resume guest. We can find that the guest kernel comes back, but the display doesn't. It just shown a black screen. Through reading codes, I founded that when guest was during suspending, it called into Qemu to call virtio_gpu_gl_reset. In virtio_gpu_gl_reset, it destroyed all resources and reset renderer. This made the display gone after guest resumed. I think we should keep resources or prevent they being destroyed when guest is suspending. So, I add a new status named freezing to virtgpu, and add a new ctrl message VIRTIO_GPU_CMD_STATUS_FREEZING to get notification from guest. If freezing is set to true, and then Qemu will realize that guest is suspending, it will not destroy resources and will not reset renderer. If freezing is set to false, Qemu will do its origin actions, and has no other impaction. And now, display can come back and applications can continue their status after guest resumes. Jiqian Chen (1): virtgpu: do not destroy resources when guest suspend hw/display/virtio-gpu-gl.c | 9 ++++++- hw/display/virtio-gpu-virgl.c | 3 +++ hw/display/virtio-gpu.c | 26 +++++++++++++++++++-- include/hw/virtio/virtio-gpu.h | 3 +++ include/standard-headers/linux/virtio_gpu.h | 9 +++++++ 5 files changed, 47 insertions(+), 3 deletions(-) -- 2.34.1
After suspending and resuming guest VM, you will get a black screen, and the display can't come back. This is because when guest did suspending, it called into qemu to call virtio_gpu_gl_reset. In function virtio_gpu_gl_reset, it destroyed resources and reset renderer, which were used for display. As a result, guest's screen can't come back to the time when it was suspended and only showed black. So, this patch adds a new ctrl message VIRTIO_GPU_CMD_STATUS_FREEZING to get notification from guest. If guest is during suspending, it sets freezing status of virtgpu to true, this will prevent destroying resources and resetting renderer when guest calls into virtio_gpu_gl_reset. If guest is during resuming, it sets freezing to false, and then virtio_gpu_gl_reset will keep its origin actions and has no other impaction. Signed-off-by: Jiqian Chen <Jiqian.Chen@amd.com> --- hw/display/virtio-gpu-gl.c | 9 ++++++- hw/display/virtio-gpu-virgl.c | 3 +++ hw/display/virtio-gpu.c | 26 +++++++++++++++++++-- include/hw/virtio/virtio-gpu.h | 3 +++ include/standard-headers/linux/virtio_gpu.h | 9 +++++++ 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -XXX,XX +XXX,XX @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev) */ if (gl->renderer_inited && !gl->renderer_reset) { virtio_gpu_virgl_reset_scanout(g); - gl->renderer_reset = true; + /* + * If guest is suspending, we shouldn't reset renderer, + * otherwise, the display can't come back to the time when + * it was suspended after guest resumed. + */ + if (!g->freezing) { + gl->renderer_reset = true; + } } } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -XXX,XX +XXX,XX @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, case VIRTIO_GPU_CMD_GET_EDID: virtio_gpu_get_edid(g, cmd); break; + case VIRTIO_GPU_CMD_STATUS_FREEZING: + virtio_gpu_cmd_status_freezing(g, cmd); + break; default: cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; break; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -XXX,XX +XXX,XX @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g, QTAILQ_INSERT_HEAD(&g->reslist, res, next); } +void virtio_gpu_cmd_status_freezing(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_status_freezing sf; + + VIRTIO_GPU_FILL_CMD(sf); + virtio_gpu_bswap_32(&sf, sizeof(sf)); + g->freezing = sf.freezing; +} + static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id) { struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id]; @@ -XXX,XX +XXX,XX @@ void virtio_gpu_simple_process_cmd(VirtIOGPU *g, case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: virtio_gpu_resource_detach_backing(g, cmd); break; + case VIRTIO_GPU_CMD_STATUS_FREEZING: + virtio_gpu_cmd_status_freezing(g, cmd); + break; default: cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; break; @@ -XXX,XX +XXX,XX @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) QTAILQ_INIT(&g->reslist); QTAILQ_INIT(&g->cmdq); QTAILQ_INIT(&g->fenceq); + + g->freezing = false; } void virtio_gpu_reset(VirtIODevice *vdev) @@ -XXX,XX +XXX,XX @@ void virtio_gpu_reset(VirtIODevice *vdev) struct virtio_gpu_simple_resource *res, *tmp; struct virtio_gpu_ctrl_command *cmd; - QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { - virtio_gpu_resource_destroy(g, res); + /* + * If guest is suspending, we shouldn't destroy resources, + * otherwise, the display can't come back to the time when + * it was suspended after guest resumed. + */ + if (!g->freezing) { + QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { + virtio_gpu_resource_destroy(g, res); + } } while (!QTAILQ_EMPTY(&g->cmdq)) { diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -XXX,XX +XXX,XX @@ struct VirtIOGPU { uint64_t hostmem; + bool freezing; bool processing_cmdq; QEMUTimer *fence_poll; QEMUTimer *print_stats; @@ -XXX,XX +XXX,XX @@ void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); +void virtio_gpu_cmd_status_freezing(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd); #endif diff --git a/include/standard-headers/linux/virtio_gpu.h b/include/standard-headers/linux/virtio_gpu.h index XXXXXXX..XXXXXXX 100644 --- a/include/standard-headers/linux/virtio_gpu.h +++ b/include/standard-headers/linux/virtio_gpu.h @@ -XXX,XX +XXX,XX @@ enum virtio_gpu_ctrl_type { VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, + + /* status */ + VIRTIO_GPU_CMD_STATUS_FREEZING = 0x1300, }; enum virtio_gpu_shm_id { @@ -XXX,XX +XXX,XX @@ struct virtio_gpu_resource_unmap_blob { uint32_t padding; }; +/* VIRTIO_GPU_CMD_STATUS_FREEZING */ +struct virtio_gpu_status_freezing { + struct virtio_gpu_ctrl_hdr hdr; + __u32 freezing; +}; + #endif -- 2.34.1
Hi, Not very related to microcode anymore, but this was part of the microcode series, so... v1: https://lore.kernel.org/xen-devel/20251112162219.226075-1-alejandro.garciavallejo@amd.com/ v2: https://lore.kernel.org/xen-devel/20260112150259.74535-1-alejandro.garciavallejo@amd.com/ v3: https://lore.kernel.org/xen-devel/20260113122109.62399-1-alejandro.garciavallejo@amd.com/ v4: https://lore.kernel.org/xen-devel/20260120093852.2380-1-alejandro.garciavallejo@amd.com/ Alejandro Vallejo (2): xen: Allow lib-y targets to also be .init.o earlycpio: lib-ify earlycpio.c docs/misra/exclude-list.json | 4 ---- xen/Rules.mk | 10 +++++----- xen/common/Makefile | 2 +- xen/lib/Makefile | 1 + xen/{common => lib}/earlycpio.c | 0 5 files changed, 7 insertions(+), 10 deletions(-) rename xen/{common => lib}/earlycpio.c (100%) base-commit: 61204ed24ba4537d6eff56594faa5d23cacb8310 -- 2.43.0
There's some assumptions as to which targets may be init-only. But there's little reason to preclude libraries from being init-only. Signed-off-by: Alejandro Vallejo <alejandro.garciavallejo@amd.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> --- xen/Rules.mk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xen/Rules.mk b/xen/Rules.mk index XXXXXXX..XXXXXXX 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -XXX,XX +XXX,XX @@ endif targets += $(targets-for-builtin) -$(filter %.init.o,$(obj-y) $(obj-bin-y) $(extra-y)): CFLAGS-y += -DINIT_SECTIONS_ONLY +$(filter %.init.o,$(obj-y) $(obj-bin-y) $(extra-y) $(lib-y)): CFLAGS-y += -DINIT_SECTIONS_ONLY -non-init-objects = $(filter-out %.init.o, $(obj-y) $(obj-bin-y) $(extra-y)) +non-init-objects = $(filter-out %.init.o, $(obj-y) $(obj-bin-y) $(extra-y) $(lib-y)) ifeq ($(CONFIG_CC_IS_CLANG),y) cov-cflags-$(CONFIG_COVERAGE) := -fprofile-instr-generate -fcoverage-mapping @@ -XXX,XX +XXX,XX @@ endif $(call cc-option-add,cov-cflags-$(CONFIG_COVERAGE),CC,-fprofile-update=atomic) # Reset cov-cflags-y in cases where an objects has another one as prerequisite -$(nocov-y) $(filter %.init.o, $(obj-y) $(obj-bin-y) $(extra-y)): \ +$(nocov-y) $(filter %.init.o, $(obj-y) $(obj-bin-y) $(extra-y) $(lib-y)): \ cov-cflags-y := $(non-init-objects): _c_flags += $(cov-cflags-y) @@ -XXX,XX +XXX,XX @@ ifeq ($(CONFIG_UBSAN),y) UBSAN_FLAGS := $(filter-out -fno-%,$(CFLAGS_UBSAN)) $(filter -fno-%,$(CFLAGS_UBSAN)) # Reset UBSAN_FLAGS in cases where an objects has another one as prerequisite -$(noubsan-y) $(filter %.init.o, $(obj-y) $(obj-bin-y) $(extra-y)): \ +$(noubsan-y) $(filter %.init.o, $(obj-y) $(obj-bin-y) $(extra-y) $(lib-y)): \ UBSAN_FLAGS := $(non-init-objects): _c_flags += $(UBSAN_FLAGS) @@ -XXX,XX +XXX,XX @@ define cmd_obj_init_o $(OBJCOPY) $(foreach s,$(SPECIAL_DATA_SECTIONS),--rename-section .$(s)=.init.$(s)) $< $@ endef -$(filter %.init.o,$(obj-y) $(obj-bin-y) $(extra-y)): $(obj)/%.init.o: $(obj)/%.o FORCE +$(filter %.init.o,$(obj-y) $(obj-bin-y) $(extra-y) $(lib-y)): $(obj)/%.init.o: $(obj)/%.o FORCE $(call if_changed,obj_init_o) quiet_cmd_cpp_i_c = CPP $@ -- 2.43.0
It's only used for microcode loading on x86. By lib-ifying it we can make it go away automatically when microcode loading becomes an optional feature in follow-up patches. The exclude-list.json file goes stale after the move, so remove the entry for earlycpio.c now that it's not included in AMD's build. Its breakages will be fixed in due time and not ignored. Signed-off-by: Alejandro Vallejo <alejandro.garciavallejo@amd.com> Acked-by: Andrew Cooper <andrew.cooper3@citrix.com> # lib-ify only Reviewed-by: Nicola Vetrini <nicola.vetrini@bugseng.com> # exclude-list.json --- docs/misra/exclude-list.json | 4 ---- xen/common/Makefile | 2 +- xen/lib/Makefile | 1 + xen/{common => lib}/earlycpio.c | 0 4 files changed, 2 insertions(+), 5 deletions(-) rename xen/{common => lib}/earlycpio.c (100%) diff --git a/docs/misra/exclude-list.json b/docs/misra/exclude-list.json index XXXXXXX..XXXXXXX 100644 --- a/docs/misra/exclude-list.json +++ b/docs/misra/exclude-list.json @@ -XXX,XX +XXX,XX @@ "rel_path": "common/bunzip2.c", "comment": "Imported from Linux, ignore for now" }, - { - "rel_path": "common/earlycpio.c", - "comment": "Imported from Linux, ignore for now" - }, { "rel_path": "common/gzip/*", "comment": "Imported from Linux, ignore for now" diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += wait.o obj-bin-y += warning.init.o obj-y += xmalloc_tlsf.o -obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma lzo unlzo unlz4 unzstd earlycpio,$(n).init.o) +obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma lzo unlzo unlz4 unzstd,$(n).init.o) obj-$(CONFIG_COMPAT) += $(addprefix compat/,domain.o memory.o multicall.o xlat.o) diff --git a/xen/lib/Makefile b/xen/lib/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/lib/Makefile +++ b/xen/lib/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_X86) += x86/ lib-y += bsearch.o lib-y += ctors.o lib-y += ctype.o +lib-y += earlycpio.init.o lib-y += find-next-bit.o lib-y += generic-ffsl.o lib-y += generic-flsl.o diff --git a/xen/common/earlycpio.c b/xen/lib/earlycpio.c similarity index 100% rename from xen/common/earlycpio.c rename to xen/lib/earlycpio.c -- 2.43.0