From: Wei Liu <[email protected]>

Add wrappers for importing isolated pages, completing the import,
modifying sparse SPA host access, and setting partition properties.
Support synchronous and pending completion and batch repetition calls
within the Hyper-V input page.

Preserve the asynchronous completion result and encode its bounded
repetition count in the standard hypercall status field. Keep the
distinct, currently unused substatus out of the result bits. Return exact
bounded import progress on both success and failure, reject malformed
completion counts, and rate-limit guest-driven failures.

Signed-off-by: Wei Liu <[email protected]>
---
 drivers/hv/mshv_root.h         |  12 ++++
 drivers/hv/mshv_root_hv_call.c | 110 +++++++++++++++++++++++++++++++++
 drivers/hv/mshv_synic.c        |  10 ++-
 3 files changed, 131 insertions(+), 1 deletion(-)

diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index 2150019b588c..a87d9773093c 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -389,6 +389,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, u64 *completed_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 fca2419df397..cb5727529355 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
@@ -1041,6 +1045,112 @@ 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, u64 *completed_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;
+       u64 remaining = num_pages;
+       unsigned long flags;
+       u64 *gpa = pages;
+       u64 completed;
+       u64 status;
+       int rep_count;
+
+       if (!num_pages || !completed_pages)
+               return -EINVAL;
+       *completed_pages = 0;
+
+       if (!completion_handler) {
+               pr_err("%s: missing completion handler, page_type=%u\n",
+                      __func__, page_type);
+               return -EINVAL;
+       }
+
+       while (remaining) {
+               rep_count = min_t(u64, 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);
+
+               if (hv_result(status) == HV_STATUS_CALL_PENDING)
+                       completion_handler(completion_data, &status);
+
+               completed = hv_repcomp(status);
+               if (completed > rep_count) {
+                       pr_err_ratelimited("%s: invalid completion count 
%llu/%d\n",
+                                          __func__, completed, rep_count);
+                       return -EPROTO;
+               }
+               *completed_pages += completed;
+
+               if (!hv_result_success(status)) {
+                       pr_err_ratelimited("%s: completed %llu of %llu, %s\n",
+                                          __func__, *completed_pages, 
num_pages,
+                                          hv_result_to_string(status));
+                       return hv_result_to_errno(status);
+               }
+               if (!completed)
+                       return -EPROTO;
+
+               gpa += completed;
+               remaining -= completed;
+               cond_resched();
+       }
+
+       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_ratelimited("%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,
diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c
index c77688b8d23c..0fdbae1e053c 100644
--- a/drivers/hv/mshv_synic.c
+++ b/drivers/hv/mshv_synic.c
@@ -159,7 +159,15 @@ static bool mshv_async_call_completion_isr(struct 
hv_message *msg)
                goto unlock_out;
        }
 
-       partition->async_hypercall_status = async_msg->status;
+       /* No current completion caller consumes the distinct substatus. */
+       (void)async_msg->sub_status;
+       partition->async_hypercall_status =
+               (u64)async_msg->status & ~HV_HYPERCALL_REP_COMP_MASK;
+       partition->async_hypercall_status |=
+               (min_t(u64, async_msg->completion_count,
+                      HV_HYPERCALL_REP_COMP_MASK >>
+                      HV_HYPERCALL_REP_COMP_OFFSET) <<
+                HV_HYPERCALL_REP_COMP_OFFSET);
        complete(&partition->async_hypercall);
 
        handled = true;
-- 
2.43.0


Reply via email to