@@ -71,6 +71,7 @@ struct sev_device {
struct fw_upload *fwl;
bool fw_cancel;
#endif /* CONFIG_FW_UPLOAD */
+ bool tio_en;
};
bool sev_version_greater_or_equal(u8 maj, u8 min);
@@ -107,6 +107,7 @@ enum sev_cmd {
SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA,
SEV_CMD_SNP_COMMIT = 0x0CB,
SEV_CMD_SNP_VLEK_LOAD = 0x0CD,
+ SEV_CMD_SNP_FEATURE_INFO = 0x0CE,
SEV_CMD_MAX,
};
@@ -146,6 +147,7 @@ struct sev_data_init_ex {
} __packed;
#define SEV_INIT_FLAGS_SEV_ES 0x01
+#define SEV_INIT_FLAGS_SEV_TIO_EN BIT(2)
/**
* struct sev_data_pek_csr - PEK_CSR command parameters
@@ -601,6 +603,25 @@ struct sev_data_snp_addr {
u64 address; /* In/Out */
} __packed;
+/**
+ * struct sev_data_snp_feature_info - SEV_CMD_SNP_FEATURE_INFO command params
+ *
+ * @len: length of this struct
+ * @ecx_in: subfunction index of CPUID Fn8000_0024
+ * @feature_info_paddr: physical address of a page with sev_snp_feature_info
+ */
+#define SNP_FEATURE_FN8000_0024_EBX_X00_SEVTIO 1
+
+struct sev_snp_feature_info {
+ u32 eax, ebx, ecx, edx; /* Out */
+} __packed;
+
+struct sev_data_snp_feature_info {
+ u32 length; /* In */
+ u32 ecx_in; /* In */
+ u64 feature_info_paddr; /* In */
+} __packed;
+
/**
* struct sev_data_snp_launch_start - SNP_LAUNCH_START command params
*
@@ -762,10 +783,14 @@ struct sev_data_snp_guest_request {
struct sev_data_snp_init_ex {
u32 init_rmp:1;
u32 list_paddr_en:1;
- u32 rsvd:30;
+ u32 rapl_dis:1;
+ u32 ciphertext_hiding_en:1;
+ u32 tio_en:1;
+ u32 rsvd:27;
u32 rsvd1;
u64 list_paddr;
- u8 rsvd2[48];
+ u16 max_snp_asid;
+ u8 rsvd2[46];
} __packed;
/**
@@ -804,7 +829,8 @@ struct sev_data_range_list {
struct sev_data_snp_shutdown_ex {
u32 len;
u32 iommu_snp_shutdown:1;
- u32 rsvd1:31;
+ u32 x86_snp_shutdown:1;
+ u32 rsvd1:30;
} __packed;
/**
@@ -189,6 +189,7 @@ struct sev_user_data_get_id2 {
* @mask_chip_id: whether chip id is present in attestation reports or not
* @mask_chip_key: whether attestation reports are signed or not
* @vlek_en: VLEK (Version Loaded Endorsement Key) hashstick is loaded
+ * @feature_info: Indicates that the SNP_FEATURE_INFO command is available
* @rsvd1: reserved
* @guest_count: the number of guest currently managed by the firmware
* @current_tcb_version: current TCB version
@@ -204,7 +205,8 @@ struct sev_user_data_snp_status {
__u32 mask_chip_id:1; /* Out */
__u32 mask_chip_key:1; /* Out */
__u32 vlek_en:1; /* Out */
- __u32 rsvd1:29;
+ __u32 feature_info:1; /* Out */
+ __u32 rsvd1:28;
__u32 guest_count; /* Out */
__u64 current_tcb_version; /* Out */
__u64 reported_tcb_version; /* Out */
@@ -74,6 +74,10 @@ static bool psp_init_on_probe = true;
module_param(psp_init_on_probe, bool, 0444);
MODULE_PARM_DESC(psp_init_on_probe, " if true, the PSP will be initialized on module init. Else the PSP will be initialized on the first command requiring it");
+/* enable/disable SEV-TIO support */
+static bool sev_tio_enabled = true;
+module_param_named(sev_tio, sev_tio_enabled, bool, 0444);
+
MODULE_FIRMWARE("amd/amd_sev_fam17h_model0xh.sbin"); /* 1st gen EPYC */
MODULE_FIRMWARE("amd/amd_sev_fam17h_model3xh.sbin"); /* 2nd gen EPYC */
MODULE_FIRMWARE("amd/amd_sev_fam19h_model0xh.sbin"); /* 3rd gen EPYC */
@@ -228,6 +232,7 @@ static int sev_cmd_buffer_len(int cmd)
case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request);
case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config);
case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit);
+ case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct sev_data_snp_feature_info);
case SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX: return sizeof(struct sev_data_download_firmware_ex);
default: return 0;
}
@@ -1055,7 +1060,7 @@ static int __sev_init_ex_locked(int *error)
*/
data.tmr_address = __pa(sev_es_tmr);
- data.flags |= SEV_INIT_FLAGS_SEV_ES;
+ data.flags |= SEV_INIT_FLAGS_SEV_ES | SEV_INIT_FLAGS_SEV_TIO_EN;
data.tmr_len = sev_es_tmr_size;
}
@@ -1226,6 +1231,77 @@ int sev_snp_guest_decommission(int asid, int *psp_ret)
}
EXPORT_SYMBOL_GPL(sev_snp_guest_decommission);
+static int snp_feature_info_locked(struct sev_device *sev, u32 ecx,
+ struct sev_snp_feature_info *fi, int *psp_ret)
+{
+ struct sev_data_snp_feature_info buf = {
+ .length = sizeof(buf),
+ .ecx_in = ecx,
+ };
+ struct page *status_page;
+ void *data;
+ int ret;
+
+ status_page = alloc_page(GFP_KERNEL_ACCOUNT);
+ if (!status_page)
+ return -ENOMEM;
+
+ data = page_address(status_page);
+
+ if (sev->snp_initialized && rmp_mark_pages_firmware(__pa(data), 1, true)) {
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ buf.feature_info_paddr = __psp_pa(data);
+ ret = __sev_do_cmd_locked(SEV_CMD_SNP_FEATURE_INFO, &buf, psp_ret);
+
+ if (sev->snp_initialized && snp_reclaim_pages(__pa(data), 1, true))
+ ret = -EFAULT;
+
+ if (!ret)
+ memcpy(fi, data, sizeof(*fi));
+
+cleanup:
+ __free_pages(status_page, 0);
+ return ret;
+}
+
+static int snp_get_feature_info(struct sev_device *sev, u32 ecx, struct sev_snp_feature_info *fi)
+{
+ struct sev_user_data_snp_status status = { 0 };
+ int psp_ret = 0, ret;
+
+ ret = snp_platform_status_locked(sev, &status, &psp_ret);
+ if (ret)
+ return ret;
+ if (ret != SEV_RET_SUCCESS)
+ return -EFAULT;
+ if (!status.feature_info)
+ return -ENOENT;
+
+ ret = snp_feature_info_locked(sev, ecx, fi, &psp_ret);
+ if (ret)
+ return ret;
+ if (ret != SEV_RET_SUCCESS)
+ return -EFAULT;
+
+ return 0;
+}
+
+static bool sev_tio_present(struct sev_device *sev)
+{
+ struct sev_snp_feature_info fi = { 0 };
+ bool present;
+
+ if (snp_get_feature_info(sev, 0, &fi))
+ return false;
+
+ present = (fi.ebx & SNP_FEATURE_FN8000_0024_EBX_X00_SEVTIO) != 0;
+ dev_info(sev->dev, "SEV-TIO support is %s\n", present ? "present" : "not present");
+ return present;
+}
+
static int __sev_snp_init_locked(int *error)
{
struct psp_device *psp = psp_master;
@@ -1290,6 +1366,8 @@ static int __sev_snp_init_locked(int *error)
data.init_rmp = 1;
data.list_paddr_en = 1;
data.list_paddr = __psp_pa(snp_range_list);
+ data.tio_en = sev_tio_enabled && sev_tio_present(sev) &&
+ amd_iommu_sev_tio_supported();
cmd = SEV_CMD_SNP_INIT_EX;
} else {
cmd = SEV_CMD_SNP_INIT;
@@ -1319,7 +1397,9 @@ static int __sev_snp_init_locked(int *error)
return rc;
sev->snp_initialized = true;
- dev_dbg(sev->dev, "SEV-SNP firmware initialized\n");
+ sev->tio_en = data.tio_en;
+ dev_dbg(sev->dev, "SEV-SNP firmware initialized, SEV-TIO is %s\n",
+ sev->tio_en ? "enabled" : "disabled");
sev_es_tmr_size = SNP_TMR_SIZE;
The PSP advertises the SEV-TIO support via the FEATURE_INFO command support of which is advertised via SNP_PLATFORM_STATUS. Add FEATURE_INFO and use it to detect the TIO support in the PSP. If present, enable TIO in the SNP_INIT_EX call. While at this, add new bits to sev_data_snp_init_ex() from SEV-SNP 1.55. Note that this tests the PSP firmware support but not if the feature is enabled in the BIOS. While at this, add new sev_data_snp_shutdown_ex::x86_snp_shutdown Signed-off-by: Alexey Kardashevskiy <aik@amd.com> --- drivers/crypto/ccp/sev-dev.h | 1 + include/linux/psp-sev.h | 32 +++++++- include/uapi/linux/psp-sev.h | 4 +- drivers/crypto/ccp/sev-dev.c | 84 +++++++++++++++++++- 4 files changed, 115 insertions(+), 6 deletions(-)