[PATCH v1 03/13] mshv: add SEV-SNP isolated page hypercalls

From: Wei Hu

Date: Fri Aug 07 2026 - 10:13:01 EST


From: Wei Liu <wei.liu@xxxxxxxxxx>

Add helpers for importing isolated pages and completing isolated
imports. These are used by SEV-SNP guest launch flows to transfer
isolated page state to the hypervisor.

Signed-off-by: Wei Liu <wei.liu@xxxxxxxxxx>
---
drivers/hv/mshv_root.h | 12 +++++
drivers/hv/mshv_root_hv_call.c | 97 ++++++++++++++++++++++++++++++++++
2 files changed, 109 insertions(+)

diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index 8abb080938fd..69226179cfbf 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -379,6 +379,18 @@ void mshv_region_movable_fini(struct mshv_mem_region *region);
bool mshv_region_movable_init(struct mshv_mem_region *region);

#ifdef HV_SUPPORTS_SEV_SNP_GUESTS
+int hv_call_import_isolated_pages(u64 partition_id, u64 *pages,
+ u64 num_pages,
+ enum hv_isolated_page_type page_type,
+ enum hv_isolated_page_size page_size,
+ void (*completion_handler)(void *data,
+ u64 *status),
+ void *completion_data);
+int hv_call_complete_isolated_import(u64 partition_id,
+ union hv_partition_complete_isolated_import_data *import_data,
+ void (*completion_handler)(void *data,
+ u64 *status),
+ void *completion_data);
int hv_call_issue_psp_guest_request(u64 partition_id, u64 req_pfn,
u64 rsp_pfn,
void (*completion_handler)(void *data,
diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
index 48abe338c06f..9ddc8dd73da7 100644
--- a/drivers/hv/mshv_root_hv_call.c
+++ b/drivers/hv/mshv_root_hv_call.c
@@ -14,6 +14,10 @@

#include "mshv_root.h"

+#define HV_ISOLATED_PAGE_BATCH_SIZE \
+ ((HV_HYP_PAGE_SIZE - sizeof(struct hv_input_import_isolated_pages)) / \
+ sizeof(u64))
+
/* Determined empirically */
#define HV_INIT_PARTITION_DEPOSIT_PAGES 208
#define HV_MAP_GPA_DEPOSIT_PAGES 256
@@ -1010,6 +1014,99 @@ int hv_unmap_stats_page(enum hv_stats_object_type type,
}

#ifdef HV_SUPPORTS_SEV_SNP_GUESTS
+int hv_call_import_isolated_pages(u64 partition_id, u64 *pages,
+ u64 num_pages,
+ enum hv_isolated_page_type page_type,
+ enum hv_isolated_page_size page_size,
+ void (*completion_handler)(void *data,
+ u64 *status),
+ void *completion_data)
+{
+ struct hv_input_import_isolated_pages *input;
+ unsigned long remaining = num_pages;
+ unsigned long flags;
+ u64 *gpa = pages;
+ u64 completed;
+ u64 status;
+ int rep_count;
+
+ if (!num_pages)
+ return -EINVAL;
+
+ if (!completion_handler) {
+ pr_err("%s: missing completion handler, page_type=%u\n",
+ __func__, page_type);
+ return -EINVAL;
+ }
+
+ while (remaining) {
+ rep_count = min_t(unsigned long, remaining,
+ HV_ISOLATED_PAGE_BATCH_SIZE);
+
+ local_irq_save(flags);
+ input = *this_cpu_ptr(hyperv_pcpu_input_arg);
+ memset(input, 0, sizeof(*input));
+ input->partition_id = partition_id;
+ input->page_type = page_type;
+ input->page_size = page_size;
+ memcpy(input->page_number, gpa, rep_count * sizeof(*gpa));
+ status = hv_do_rep_hypercall(HVCALL_IMPORT_ISOLATED_PAGES,
+ rep_count, 0, input, NULL);
+ local_irq_restore(flags);
+
+ completed = hv_repcomp(status);
+ if (hv_result(status) == HV_STATUS_CALL_PENDING)
+ completion_handler(completion_data, &status);
+
+ if (!hv_result_success(status)) {
+ pr_err("%s: completed %llu of %llu, %s\n", __func__,
+ num_pages - remaining, num_pages,
+ hv_result_to_string(status));
+ return hv_result_to_errno(status);
+ }
+
+ gpa += completed;
+ remaining -= completed;
+ }
+
+ return 0;
+}
+
+int hv_call_complete_isolated_import(u64 partition_id,
+ union hv_partition_complete_isolated_import_data *import_data,
+ void (*completion_handler)(void *data,
+ u64 *status),
+ void *completion_data)
+{
+ struct hv_input_complete_isolated_import *input;
+ unsigned long flags;
+ u64 status;
+
+ if (!completion_handler) {
+ pr_err("%s: missing completion handler\n", __func__);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+ input = *this_cpu_ptr(hyperv_pcpu_input_arg);
+ memset(input, 0, sizeof(*input));
+ input->partition_id = partition_id;
+ input->import_data = *import_data;
+ status = hv_do_hypercall(HVCALL_COMPLETE_ISOLATED_IMPORT, input, NULL);
+ local_irq_restore(flags);
+
+ if (hv_result(status) == HV_STATUS_CALL_PENDING)
+ completion_handler(completion_data, &status);
+
+ if (!hv_result_success(status)) {
+ pr_err("%s: status=%s partition_id=%llu\n", __func__,
+ hv_result_to_string(status), partition_id);
+ return hv_result_to_errno(status);
+ }
+
+ return 0;
+}
+
int hv_call_issue_psp_guest_request(u64 partition_id, u64 req_pfn,
u64 rsp_pfn,
void (*completion_handler)(void *data,
--
2.43.0