From 77f2bfd8c42d58276806115f6df0687ad30a3b85 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Fri, 3 Dec 2021 06:08:07 -0500 Subject: [PATCH 1/4] anolis: crypto: ccp: Support DOWNLOAD_FIRMWARE when detect CSV ANBZ: #5962 When ccp driver detect CSV support on Hygon CPU, it should try to update the latest CSV firmware on the system paths. Signed-off-by: hanliyang Reviewed-by: Artie Ding Link: https://gitee.com/anolis/cloud-kernel/pulls/1971 --- drivers/crypto/ccp/sev-dev.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 9c7e50a58a10..5110ff6c6104 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -30,6 +30,7 @@ #define DEVICE_NAME "sev" #define SEV_FW_FILE "amd/sev.fw" +#define CSV_FW_FILE "hygon/csv.fw" #define SEV_FW_NAME_SIZE 64 DEFINE_MUTEX(sev_cmd_mutex); @@ -79,6 +80,11 @@ static inline bool sev_version_greater_or_equal(u8 maj, u8 min) return false; } +static inline bool csv_version_greater_or_equal(u32 build) +{ + return hygon_csv_build >= build; +} + static void sev_irq_handler(int irq, void *data, unsigned int status) { struct sev_device *sev = data; @@ -814,6 +820,14 @@ static int sev_get_firmware(struct device *dev, char fw_name_specific[SEV_FW_NAME_SIZE]; char fw_name_subset[SEV_FW_NAME_SIZE]; + if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) { + /* Check for CSV FW to using generic name: csv.fw */ + if (firmware_request_nowarn(firmware, CSV_FW_FILE, dev) >= 0) + return 0; + else + return -ENOENT; + } + snprintf(fw_name_specific, sizeof(fw_name_specific), "amd/amd_sev_fam%.2xh_model%.2xh.sbin", boot_cpu_data.x86, boot_cpu_data.x86_model); @@ -885,9 +899,14 @@ static int sev_update_firmware(struct device *dev) ret = sev_do_cmd(SEV_CMD_DOWNLOAD_FIRMWARE, data, &error); if (ret) - dev_dbg(dev, "Failed to update SEV firmware: %#x\n", error); + dev_dbg(dev, "Failed to update %s firmware: %#x\n", + (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) + ? "CSV" : "SEV", + error); else - dev_info(dev, "SEV firmware update successful\n"); + dev_info(dev, "%s firmware update successful\n", + (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) + ? "CSV" : "SEV"); __free_pages(p, order); @@ -1605,6 +1624,8 @@ void sev_pci_init(void) goto err; if (sev_version_greater_or_equal(0, 15) && + (boot_cpu_data.x86_vendor != X86_VENDOR_HYGON || + csv_version_greater_or_equal(1667)) && sev_update_firmware(sev->dev) == 0) sev_get_api_version(); -- Gitee From 2f564e9338912d82eb24b5f3132cd2c4236447f4 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Fri, 3 Dec 2021 05:31:27 -0500 Subject: [PATCH 2/4] anolis: crypto: ccp: Implement CSV_PLATFORM_INIT ioctl command ANBZ: #5962 The CSV_PLATFORM_INIT command can be used by the platform owner to switch platform from PSTATE.UNINIT to PSTATE.INIT. In the upcoming patches, we'll support DOWNLOAD_FIRMWARE at userspace. Due to DOWNLOAD_FIRMWARE can only performed when platform is in the PSTATE.UNINIT, we need invoke PLATFORM_INIT following DOWNLOAD_FIRMWARE to switch platform back to PSTATE.INIT. Signed-off-by: hanliyang Reviewed-by: Artie Ding Link: https://gitee.com/anolis/cloud-kernel/pulls/1971 --- drivers/crypto/ccp/sev-dev.c | 3 +++ include/uapi/linux/psp-sev.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 5110ff6c6104..e5d5f1c8be49 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1232,6 +1232,9 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) { switch (input.cmd) { + case CSV_PLATFORM_INIT: + ret = __sev_platform_init_locked(&input.error); + goto result_to_user; case CSV_HGSC_CERT_IMPORT: ret = csv_ioctl_do_hgsc_import(&input); goto result_to_user; diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h index b48e72d595ff..e34eba31dbe7 100644 --- a/include/uapi/linux/psp-sev.h +++ b/include/uapi/linux/psp-sev.h @@ -36,6 +36,7 @@ enum { * CSV platform commands */ enum { + CSV_PLATFORM_INIT = 101, CSV_HGSC_CERT_IMPORT = 201, CSV_MAX, -- Gitee From 0ded9fee2efd9a4bfab0f0a3cc770050e6a3d229 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Fri, 3 Dec 2021 05:33:25 -0500 Subject: [PATCH 3/4] anolis: crypto: ccp: Implement CSV_PLATFORM_SHUTDOWN ioctl command ANBZ: #5962 The CSV_PLATFORM_SHUTDOWN command can be used by the platform owner to switch platform to PSTATE.UNINIT. The DOWNLOAD_FIRMWARE API can only performed when platform is in the PSTATE.UNINIT. In order to support DOWNLOAD_FIRMWARE at userspace, we need invoke PLATFORM_SHUTDOWN before that. Signed-off-by: hanliyang Reviewed-by: Artie Ding Link: https://gitee.com/anolis/cloud-kernel/pulls/1971 --- drivers/crypto/ccp/sev-dev.c | 3 +++ include/uapi/linux/psp-sev.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index e5d5f1c8be49..3291398928e7 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1235,6 +1235,9 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) case CSV_PLATFORM_INIT: ret = __sev_platform_init_locked(&input.error); goto result_to_user; + case CSV_PLATFORM_SHUTDOWN: + ret = __sev_platform_shutdown_locked(&input.error); + goto result_to_user; case CSV_HGSC_CERT_IMPORT: ret = csv_ioctl_do_hgsc_import(&input); goto result_to_user; diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h index e34eba31dbe7..00459602904f 100644 --- a/include/uapi/linux/psp-sev.h +++ b/include/uapi/linux/psp-sev.h @@ -37,6 +37,7 @@ enum { */ enum { CSV_PLATFORM_INIT = 101, + CSV_PLATFORM_SHUTDOWN = 102, CSV_HGSC_CERT_IMPORT = 201, CSV_MAX, -- Gitee From 51355f65a3f3035cbc031a91fd3e4fe5a4460d70 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Fri, 3 Dec 2021 05:58:23 -0500 Subject: [PATCH 4/4] anolis: crypto: ccp: Implement CSV_DOWNLOAD_FIRMWARE ioctl command ANBZ: #5962 The CSV_DOWNLOAD_FIRMWARE command can be used by the platform owner to updating CSV firmware. Signed-off-by: hanliyang Reviewed-by: Artie Ding Link: https://gitee.com/anolis/cloud-kernel/pulls/1971 --- drivers/crypto/ccp/sev-dev.c | 70 ++++++++++++++++++++++++++++++++++++ include/linux/psp-sev.h | 2 ++ include/uapi/linux/psp-sev.h | 12 +++++++ 3 files changed, 84 insertions(+) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 3291398928e7..2c4951c9c84d 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -1151,6 +1151,73 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) return ret; } +static int csv_ioctl_do_download_firmware(struct sev_issue_cmd *argp) +{ + struct sev_data_download_firmware *data = NULL; + struct csv_user_data_download_firmware input; + int ret, order; + struct page *p; + u64 data_size; + + /* Only support DOWNLOAD_FIRMWARE if build greater or equal 1667 */ + if (!csv_version_greater_or_equal(1667)) { + pr_err("DOWNLOAD_FIRMWARE not supported\n"); + return -EIO; + } + + if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) + return -EFAULT; + + if (!input.address) { + argp->error = SEV_RET_INVALID_ADDRESS; + return -EINVAL; + } + + if (!input.length || input.length > CSV_FW_MAX_SIZE) { + argp->error = SEV_RET_INVALID_LEN; + return -EINVAL; + } + + /* + * CSV FW expects the physical address given to it to be 32 + * byte aligned. Memory allocated has structure placed at the + * beginning followed by the firmware being passed to the CSV + * FW. Allocate enough memory for data structure + alignment + * padding + CSV FW. + */ + data_size = ALIGN(sizeof(struct sev_data_download_firmware), 32); + + order = get_order(input.length + data_size); + p = alloc_pages(GFP_KERNEL, order); + if (!p) + return -ENOMEM; + + /* + * Copy firmware data to a kernel allocated contiguous + * memory region. + */ + data = page_address(p); + if (copy_from_user((void *)(page_address(p) + data_size), + (void *)input.address, input.length)) { + ret = -EFAULT; + goto err_free_page; + } + + data->address = __psp_pa(page_address(p) + data_size); + data->len = input.length; + + ret = __sev_do_cmd_locked(SEV_CMD_DOWNLOAD_FIRMWARE, data, &argp->error); + if (ret) + pr_err("Failed to update CSV firmware: %#x\n", argp->error); + else + pr_info("CSV firmware update successful\n"); + +err_free_page: + __free_pages(p, order); + + return ret; +} + static int csv_ioctl_do_hgsc_import(struct sev_issue_cmd *argp) { struct csv_user_data_hgsc_cert_import input; @@ -1238,6 +1305,9 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) case CSV_PLATFORM_SHUTDOWN: ret = __sev_platform_shutdown_locked(&input.error); goto result_to_user; + case CSV_DOWNLOAD_FIRMWARE: + ret = csv_ioctl_do_download_firmware(&input); + goto result_to_user; case CSV_HGSC_CERT_IMPORT: ret = csv_ioctl_do_hgsc_import(&input); goto result_to_user; diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 029ab2b46ab7..90041775b5e6 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -24,6 +24,8 @@ #define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ +#define CSV_FW_MAX_SIZE 0x80000 /* 512KB */ + /** * SEV platform state */ diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h index 00459602904f..9950f595bee5 100644 --- a/include/uapi/linux/psp-sev.h +++ b/include/uapi/linux/psp-sev.h @@ -38,6 +38,7 @@ enum { enum { CSV_PLATFORM_INIT = 101, CSV_PLATFORM_SHUTDOWN = 102, + CSV_DOWNLOAD_FIRMWARE = 128, CSV_HGSC_CERT_IMPORT = 201, CSV_MAX, @@ -173,6 +174,17 @@ struct csv_user_data_hgsc_cert_import { __u32 hgsc_cert_len; /* In */ } __packed; +/** + * struct csv_user_data_download_firmware - DOWNLOAD_FIRMWARE command parameters + * + * @address: physical address of CSV firmware image + * @length: length of the CSV firmware image + */ +struct csv_user_data_download_firmware { + __u64 address; /* In */ + __u32 length; /* In */ +} __packed; + /** * struct sev_issue_cmd - SEV ioctl parameters * -- Gitee