Commit 9632f791 authored by xiongmengbiao's avatar xiongmengbiao
Browse files

drivers/crypto/ccp: Add psp mutex enable ioctl support

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I9C3AM


CVE: NA

---------------------------

Add ioctl interface to control the state of self-defined
mutex in user and kernel space.

By default, when psp user-mode driver is not used,
the self-defined mutex is disabled, and the kernel's native
private lock is utilized instead.

Signed-off-by: default avatarxiongmengbiao <xiongmengbiao@hygon.cn>
parent fe08767e
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	void __user *argp = (void __user *)arg;
	struct sev_issue_cmd input;
	int ret = -EFAULT;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;
@@ -184,7 +185,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (input.cmd > CSV_MAX)
		return -EINVAL;

	if (is_vendor_hygon()) {
	if (is_vendor_hygon() && mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -212,7 +213,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
		 * Release the mutex before calling the native ioctl function
		 * because it will acquires the mutex.
		 */
		if (is_vendor_hygon())
		if (is_vendor_hygon() && mutex_enabled)
			psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
		else
			mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -222,7 +223,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
		ret = -EFAULT;

	if (is_vendor_hygon())
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -380,11 +381,12 @@ static int csv_do_ringbuf_cmds(int *psp_ret)
{
	struct sev_user_data_status data;
	int rc;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (is_vendor_hygon()) {
	if (is_vendor_hygon() && mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -403,7 +405,7 @@ static int csv_do_ringbuf_cmds(int *psp_ret)
	csv_comm_mode = CSV_COMM_MAILBOX_ON;

cmd_unlock:
	if (is_vendor_hygon())
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
+48 −1
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/psp.h>
#include <linux/psp-hygon.h>
#include <linux/bitfield.h>
#include <linux/delay.h>

#include "psp-dev.h"

@@ -21,6 +22,12 @@
struct hygon_psp_hooks_table hygon_psp_hooks;

static struct psp_misc_dev *psp_misc;
#define HYGON_PSP_IOC_TYPE 'H'
enum HYGON_PSP_OPCODE {
	HYGON_PSP_MUTEX_ENABLE = 1,
	HYGON_PSP_MUTEX_DISABLE,
	HYGON_PSP_OPCODE_MAX_NR,
};

uint64_t atomic64_exchange(uint64_t *dst, uint64_t val)
{
@@ -54,7 +61,7 @@ int psp_mutex_lock_timeout(struct psp_mutex *mutex, uint64_t ms)
			ret = 1;
			break;
		}
	} while (time_before(jiffies, je));
	} while ((ms == 0) || time_before(jiffies, je));

	return ret;
}
@@ -124,11 +131,51 @@ static ssize_t write_psp(struct file *file, const char __user *buf, size_t count
	return written;
}

static long ioctl_psp(struct file *file, unsigned int ioctl, unsigned long arg)
{
	unsigned int opcode = 0;

	if (_IOC_TYPE(ioctl) != HYGON_PSP_IOC_TYPE) {
		pr_info("%s: invalid ioctl type: 0x%x\n", __func__, _IOC_TYPE(ioctl));
		return -EINVAL;
	}
	opcode = _IOC_NR(ioctl);
	switch (opcode) {
	case HYGON_PSP_MUTEX_ENABLE:
		psp_mutex_lock_timeout(&psp_misc->data_pg_aligned->mb_mutex, 0);
		// And get the sev lock to make sure no one is using it now.
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		hygon_psp_hooks.psp_mutex_enabled = 1;
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		// Wait 10ms just in case someone is right before getting the psp lock.
		mdelay(10);
		psp_mutex_unlock(&psp_misc->data_pg_aligned->mb_mutex);
		break;

	case HYGON_PSP_MUTEX_DISABLE:
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		// And get the psp lock to make sure no one is using it now.
		psp_mutex_lock_timeout(&psp_misc->data_pg_aligned->mb_mutex, 0);
		hygon_psp_hooks.psp_mutex_enabled = 0;
		psp_mutex_unlock(&psp_misc->data_pg_aligned->mb_mutex);
		// Wait 10ms just in case someone is right before getting the sev lock.
		mdelay(10);
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		break;

	default:
		pr_info("%s: invalid ioctl number: %d\n", __func__, opcode);
		return -EINVAL;
	}
	return 0;
}

static const struct file_operations psp_fops = {
	.owner          = THIS_MODULE,
	.mmap		= mmap_psp,
	.read		= read_psp,
	.write		= write_psp,
	.unlocked_ioctl = ioctl_psp,
};

int hygon_psp_additional_setup(struct sp_device *sp)
+2 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ extern struct hygon_psp_hooks_table {
	bool sev_dev_hooks_installed;
	struct mutex *sev_cmd_mutex;
	struct psp_misc_dev *psp_misc;
	bool psp_mutex_enabled;
	bool *psp_dead;
	int *psp_timeout;
	int *psp_cmd_timeout;
@@ -44,7 +45,7 @@ extern struct hygon_psp_hooks_table {
	long (*sev_ioctl)(struct file *file, unsigned int ioctl, unsigned long arg);
} hygon_psp_hooks;

#define PSP_MUTEX_TIMEOUT 10000
#define PSP_MUTEX_TIMEOUT 60000
struct psp_mutex {
	uint64_t locked;
};
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@

#include <linux/kernel.h>
#include <linux/irqreturn.h>
#include <linux/delay.h>

#include "sp-dev.h"
#include "psp-dev.h"
+12 −8
Original line number Diff line number Diff line
@@ -408,8 +408,9 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
static int sev_do_cmd(int cmd, void *data, int *psp_ret)
{
	int rc;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon()) {
	if (is_vendor_hygon() && mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -417,7 +418,7 @@ static int sev_do_cmd(int cmd, void *data, int *psp_ret)
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
	}
	rc = __sev_do_cmd_locked(cmd, data, psp_ret);
	if (is_vendor_hygon())
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -538,8 +539,9 @@ static int __sev_platform_init_locked(int *error)
int sev_platform_init(int *error)
{
	int rc;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon()) {
	if (is_vendor_hygon() && mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -547,7 +549,7 @@ int sev_platform_init(int *error)
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
	}
	rc = __sev_platform_init_locked(error);
	if (is_vendor_hygon())
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -587,8 +589,9 @@ static int __sev_platform_shutdown_locked(int *error)
static int sev_platform_shutdown(int *error)
{
	int rc;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon()) {
	if (is_vendor_hygon() && mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -596,7 +599,7 @@ static int sev_platform_shutdown(int *error)
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
	}
	rc = __sev_platform_shutdown_locked(NULL);
	if (is_vendor_hygon())
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -1146,6 +1149,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	struct sev_issue_cmd input;
	int ret = -EFAULT;
	bool writable = file->f_mode & FMODE_WRITE;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (!psp_master || !psp_master->sev_data)
		return -ENODEV;
@@ -1159,7 +1163,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (input.cmd > SEV_MAX)
		return -EINVAL;

	if (is_vendor_hygon()) {
	if (is_vendor_hygon() && mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -1205,7 +1209,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
		ret = -EFAULT;
out:
	if (is_vendor_hygon())
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);