From: Wei Liu <[email protected]>

Query Hyper-V dynamic processor features during mshv initialization to
determine SEV-SNP availability, and report the result: on success log the
maximum number of encrypted partitions, otherwise log the decoded SNP
status string so misconfigurations are diagnosable. Cloud Hypervisor
expects the root driver to perform this capability check before SEV-SNP
child partition setup.

Signed-off-by: Wei Liu <[email protected]>
---
 drivers/hv/mshv_root_main.c | 96 +++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 8c87dd8e0378..712f45dcef60 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -2705,6 +2705,100 @@ static int mshv_root_scheduler_cleanup(unsigned int cpu)
 }
 
 /* Must be called after retrieving the scheduler type */
+#if defined(__x86_64__)
+static const char *hv_snp_status_to_string(enum hv_snp_status status)
+{
+       switch (status) {
+       case HV_SNP_STATUS_NONE:
+               return "not available";
+       case HV_SNP_STATUS_AVAILABLE:
+               return "available";
+       case HV_SNP_STATUS_INCOMPATIBLE:
+               return "incompatible";
+       case HV_SNP_STATUS_PSP_UNAVAILABLE:
+               return "PSP unavailable";
+       case HV_SNP_STATUS_PSP_INIT_FAILED:
+               return "PSP init failed";
+       case HV_SNP_STATUS_PSP_BAD_FW_VERSION:
+               return "bad PSP firmware version";
+       case HV_SNP_STATUS_BAD_CONFIGURATION:
+               return "bad configuration";
+       case HV_SNP_STATUS_PSP_FW_UPDATE_IN_PROGRESS:
+               return "PSP firmware update in progress";
+       case HV_SNP_STATUS_PSP_RB_INIT_FAILED:
+               return "PSP ring buffer init failed";
+       case HV_SNP_STATUS_PSP_PLATFORM_STATUS_FAILED:
+               return "PSP platform status failed";
+       case HV_SNP_STATUS_PSP_INIT_LATE_FAILED:
+               return "PSP late init failed";
+       default:
+               return "unknown";
+       }
+}
+
+static void mshv_print_max_sev_snp_partitions(struct device *dev)
+{
+       struct hv_input_get_system_property *input;
+       struct hv_output_get_system_property *output;
+       unsigned long flags;
+       u64 status;
+
+       local_irq_save(flags);
+       input = *this_cpu_ptr(hyperv_pcpu_input_arg);
+       output = *this_cpu_ptr(hyperv_pcpu_output_arg);
+
+       memset(input, 0, sizeof(*input));
+       input->property_id = HV_DYNAMIC_PROCESSOR_FEATURE_PROPERTY;
+       input->hv_processor_feature =
+               HV_X64_DYNAMIC_PROCESSOR_FEATURE_MAX_ENCRYPTED_PARTITIONS;
+
+       status = hv_do_hypercall(HVCALL_GET_SYSTEM_PROPERTY, input, output);
+       local_irq_restore(flags);
+       if (!hv_result_success(status)) {
+               dev_warn(dev, "Failed to get max SNP partitions: %s\n",
+                        hv_result_to_string(status));
+               return;
+       }
+
+       dev_info(dev, "Maximum supported SEV-SNP partitions are: %llu\n",
+                output->hv_processor_feature_value);
+}
+
+static void __init mshv_check_sev_snp_support(struct device *dev)
+{
+       struct hv_input_get_system_property *input;
+       struct hv_output_get_system_property *output;
+       unsigned long flags;
+       enum hv_snp_status snp_status;
+       u64 status;
+
+       local_irq_save(flags);
+       input = *this_cpu_ptr(hyperv_pcpu_input_arg);
+       output = *this_cpu_ptr(hyperv_pcpu_output_arg);
+
+       memset(input, 0, sizeof(*input));
+       input->property_id = HV_DYNAMIC_PROCESSOR_FEATURE_PROPERTY;
+       input->hv_processor_feature = 
HV_X64_DYNAMIC_PROCESSOR_FEATURE_SNP_STATUS;
+
+       status = hv_do_hypercall(HVCALL_GET_SYSTEM_PROPERTY, input, output);
+       local_irq_restore(flags);
+       if (!hv_result_success(status)) {
+               dev_warn(dev, "Failed to get SNP support: %s\n",
+                        hv_result_to_string(status));
+               return;
+       }
+
+       snp_status = output->hv_processor_feature_value;
+       dev_info(dev, "SEV-SNP support status: %s (%u)\n",
+                hv_snp_status_to_string(snp_status), snp_status);
+
+       if (snp_status == HV_SNP_STATUS_AVAILABLE)
+               mshv_print_max_sev_snp_partitions(dev);
+}
+#else
+static void __init mshv_check_sev_snp_support(struct device *dev) {}
+#endif
+
 static int
 root_scheduler_init(struct device *dev)
 {
@@ -2808,6 +2902,8 @@ static int __init mshv_parent_partition_init(void)
        if (ret)
                goto synic_cleanup;
 
+       mshv_check_sev_snp_support(dev);
+
        ret = root_scheduler_init(dev);
        if (ret)
                goto synic_cleanup;
-- 
2.43.0


Reply via email to