| .. SPDX-License-Identifier: GPL-2.0 | |
| =================================================================== | |
| The Definitive SEV Guest API Documentation | |
| =================================================================== | |
| 1. General description | |
| ====================== | |
| The SEV API is a set of ioctls that are used by the guest or hypervisor | |
| to get or set a certain aspect of the SEV virtual machine. The ioctls belong | |
| to the following classes: | |
| - Hypervisor ioctls: These query and set global attributes which affect the | |
| whole SEV firmware. These ioctl are used by platform provisioning tools. | |
| - Guest ioctls: These query and set attributes of the SEV virtual machine. | |
| 2. API description | |
| ================== | |
| This section describes ioctls that is used for querying the SEV guest report | |
| from the SEV firmware. For each ioctl, the following information is provided | |
| along with a description: | |
| Technology: | |
| which SEV technology provides this ioctl. SEV, SEV-ES, SEV-SNP or all. | |
| Type: | |
| hypervisor or guest. The ioctl can be used inside the guest or the | |
| hypervisor. | |
| Parameters: | |
| what parameters are accepted by the ioctl. | |
| Returns: | |
| the return value. General error numbers (-ENOMEM, -EINVAL) | |
| are not detailed, but errors with specific meanings are. | |
| The guest ioctl should be issued on a file descriptor of the /dev/sev-guest | |
| device. The ioctl accepts struct snp_user_guest_request. The input and | |
| output structure is specified through the req_data and resp_data field | |
| respectively. If the ioctl fails to execute due to a firmware error, then | |
| the fw_error code will be set, otherwise fw_error will be set to -1. | |
| The firmware checks that the message sequence counter is one greater than | |
| the guests message sequence counter. If guest driver fails to increment message | |
| counter (e.g. counter overflow), then -EIO will be returned. | |
| :: | |
| struct snp_guest_request_ioctl { | |
| /* Message version number */ | |
| __u32 msg_version; | |
| /* Request and response structure address */ | |
| __u64 req_data; | |
| __u64 resp_data; | |
| /* bits[63:32]: VMM error code, bits[31:0] firmware error code (see psp-sev.h) */ | |
| union { | |
| __u64 exitinfo2; | |
| struct { | |
| __u32 fw_error; | |
| __u32 vmm_error; | |
| }; | |
| }; | |
| }; | |
| The host ioctls are issued to a file descriptor of the /dev/sev device. | |
| The ioctl accepts the command ID/input structure documented below. | |
| :: | |
| struct sev_issue_cmd { | |
| /* Command ID */ | |
| __u32 cmd; | |
| /* Command request structure */ | |
| __u64 data; | |
| /* Firmware error code on failure (see psp-sev.h) */ | |
| __u32 error; | |
| }; | |
| 2.1 SNP_GET_REPORT | |
| ------------------ | |
| :Technology: sev-snp | |
| :Type: guest ioctl | |
| :Parameters (in): struct snp_report_req | |
| :Returns (out): struct snp_report_resp on success, -negative on error | |
| The SNP_GET_REPORT ioctl can be used to query the attestation report from the | |
| SEV-SNP firmware. The ioctl uses the SNP_GUEST_REQUEST (MSG_REPORT_REQ) command | |
| provided by the SEV-SNP firmware to query the attestation report. | |
| On success, the snp_report_resp.data will contains the report. The report | |
| contain the format described in the SEV-SNP specification. See the SEV-SNP | |
| specification for further details. | |
| 2.2 SNP_GET_DERIVED_KEY | |
| ----------------------- | |
| :Technology: sev-snp | |
| :Type: guest ioctl | |
| :Parameters (in): struct snp_derived_key_req | |
| :Returns (out): struct snp_derived_key_resp on success, -negative on error | |
| The SNP_GET_DERIVED_KEY ioctl can be used to get a key derive from a root key. | |
| The derived key can be used by the guest for any purpose, such as sealing keys | |
| or communicating with external entities. | |
| The ioctl uses the SNP_GUEST_REQUEST (MSG_KEY_REQ) command provided by the | |
| SEV-SNP firmware to derive the key. See SEV-SNP specification for further details | |
| on the various fields passed in the key derivation request. | |
| On success, the snp_derived_key_resp.data contains the derived key value. See | |
| the SEV-SNP specification for further details. | |
| 2.3 SNP_GET_EXT_REPORT | |
| ---------------------- | |
| :Technology: sev-snp | |
| :Type: guest ioctl | |
| :Parameters (in/out): struct snp_ext_report_req | |
| :Returns (out): struct snp_report_resp on success, -negative on error | |
| The SNP_GET_EXT_REPORT ioctl is similar to the SNP_GET_REPORT. The difference is | |
| related to the additional certificate data that is returned with the report. | |
| The certificate data returned is being provided by the hypervisor through the | |
| SNP_SET_EXT_CONFIG. | |
| The ioctl uses the SNP_GUEST_REQUEST (MSG_REPORT_REQ) command provided by the SEV-SNP | |
| firmware to get the attestation report. | |
| On success, the snp_ext_report_resp.data will contain the attestation report | |
| and snp_ext_report_req.certs_address will contain the certificate blob. If the | |
| length of the blob is smaller than expected then snp_ext_report_req.certs_len will | |
| be updated with the expected value. | |
| See GHCB specification for further detail on how to parse the certificate blob. | |
| 2.4 SNP_PLATFORM_STATUS | |
| ----------------------- | |
| :Technology: sev-snp | |
| :Type: hypervisor ioctl cmd | |
| :Parameters (out): struct sev_user_data_snp_status | |
| :Returns (out): 0 on success, -negative on error | |
| The SNP_PLATFORM_STATUS command is used to query the SNP platform status. The | |
| status includes API major, minor version and more. See the SEV-SNP | |
| specification for further details. | |
| 2.5 SNP_COMMIT | |
| -------------- | |
| :Technology: sev-snp | |
| :Type: hypervisor ioctl cmd | |
| :Returns (out): 0 on success, -negative on error | |
| SNP_COMMIT is used to commit the currently installed firmware using the | |
| SEV-SNP firmware SNP_COMMIT command. This prevents roll-back to a previously | |
| committed firmware version. This will also update the reported TCB to match | |
| that of the currently installed firmware. | |
| 2.6 SNP_SET_CONFIG | |
| ------------------ | |
| :Technology: sev-snp | |
| :Type: hypervisor ioctl cmd | |
| :Parameters (in): struct sev_user_data_snp_config | |
| :Returns (out): 0 on success, -negative on error | |
| SNP_SET_CONFIG is used to set the system-wide configuration such as | |
| reported TCB version in the attestation report. The command is similar | |
| to SNP_CONFIG command defined in the SEV-SNP spec. The current values of | |
| the firmware parameters affected by this command can be queried via | |
| SNP_PLATFORM_STATUS. | |
| 2.7 SNP_VLEK_LOAD | |
| ----------------- | |
| :Technology: sev-snp | |
| :Type: hypervisor ioctl cmd | |
| :Parameters (in): struct sev_user_data_snp_vlek_load | |
| :Returns (out): 0 on success, -negative on error | |
| When requesting an attestation report a guest is able to specify whether | |
| it wants SNP firmware to sign the report using either a Versioned Chip | |
| Endorsement Key (VCEK), which is derived from chip-unique secrets, or a | |
| Versioned Loaded Endorsement Key (VLEK) which is obtained from an AMD | |
| Key Derivation Service (KDS) and derived from seeds allocated to | |
| enrolled cloud service providers. | |
| In the case of VLEK keys, the SNP_VLEK_LOAD SNP command is used to load | |
| them into the system after obtaining them from the KDS, and corresponds | |
| closely to the SNP_VLEK_LOAD firmware command specified in the SEV-SNP | |
| spec. | |
| 3. SEV-SNP CPUID Enforcement | |
| ============================ | |
| SEV-SNP guests can access a special page that contains a table of CPUID values | |
| that have been validated by the PSP as part of the SNP_LAUNCH_UPDATE firmware | |
| command. It provides the following assurances regarding the validity of CPUID | |
| values: | |
| - Its address is obtained via bootloader/firmware (via CC blob), and those | |
| binaries will be measured as part of the SEV-SNP attestation report. | |
| - Its initial state will be encrypted/pvalidated, so attempts to modify | |
| it during run-time will result in garbage being written, or #VC exceptions | |
| being generated due to changes in validation state if the hypervisor tries | |
| to swap the backing page. | |
| - Attempts to bypass PSP checks by the hypervisor by using a normal page, or | |
| a non-CPUID encrypted page will change the measurement provided by the | |
| SEV-SNP attestation report. | |
| - The CPUID page contents are *not* measured, but attempts to modify the | |
| expected contents of a CPUID page as part of guest initialization will be | |
| gated by the PSP CPUID enforcement policy checks performed on the page | |
| during SNP_LAUNCH_UPDATE, and noticeable later if the guest owner | |
| implements their own checks of the CPUID values. | |
| It is important to note that this last assurance is only useful if the kernel | |
| has taken care to make use of the SEV-SNP CPUID throughout all stages of boot. | |
| Otherwise, guest owner attestation provides no assurance that the kernel wasn't | |
| fed incorrect values at some point during boot. | |
| 4. SEV Guest Driver Communication Key | |
| ===================================== | |
| Communication between an SEV guest and the SEV firmware in the AMD Secure | |
| Processor (ASP, aka PSP) is protected by a VM Platform Communication Key | |
| (VMPCK). By default, the sev-guest driver uses the VMPCK associated with the | |
| VM Privilege Level (VMPL) at which the guest is running. Should this key be | |
| wiped by the sev-guest driver (see the driver for reasons why a VMPCK can be | |
| wiped), a different key can be used by reloading the sev-guest driver and | |
| specifying the desired key using the vmpck_id module parameter. | |
| Reference | |
| --------- | |
| SEV-SNP and GHCB specification: developer.amd.com/sev | |
| The driver is based on SEV-SNP firmware spec 0.9 and GHCB spec version 2.0. |