Unverified Commit 79e1c0e4 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!5257 [OLK-6.6] Support DOWNLOAD_FIRMWARE feature for hygon CSV

Merge Pull Request from: @hanliyang 
 
Support DOWNLAOD_FIRMWARE for Hygon CSV

issue:
https://gitee.com/open_euler/dashboard?issue_id=I98VXP

1. Allows Cryptographic Co-Processor driver to update the CSV firmware during module init. Once the CSV support on Hygon PSP is detected in the driver, the driver will load firmware files from filesystem and update the firmware. 
2. Add the user-space ioctl interface to update CSV firmware at runtime, without re-insmod the driver.

Test:
1. Save csv.fw in the root path /lib/firmware/hygon/, insmod Cryptographic Co-Processor driver, we can see that the CSV firmware is updated.
2. Save csv.fw on the disk, use gadget hag to updating CSV firmware, we can see that the CSV firmware is updated.
3. After step2, the platform stays in UNINIT state, use gadget hag to execute PLATFORM_INIT, and then the platform switch to INIT state. 
 
Link:https://gitee.com/openeuler/kernel/pulls/5257

 

Reviewed-by: default avatarZhang Peng <zhangpeng362@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 40c3b22a 582fab52
Loading
Loading
Loading
Loading
+78 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <uapi/linux/psp-hygon.h>

#include "psp-dev.h"
#include "csv-dev.h"

/*
 * Hygon CSV build info:
@@ -90,6 +91,74 @@ static int csv_ioctl_do_hgsc_import(struct sev_issue_cmd *argp)
	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 = hygon_psp_hooks.__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 long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
@@ -117,6 +186,15 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	case CSV_HGSC_CERT_IMPORT:
		ret = csv_ioctl_do_hgsc_import(&input);
		break;
	case CSV_PLATFORM_INIT:
		ret = hygon_psp_hooks.__sev_platform_init_locked(&input.error);
		break;
	case CSV_PLATFORM_SHUTDOWN:
		ret = hygon_psp_hooks.__sev_platform_shutdown_locked(&input.error);
		break;
	case CSV_DOWNLOAD_FIRMWARE:
		ret = csv_ioctl_do_download_firmware(&input);
		break;
	default:
		/*
		 * If the command is compatible between CSV and SEV, the
+7 −0
Original line number Diff line number Diff line
@@ -12,10 +12,17 @@

#include <linux/fs.h>

#define CSV_FW_FILE		"hygon/csv.fw"

extern u32 hygon_csv_build;
extern const struct file_operations csv_fops;

void csv_update_api_version(struct sev_user_data_status *status);
int csv_cmd_buffer_len(int cmd);

static inline bool csv_version_greater_or_equal(u32 build)
{
	return hygon_csv_build >= build;
}

#endif	/* __CCP_HYGON_CSV_DEV_H__ */
+2 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ extern struct hygon_psp_hooks_table {
	bool sev_dev_hooks_installed;
	struct mutex *sev_cmd_mutex;
	int (*__sev_do_cmd_locked)(int cmd, void *data, int *psp_ret);
	int (*__sev_platform_init_locked)(int *error);
	int (*__sev_platform_shutdown_locked)(int *error);
	long (*sev_ioctl)(struct file *file, unsigned int ioctl, unsigned long arg);
} hygon_psp_hooks;

+18 −4
Original line number Diff line number Diff line
@@ -758,6 +758,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 (is_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);
@@ -796,13 +804,15 @@ static int sev_update_firmware(struct device *dev)
	struct page *p;
	u64 data_size;

	if (!sev_version_greater_or_equal(0, 15)) {
	if (!sev_version_greater_or_equal(0, 15) &&
	    !(is_vendor_hygon() && csv_version_greater_or_equal(1667))) {
		dev_dbg(dev, "DOWNLOAD_FIRMWARE not supported\n");
		return -1;
	}

	if (sev_get_firmware(dev, &firmware) == -ENOENT) {
		dev_dbg(dev, "No SEV firmware file present\n");
		dev_dbg(dev, "No %s firmware file present\n",
			is_vendor_hygon() ? "CSV" : "SEV");
		return -1;
	}

@@ -842,9 +852,11 @@ 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",
			is_vendor_hygon() ? "CSV" : "SEV", error);
	else
		dev_info(dev, "SEV firmware update successful\n");
		dev_info(dev, "%s firmware update successful\n",
			 is_vendor_hygon() ? "CSV" : "SEV");

	__free_pages(p, order);

@@ -1251,6 +1263,8 @@ static void sev_dev_install_hooks(void)
{
	hygon_psp_hooks.sev_cmd_mutex = &sev_cmd_mutex;
	hygon_psp_hooks.__sev_do_cmd_locked = __sev_do_cmd_locked;
	hygon_psp_hooks.__sev_platform_init_locked = __sev_platform_init_locked;
	hygon_psp_hooks.__sev_platform_shutdown_locked = __sev_platform_shutdown_locked;
	hygon_psp_hooks.sev_ioctl = sev_ioctl;

	hygon_psp_hooks.sev_dev_hooks_installed = true;
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
/***************************** CSV interface *********************************/
/*****************************************************************************/

#define CSV_FW_MAX_SIZE		0x80000	/* 512KB */

/**
 * Guest/platform management commands for CSV
 */
Loading