From 93de2a6a4b91b72607136dd656edf03fb399d27f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 23 Sep 2026 09:37:21 -0700 Subject: KVM: SEV: Do cache maintenance on the source VM during intra-host migration Manually perform cache maintenance on the source VM during intra-host migration to ensure no stale data is left in CPU caches after the VM is destroyed. Because the source VM is "converted" to a non-SEV VM, KVM's memory reclaim flows won't trigger cache maintenance, e.g. when all guest memory is reclaimed in response to detaching from the mmu_notifier. Note, relying on the destination VM to do cache maintenance isn't an option as KVM doesn't require identical guest memory configurations, i.e. the source VM may have access to memory that the destination VM does not. Enforcing equivalent memory configurations is infeasible, as it would require a *deep* comparison of memslots, e.g. to verify that not only are the memslot identical, but what the memslots point at is also identical. Fixes: b56639318bb2 ("KVM: SEV: Add support for SEV intra host migration") Cc: stable@vger.kernel.org Reported-by: Stefan Teodorescu Signed-off-by: Sean Christopherson Message-ID: <20260923163721.1584779-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- sound/soc/sof/sof-client-probes-ipc3.c | 258 +++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 sound/soc/sof/sof-client-probes-ipc3.c (limited to 'sound/soc/sof/sof-client-probes-ipc3.c') diff --git a/sound/soc/sof/sof-client-probes-ipc3.c b/sound/soc/sof/sof-client-probes-ipc3.c new file mode 100644 index 000000000..a3e382d61 --- /dev/null +++ b/sound/soc/sof/sof-client-probes-ipc3.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2019-2022 Intel Corporation +// +// Author: Cezary Rojewski +// +// Code moved to this file by: +// Jyri Sarha +// + +#include +#include +#include +#include "sof-client.h" +#include "sof-client-probes.h" + +struct sof_probe_dma { + unsigned int stream_tag; + unsigned int dma_buffer_size; +} __packed; + +struct sof_ipc_probe_dma_add_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + struct sof_probe_dma dma[]; +} __packed; + +struct sof_ipc_probe_info_params { + struct sof_ipc_reply rhdr; + unsigned int num_elems; + union { + DECLARE_FLEX_ARRAY(struct sof_probe_dma, dma); + DECLARE_FLEX_ARRAY(struct sof_probe_point_desc, desc); + }; +} __packed; + +struct sof_ipc_probe_point_add_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + struct sof_probe_point_desc desc[]; +} __packed; + +struct sof_ipc_probe_point_remove_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + unsigned int buffer_id[]; +} __packed; + +/** + * ipc3_probes_init - initialize data probing + * @cdev: SOF client device + * @stream_tag: Extractor stream tag + * @buffer_size: DMA buffer size to set for extractor + * + * Host chooses whether extraction is supported or not by providing + * valid stream tag to DSP. Once specified, stream described by that + * tag will be tied to DSP for extraction for the entire lifetime of + * probe. + * + * Probing is initialized only once and each INIT request must be + * matched by DEINIT call. + */ +static int ipc3_probes_init(struct sof_client_dev *cdev, u32 stream_tag, + size_t buffer_size) +{ + struct sof_ipc_probe_dma_add_params *msg; + size_t size = struct_size(msg, dma, 1); + int ret; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + msg->hdr.size = size; + msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT; + msg->num_elems = 1; + msg->dma[0].stream_tag = stream_tag; + msg->dma[0].dma_buffer_size = buffer_size; + + ret = sof_client_ipc_tx_message_no_reply(cdev, msg); + kfree(msg); + return ret; +} + +/** + * ipc3_probes_deinit - cleanup after data probing + * @cdev: SOF client device + * + * Host sends DEINIT request to free previously initialized probe + * on DSP side once it is no longer needed. DEINIT only when there + * are no probes connected and with all injectors detached. + */ +static int ipc3_probes_deinit(struct sof_client_dev *cdev) +{ + struct sof_ipc_cmd_hdr msg; + + msg.size = sizeof(msg); + msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT; + + return sof_client_ipc_tx_message_no_reply(cdev, &msg); +} + +static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd, + void **params, size_t *num_params, + enum sof_probe_info_type type) +{ + size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev); + struct device *dev = &cdev->auxdev.dev; + struct sof_ipc_probe_info_params msg = {{{0}}}; + struct sof_ipc_probe_info_params *reply; + size_t bytes, elem_size, payload_size; + int ret; + + *params = NULL; + *num_params = 0; + + if (type != PROBES_INFO_ACTIVE_PROBES) { + dev_err(dev, "%s: info type %u not supported", __func__, type); + return -EOPNOTSUPP; + } + + reply = kzalloc(max_msg_size, GFP_KERNEL); + if (!reply) + return -ENOMEM; + msg.rhdr.hdr.size = sizeof(msg); + msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd; + + ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size); + if (ret < 0 || reply->rhdr.error < 0) + goto exit; + + payload_size = reply->rhdr.hdr.size; + if (payload_size < offsetof(struct sof_ipc_probe_info_params, dma)) { + ret = -EINVAL; + goto exit; + } + + if (!reply->num_elems) + goto exit; + + if (cmd == SOF_IPC_PROBE_DMA_INFO) + elem_size = sizeof(reply->dma[0]); + else + elem_size = sizeof(reply->desc[0]); + + payload_size -= offsetof(struct sof_ipc_probe_info_params, dma); + if (reply->num_elems > payload_size / elem_size) { + dev_err(dev, "%s: invalid probe info element count %u\n", + __func__, reply->num_elems); + ret = -EINVAL; + goto exit; + } + + bytes = reply->num_elems * elem_size; + *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL); + if (!*params) { + ret = -ENOMEM; + goto exit; + } + *num_params = reply->num_elems; + +exit: + kfree(reply); + return ret; +} + +/** + * ipc3_probes_points_info - retrieve list of probe points + * @cdev: SOF client device + * @desc: Returned list of active probes + * @num_desc: Returned count of active probes + * @type: Either PROBES_INFO_ACTIVE_PROBES or PROBES_INFO_AVAILABE_PROBES + * + * If type is PROBES_INFO_ACTIVE_PROBES, host sends PROBE_POINT_INFO + * request to obtain list of active probe points, valid for + * disconnection when given probe is no longer required. + * + * Type PROBES_INFO_AVAILABE_PROBES is not yet supported. + */ +static int ipc3_probes_points_info(struct sof_client_dev *cdev, + struct sof_probe_point_desc **desc, + size_t *num_desc, + enum sof_probe_info_type type) +{ + return ipc3_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO, + (void **)desc, num_desc, type); +} + +/** + * ipc3_probes_points_add - connect specified probes + * @cdev: SOF client device + * @desc: List of probe points to connect + * @num_desc: Number of elements in @desc + * + * Dynamically connects to provided set of endpoints. Immediately + * after connection is established, host must be prepared to + * transfer data from or to target stream given the probing purpose. + * + * Each probe point should be removed using PROBE_POINT_REMOVE + * request when no longer needed. + */ +static int ipc3_probes_points_add(struct sof_client_dev *cdev, + struct sof_probe_point_desc *desc, + size_t num_desc) +{ + struct sof_ipc_probe_point_add_params *msg; + size_t size = struct_size(msg, desc, num_desc); + int ret; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + msg->hdr.size = size; + msg->num_elems = num_desc; + msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD; + memcpy(&msg->desc[0], desc, size - sizeof(*msg)); + + ret = sof_client_ipc_tx_message_no_reply(cdev, msg); + kfree(msg); + return ret; +} + +/** + * ipc3_probes_points_remove - disconnect specified probes + * @cdev: SOF client device + * @buffer_id: List of probe points to disconnect + * @num_buffer_id: Number of elements in @desc + * + * Removes previously connected probes from list of active probe + * points and frees all resources on DSP side. + */ +static int ipc3_probes_points_remove(struct sof_client_dev *cdev, + unsigned int *buffer_id, + size_t num_buffer_id) +{ + struct sof_ipc_probe_point_remove_params *msg; + size_t size = struct_size(msg, buffer_id, num_buffer_id); + int ret; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + msg->hdr.size = size; + msg->num_elems = num_buffer_id; + msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE; + memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg)); + + ret = sof_client_ipc_tx_message_no_reply(cdev, msg); + kfree(msg); + return ret; +} + +const struct sof_probes_ipc_ops ipc3_probe_ops = { + .init = ipc3_probes_init, + .deinit = ipc3_probes_deinit, + .points_info = ipc3_probes_points_info, + .points_add = ipc3_probes_points_add, + .points_remove = ipc3_probes_points_remove, +}; -- cgit v1.3.1