Commit 9f750794 authored by Brijesh Singh's avatar Brijesh Singh Committed by Paolo Bonzini
Browse files

sev/i386: add sev_get_capabilities()



The function can be used to get the current SEV capabilities.
The capabilities include platform diffie-hellman key (pdh) and certificate
chain. The key can be provided to the external entities which wants to
establish a trusted channel between SEV firmware and guest owner.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: default avatarBrijesh Singh <brijesh.singh@amd.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 31dd67f6
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -717,6 +717,13 @@ SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp)

SevCapability *qmp_query_sev_capabilities(Error **errp)
{
    SevCapability *data;

    data = sev_get_capabilities();
    if (!data) {
        error_setg(errp, "SEV feature is not available");
        return NULL;
    }

    return data;
}
+5 −0
Original line number Diff line number Diff line
@@ -44,3 +44,8 @@ char *sev_get_launch_measurement(void)
{
    return NULL;
}

SevCapability *sev_get_capabilities(void)
{
    return NULL;
}
+83 −0
Original line number Diff line number Diff line
@@ -426,6 +426,89 @@ sev_get_info(void)
    return info;
}

static int
sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
                 size_t *cert_chain_len)
{
    guchar *pdh_data, *cert_chain_data;
    struct sev_user_data_pdh_cert_export export = {};
    int err, r;

    /* query the certificate length */
    r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
    if (r < 0) {
        if (err != SEV_RET_INVALID_LEN) {
            error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
                         r, err, fw_error_to_str(err));
            return 1;
        }
    }

    pdh_data = g_new(guchar, export.pdh_cert_len);
    cert_chain_data = g_new(guchar, export.cert_chain_len);
    export.pdh_cert_address = (unsigned long)pdh_data;
    export.cert_chain_address = (unsigned long)cert_chain_data;

    r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
    if (r < 0) {
        error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
                     r, err, fw_error_to_str(err));
        goto e_free;
    }

    *pdh = pdh_data;
    *pdh_len = export.pdh_cert_len;
    *cert_chain = cert_chain_data;
    *cert_chain_len = export.cert_chain_len;
    return 0;

e_free:
    g_free(pdh_data);
    g_free(cert_chain_data);
    return 1;
}

SevCapability *
sev_get_capabilities(void)
{
    SevCapability *cap;
    guchar *pdh_data, *cert_chain_data;
    size_t pdh_len = 0, cert_chain_len = 0;
    uint32_t ebx;
    int fd;

    fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
    if (fd < 0) {
        error_report("%s: Failed to open %s '%s'", __func__,
                     DEFAULT_SEV_DEVICE, strerror(errno));
        return NULL;
    }

    if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
                         &cert_chain_data, &cert_chain_len)) {
        return NULL;
    }

    cap = g_new0(SevCapability, 1);
    cap->pdh = g_base64_encode(pdh_data, pdh_len);
    cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);

    host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
    cap->cbitpos = ebx & 0x3f;

    /*
     * When SEV feature is enabled, we loose one bit in guest physical
     * addressing.
     */
    cap->reduced_phys_bits = 1;

    g_free(pdh_data);
    g_free(cert_chain_data);

    close(fd);
    return cap;
}

static int
sev_read_file_base64(const char *filename, guchar **data, gsize *len)
{
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ extern SevInfo *sev_get_info(void);
extern uint32_t sev_get_cbit_position(void);
extern uint32_t sev_get_reduced_phys_bits(void);
extern char *sev_get_launch_measurement(void);
extern SevCapability *sev_get_capabilities(void);

typedef struct QSevGuestInfo QSevGuestInfo;
typedef struct QSevGuestInfoClass QSevGuestInfoClass;