Commit 680134f1 authored by chench00's avatar chench00
Browse files

crypto: ccp: Add a new interface for X86 sending command to PSP

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


CVE: NA

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

HYGON's fTPM and TDM need to send commands to PSP to complete the
firmware function.

In order to be compatible with the original kernel code, The command
of psp_do_cmd is added to send the command from x86 to PSP. The
interface is currently used for fTPM/TDM/TPCM of HYGON.

Signed-off-by: default avatarchench <chench@hygon.cn>
parent b9804f3b
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@
 * published by the Free Software Foundation.
 */

#include <linux/psp.h>
#include <linux/psp-hygon.h>
#include <linux/bitfield.h>

#include "psp-dev.h"

@@ -28,3 +30,77 @@ int fixup_hygon_psp_caps(struct psp_device *psp)
			     PSP_CAPABILITY_PSP_SECURITY_REPORTING);
	return 0;
}

static int __psp_do_cmd_locked(int cmd, void *data, int *psp_ret)
{
	struct psp_device *psp = psp_master;
	struct sev_device *sev;
	unsigned int phys_lsb, phys_msb;
	unsigned int reg, ret = 0;

	if (!psp || !psp->sev_data || !hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (*hygon_psp_hooks.psp_dead)
		return -EBUSY;

	sev = psp->sev_data;

	/* Get the physical address of the command buffer */
	phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0;
	phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0;

	dev_dbg(sev->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
		cmd, phys_msb, phys_lsb, *hygon_psp_hooks.psp_timeout);

	print_hex_dump_debug("(in):  ", DUMP_PREFIX_OFFSET, 16, 2, data,
			     hygon_psp_hooks.sev_cmd_buffer_len(cmd), false);

	iowrite32(phys_lsb, sev->io_regs + sev->vdata->cmdbuff_addr_lo_reg);
	iowrite32(phys_msb, sev->io_regs + sev->vdata->cmdbuff_addr_hi_reg);

	sev->int_rcvd = 0;

	reg = FIELD_PREP(SEV_CMDRESP_CMD, cmd) | SEV_CMDRESP_IOC;
	iowrite32(reg, sev->io_regs + sev->vdata->cmdresp_reg);

	/* wait for command completion */
	ret = hygon_psp_hooks.sev_wait_cmd_ioc(sev, &reg, *hygon_psp_hooks.psp_timeout);
	if (ret) {
		if (psp_ret)
			*psp_ret = 0;

		dev_err(sev->dev, "sev command %#x timed out, disabling PSP\n", cmd);
		*hygon_psp_hooks.psp_dead = true;

		return ret;
	}

	*hygon_psp_hooks.psp_timeout = *hygon_psp_hooks.psp_cmd_timeout;

	if (psp_ret)
		*psp_ret = FIELD_GET(PSP_CMDRESP_STS, reg);

	if (FIELD_GET(PSP_CMDRESP_STS, reg)) {
		dev_dbg(sev->dev, "sev command %#x failed (%#010lx)\n",
			cmd, FIELD_GET(PSP_CMDRESP_STS, reg));
		ret = -EIO;
	}

	print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data,
			     hygon_psp_hooks.sev_cmd_buffer_len(cmd), false);

	return ret;
}

int psp_do_cmd(int cmd, void *data, int *psp_ret)
{
	int rc;

	mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
	rc = __psp_do_cmd_locked(cmd, data, psp_ret);
	mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);

	return rc;
}
EXPORT_SYMBOL_GPL(psp_do_cmd);
+4 −0
Original line number Diff line number Diff line
@@ -26,9 +26,13 @@ extern struct hygon_psp_hooks_table {
	struct mutex *sev_cmd_mutex;
	bool *psp_dead;
	int *psp_timeout;
	int *psp_cmd_timeout;
	int (*sev_cmd_buffer_len)(int cmd);
	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);
	int (*sev_wait_cmd_ioc)(struct sev_device *sev,
				unsigned int *reg, unsigned int timeout);
	long (*sev_ioctl)(struct file *file, unsigned int ioctl, unsigned long arg);
} hygon_psp_hooks;

+3 −0
Original line number Diff line number Diff line
@@ -1269,9 +1269,12 @@ static void sev_dev_install_hooks(void)
	hygon_psp_hooks.sev_cmd_mutex = &sev_cmd_mutex;
	hygon_psp_hooks.psp_dead = &psp_dead;
	hygon_psp_hooks.psp_timeout = &psp_timeout;
	hygon_psp_hooks.psp_cmd_timeout = &psp_cmd_timeout;
	hygon_psp_hooks.sev_cmd_buffer_len = sev_cmd_buffer_len;
	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_wait_cmd_ioc = sev_wait_cmd_ioc;
	hygon_psp_hooks.sev_ioctl = sev_ioctl;

	hygon_psp_hooks.sev_dev_hooks_installed = true;
+4 −0
Original line number Diff line number Diff line
@@ -129,6 +129,8 @@ struct csv_data_ring_buffer {

#ifdef CONFIG_CRYPTO_DEV_SP_PSP

int psp_do_cmd(int cmd, void *data, int *psp_ret);

int csv_ring_buffer_queue_init(void);
int csv_ring_buffer_queue_free(void);
int csv_fill_cmd_queue(int prio, int cmd, void *data, uint16_t flags);
@@ -142,6 +144,8 @@ int csv_issue_ringbuf_cmds_external_user(struct file *filep, int *psp_ret);

#else	/* !CONFIG_CRYPTO_DEV_SP_PSP */

static inline int psp_do_cmd(int cmd, void *data, int *psp_ret) { return -ENODEV; }

static inline int csv_ring_buffer_queue_init(void) { return -ENODEV; }
static inline int csv_ring_buffer_queue_free(void) { return -ENODEV; }
static inline