summary refs log tree commit diff stats
path: root/target/i386/sev.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-06-01 21:23:26 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-06-01 21:23:26 +0100
commitdd2db39d78431ab5a0b78777afaab3d61e94533e (patch)
treee72d9a1508db872a6bc4218631cf39edf5681ef5 /target/i386/sev.c
parent52848929b70dcf92a68aedcfd90207be81ba3274 (diff)
parentd47b85502b92fe8015d38904cde54eb4d3364326 (diff)
downloadfocaccia-qemu-dd2db39d78431ab5a0b78777afaab3d61e94533e.tar.gz
focaccia-qemu-dd2db39d78431ab5a0b78777afaab3d61e94533e.zip
Merge remote-tracking branch 'remotes/ehabkost-gl/tags/x86-next-pull-request' into staging
x86 queue, 2021-06-01

Features:
* Add CPU model versions supporting 'xsaves' (Vitaly Kuznetsov)
* Support AVX512 ZMM regs dump (Robert Hoo)

Bug fixes:
* Use better matching family/model/stepping for generic CPUs
  (Daniel P. Berrangé)

Cleanups:
* Hyper-V feature initialization cleanup (Vitaly Kuznetsov)
* SEV firmware error list touchups (Connor Kuehl)
* Constify CPUCaches and X86CPUDefinition (Philippe Mathieu-Daudé)
* Document when features can be added to kvm_default_props
  (Eduardo Habkost)

# gpg: Signature made Tue 01 Jun 2021 19:08:33 BST
# gpg:                using RSA key 5A322FD5ABC4D3DBACCFD1AA2807936F984DC5A6
# gpg:                issuer "ehabkost@redhat.com"
# gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>" [full]
# Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF  D1AA 2807 936F 984D C5A6

* remotes/ehabkost-gl/tags/x86-next-pull-request: (24 commits)
  sev: add missing firmware error conditions
  sev: use explicit indices for mapping firmware error codes to strings
  target/i386/sev: add support to query the attestation report
  i386: use global kvm_state in hyperv_enabled() check
  i386: prefer system KVM_GET_SUPPORTED_HV_CPUID ioctl over vCPU's one
  i386: adjust the expected KVM_GET_SUPPORTED_HV_CPUID array size
  i386: switch hyperv_expand_features() to using error_setg()
  i386: move eVMCS enablement to hyperv_init_vcpu()
  i386: split hyperv_handle_properties() into hyperv_expand_features()/hyperv_fill_cpuids()
  i386: introduce hv_cpuid_cache
  i386: drop FEAT_HYPERV feature leaves
  i386: introduce hv_cpuid_get_host()
  i386: introduce hyperv_feature_supported()
  i386: stop using env->features[] for filling Hyper-V CPUIDs
  i386: always fill Hyper-V CPUID feature leaves from X86CPU data
  i386: invert hyperv_spinlock_attempts setting logic with hv_passthrough
  i386: keep hyperv_vendor string up-to-date
  i386: use better matching family/model/stepping for 'max' CPU
  i386: use better matching family/model/stepping for 'qemu64' CPU
  i386/cpu_dump: support AVX512 ZMM regs dump
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/i386/sev.c')
-rw-r--r--target/i386/sev.c115
1 files changed, 92 insertions, 23 deletions
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 41f7800b5f..83df8c09f6 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -87,29 +87,31 @@ static SevGuestState *sev_guest;
 static Error *sev_mig_blocker;
 
 static const char *const sev_fw_errlist[] = {
-    "",
-    "Platform state is invalid",
-    "Guest state is invalid",
-    "Platform configuration is invalid",
-    "Buffer too small",
-    "Platform is already owned",
-    "Certificate is invalid",
-    "Policy is not allowed",
-    "Guest is not active",
-    "Invalid address",
-    "Bad signature",
-    "Bad measurement",
-    "Asid is already owned",
-    "Invalid ASID",
-    "WBINVD is required",
-    "DF_FLUSH is required",
-    "Guest handle is invalid",
-    "Invalid command",
-    "Guest is active",
-    "Hardware error",
-    "Hardware unsafe",
-    "Feature not supported",
-    "Invalid parameter"
+    [SEV_RET_SUCCESS]                = "",
+    [SEV_RET_INVALID_PLATFORM_STATE] = "Platform state is invalid",
+    [SEV_RET_INVALID_GUEST_STATE]    = "Guest state is invalid",
+    [SEV_RET_INAVLID_CONFIG]         = "Platform configuration is invalid",
+    [SEV_RET_INVALID_LEN]            = "Buffer too small",
+    [SEV_RET_ALREADY_OWNED]          = "Platform is already owned",
+    [SEV_RET_INVALID_CERTIFICATE]    = "Certificate is invalid",
+    [SEV_RET_POLICY_FAILURE]         = "Policy is not allowed",
+    [SEV_RET_INACTIVE]               = "Guest is not active",
+    [SEV_RET_INVALID_ADDRESS]        = "Invalid address",
+    [SEV_RET_BAD_SIGNATURE]          = "Bad signature",
+    [SEV_RET_BAD_MEASUREMENT]        = "Bad measurement",
+    [SEV_RET_ASID_OWNED]             = "ASID is already owned",
+    [SEV_RET_INVALID_ASID]           = "Invalid ASID",
+    [SEV_RET_WBINVD_REQUIRED]        = "WBINVD is required",
+    [SEV_RET_DFFLUSH_REQUIRED]       = "DF_FLUSH is required",
+    [SEV_RET_INVALID_GUEST]          = "Guest handle is invalid",
+    [SEV_RET_INVALID_COMMAND]        = "Invalid command",
+    [SEV_RET_ACTIVE]                 = "Guest is active",
+    [SEV_RET_HWSEV_RET_PLATFORM]     = "Hardware error",
+    [SEV_RET_HWSEV_RET_UNSAFE]       = "Hardware unsafe",
+    [SEV_RET_UNSUPPORTED]            = "Feature not supported",
+    [SEV_RET_INVALID_PARAM]          = "Invalid parameter",
+    [SEV_RET_RESOURCE_LIMIT]         = "Required firmware resource depleted",
+    [SEV_RET_SECURE_DATA_INVALID]    = "Part-specific integrity check failure",
 };
 
 #define SEV_FW_MAX_ERROR      ARRAY_SIZE(sev_fw_errlist)
@@ -492,6 +494,73 @@ out:
     return cap;
 }
 
+SevAttestationReport *
+sev_get_attestation_report(const char *mnonce, Error **errp)
+{
+    struct kvm_sev_attestation_report input = {};
+    SevAttestationReport *report = NULL;
+    SevGuestState *sev = sev_guest;
+    guchar *data;
+    guchar *buf;
+    gsize len;
+    int err = 0, ret;
+
+    if (!sev_enabled()) {
+        error_setg(errp, "SEV is not enabled");
+        return NULL;
+    }
+
+    /* lets decode the mnonce string */
+    buf = g_base64_decode(mnonce, &len);
+    if (!buf) {
+        error_setg(errp, "SEV: failed to decode mnonce input");
+        return NULL;
+    }
+
+    /* verify the input mnonce length */
+    if (len != sizeof(input.mnonce)) {
+        error_setg(errp, "SEV: mnonce must be %zu bytes (got %" G_GSIZE_FORMAT ")",
+                sizeof(input.mnonce), len);
+        g_free(buf);
+        return NULL;
+    }
+
+    /* Query the report length */
+    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
+            &input, &err);
+    if (ret < 0) {
+        if (err != SEV_RET_INVALID_LEN) {
+            error_setg(errp, "failed to query the attestation report length "
+                    "ret=%d fw_err=%d (%s)", ret, err, fw_error_to_str(err));
+            g_free(buf);
+            return NULL;
+        }
+    }
+
+    data = g_malloc(input.len);
+    input.uaddr = (unsigned long)data;
+    memcpy(input.mnonce, buf, sizeof(input.mnonce));
+
+    /* Query the report */
+    ret = sev_ioctl(sev->sev_fd, KVM_SEV_GET_ATTESTATION_REPORT,
+            &input, &err);
+    if (ret) {
+        error_setg_errno(errp, errno, "Failed to get attestation report"
+                " ret=%d fw_err=%d (%s)", ret, err, fw_error_to_str(err));
+        goto e_free_data;
+    }
+
+    report = g_new0(SevAttestationReport, 1);
+    report->data = g_base64_encode(data, input.len);
+
+    trace_kvm_sev_attestation_report(mnonce, report->data);
+
+e_free_data:
+    g_free(data);
+    g_free(buf);
+    return report;
+}
+
 static int
 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
 {