All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver
@ 2019-10-23 11:27 Thomas, Rijo-john
  2019-10-23 11:27 ` [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev Thomas, Rijo-john
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-23 11:27 UTC (permalink / raw)
  To: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Thomas, Rijo-john, Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

The goal of this patch series is to introduce TEE (Trusted Execution
Environment) interface support to AMD Secure Processor driver. The
TEE is a secure area of a processor which ensures that sensitive data
is stored, processed and protected in an isolated and trusted
environment. The Platform Security Processor (PSP) is a dedicated
processor which provides TEE to enable HW platform security. It offers
protection against software attacks generated in Rich Operating System
(Rich OS) such as Linux running on x86.

Based on the platform feature support, the PSP is capable of supporting
either SEV (Secure Encrypted Virtualization) and/or TEE. The first three
patches in this series is about moving SEV specific functions and data
structures from PSP device driver file to a dedicated SEV interface
driver file. The last two patches add TEE interface support to AMD
Secure Processor driver. This TEE interface will be used by AMD-TEE
driver to submit command buffers for processing in PSP Trusted Execution
Environment.

Rijo Thomas (5):
  crypto: ccp - rename psp-dev files to sev-dev
  crypto: ccp - create a generic psp-dev file
  crypto: ccp - move SEV vdata to a dedicated data structure
  crypto: ccp - add TEE support for Raven Ridge
  crypto: ccp - provide in-kernel API to submit TEE commands

 drivers/crypto/ccp/Makefile  |    4 +-
 drivers/crypto/ccp/psp-dev.c |  983 +++------------------------------------
 drivers/crypto/ccp/psp-dev.h |   50 +-
 drivers/crypto/ccp/sev-dev.c | 1041 ++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/ccp/sev-dev.h |   62 +++
 drivers/crypto/ccp/sp-dev.h  |   17 +-
 drivers/crypto/ccp/sp-pci.c  |   43 +-
 drivers/crypto/ccp/tee-dev.c |  363 +++++++++++++++
 drivers/crypto/ccp/tee-dev.h |  109 +++++
 include/linux/psp-tee.h      |   72 +++
 10 files changed, 1796 insertions(+), 948 deletions(-)
 create mode 100644 drivers/crypto/ccp/sev-dev.c
 create mode 100644 drivers/crypto/ccp/sev-dev.h
 create mode 100644 drivers/crypto/ccp/tee-dev.c
 create mode 100644 drivers/crypto/ccp/tee-dev.h
 create mode 100644 include/linux/psp-tee.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev
  2019-10-23 11:27 [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Thomas, Rijo-john
@ 2019-10-23 11:27 ` Thomas, Rijo-john
  2019-10-23 11:48   ` Ard Biesheuvel
  2019-10-23 11:27 ` [RFC PATCH 2/5] crypto: ccp - create a generic psp-dev file Thomas, Rijo-john
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-23 11:27 UTC (permalink / raw)
  To: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Thomas, Rijo-john, Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

This is a preliminary patch for creating a generic PSP device driver
file, which will have support for both SEV and TEE (Trusted Execution
Environment) interface.

This patch does not introduce any new functionality, but simply renames
psp-dev.c and psp-dev.h files to sev-dev.c and sev-dev.h files
respectively.

Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
---
 drivers/crypto/ccp/Makefile  |    2 +-
 drivers/crypto/ccp/psp-dev.c | 1087 ------------------------------------------
 drivers/crypto/ccp/psp-dev.h |   66 ---
 drivers/crypto/ccp/sev-dev.c | 1087 ++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/ccp/sev-dev.h |   66 +++
 drivers/crypto/ccp/sp-pci.c  |    2 +-
 6 files changed, 1155 insertions(+), 1155 deletions(-)
 delete mode 100644 drivers/crypto/ccp/psp-dev.c
 delete mode 100644 drivers/crypto/ccp/psp-dev.h
 create mode 100644 drivers/crypto/ccp/sev-dev.c
 create mode 100644 drivers/crypto/ccp/sev-dev.h

diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index 6b86f1e..9dafcf2 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -8,7 +8,7 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \
 	    ccp-dmaengine.o
 ccp-$(CONFIG_CRYPTO_DEV_CCP_DEBUGFS) += ccp-debugfs.o
 ccp-$(CONFIG_PCI) += sp-pci.o
-ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o
+ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += sev-dev.o

 obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
 ccp-crypto-objs := ccp-crypto-main.o \
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
deleted file mode 100644
index 6b17d17..0000000
--- a/drivers/crypto/ccp/psp-dev.c
+++ /dev/null
@@ -1,1087 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * AMD Platform Security Processor (PSP) interface
- *
- * Copyright (C) 2016,2018 Advanced Micro Devices, Inc.
- *
- * Author: Brijesh Singh <brijesh.singh@amd.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/spinlock_types.h>
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/hw_random.h>
-#include <linux/ccp.h>
-#include <linux/firmware.h>
-
-#include "sp-dev.h"
-#include "psp-dev.h"
-
-#define DEVICE_NAME		"sev"
-#define SEV_FW_FILE		"amd/sev.fw"
-#define SEV_FW_NAME_SIZE	64
-
-static DEFINE_MUTEX(sev_cmd_mutex);
-static struct sev_misc_dev *misc_dev;
-static struct psp_device *psp_master;
-
-static int psp_cmd_timeout = 100;
-module_param(psp_cmd_timeout, int, 0644);
-MODULE_PARM_DESC(psp_cmd_timeout, " default timeout value, in seconds, for PSP commands");
-
-static int psp_probe_timeout = 5;
-module_param(psp_probe_timeout, int, 0644);
-MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe");
-
-static bool psp_dead;
-static int psp_timeout;
-
-static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
-{
-	if (psp_master->api_major > maj)
-		return true;
-	if (psp_master->api_major == maj && psp_master->api_minor >= min)
-		return true;
-	return false;
-}
-
-static struct psp_device *psp_alloc_struct(struct sp_device *sp)
-{
-	struct device *dev = sp->dev;
-	struct psp_device *psp;
-
-	psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL);
-	if (!psp)
-		return NULL;
-
-	psp->dev = dev;
-	psp->sp = sp;
-
-	snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord);
-
-	return psp;
-}
-
-static irqreturn_t psp_irq_handler(int irq, void *data)
-{
-	struct psp_device *psp = data;
-	unsigned int status;
-	int reg;
-
-	/* Read the interrupt status: */
-	status = ioread32(psp->io_regs + psp->vdata->intsts_reg);
-
-	/* Check if it is command completion: */
-	if (!(status & PSP_CMD_COMPLETE))
-		goto done;
-
-	/* Check if it is SEV command completion: */
-	reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg);
-	if (reg & PSP_CMDRESP_RESP) {
-		psp->sev_int_rcvd = 1;
-		wake_up(&psp->sev_int_queue);
-	}
-
-done:
-	/* Clear the interrupt status by writing the same value we read. */
-	iowrite32(status, psp->io_regs + psp->vdata->intsts_reg);
-
-	return IRQ_HANDLED;
-}
-
-static int sev_wait_cmd_ioc(struct psp_device *psp,
-			    unsigned int *reg, unsigned int timeout)
-{
-	int ret;
-
-	ret = wait_event_timeout(psp->sev_int_queue,
-			psp->sev_int_rcvd, timeout * HZ);
-	if (!ret)
-		return -ETIMEDOUT;
-
-	*reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg);
-
-	return 0;
-}
-
-static int sev_cmd_buffer_len(int cmd)
-{
-	switch (cmd) {
-	case SEV_CMD_INIT:			return sizeof(struct sev_data_init);
-	case SEV_CMD_PLATFORM_STATUS:		return sizeof(struct sev_user_data_status);
-	case SEV_CMD_PEK_CSR:			return sizeof(struct sev_data_pek_csr);
-	case SEV_CMD_PEK_CERT_IMPORT:		return sizeof(struct sev_data_pek_cert_import);
-	case SEV_CMD_PDH_CERT_EXPORT:		return sizeof(struct sev_data_pdh_cert_export);
-	case SEV_CMD_LAUNCH_START:		return sizeof(struct sev_data_launch_start);
-	case SEV_CMD_LAUNCH_UPDATE_DATA:	return sizeof(struct sev_data_launch_update_data);
-	case SEV_CMD_LAUNCH_UPDATE_VMSA:	return sizeof(struct sev_data_launch_update_vmsa);
-	case SEV_CMD_LAUNCH_FINISH:		return sizeof(struct sev_data_launch_finish);
-	case SEV_CMD_LAUNCH_MEASURE:		return sizeof(struct sev_data_launch_measure);
-	case SEV_CMD_ACTIVATE:			return sizeof(struct sev_data_activate);
-	case SEV_CMD_DEACTIVATE:		return sizeof(struct sev_data_deactivate);
-	case SEV_CMD_DECOMMISSION:		return sizeof(struct sev_data_decommission);
-	case SEV_CMD_GUEST_STATUS:		return sizeof(struct sev_data_guest_status);
-	case SEV_CMD_DBG_DECRYPT:		return sizeof(struct sev_data_dbg);
-	case SEV_CMD_DBG_ENCRYPT:		return sizeof(struct sev_data_dbg);
-	case SEV_CMD_SEND_START:		return sizeof(struct sev_data_send_start);
-	case SEV_CMD_SEND_UPDATE_DATA:		return sizeof(struct sev_data_send_update_data);
-	case SEV_CMD_SEND_UPDATE_VMSA:		return sizeof(struct sev_data_send_update_vmsa);
-	case SEV_CMD_SEND_FINISH:		return sizeof(struct sev_data_send_finish);
-	case SEV_CMD_RECEIVE_START:		return sizeof(struct sev_data_receive_start);
-	case SEV_CMD_RECEIVE_FINISH:		return sizeof(struct sev_data_receive_finish);
-	case SEV_CMD_RECEIVE_UPDATE_DATA:	return sizeof(struct sev_data_receive_update_data);
-	case SEV_CMD_RECEIVE_UPDATE_VMSA:	return sizeof(struct sev_data_receive_update_vmsa);
-	case SEV_CMD_LAUNCH_UPDATE_SECRET:	return sizeof(struct sev_data_launch_secret);
-	case SEV_CMD_DOWNLOAD_FIRMWARE:		return sizeof(struct sev_data_download_firmware);
-	case SEV_CMD_GET_ID:			return sizeof(struct sev_data_get_id);
-	default:				return 0;
-	}
-
-	return 0;
-}
-
-static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
-{
-	struct psp_device *psp = psp_master;
-	unsigned int phys_lsb, phys_msb;
-	unsigned int reg, ret = 0;
-
-	if (!psp)
-		return -ENODEV;
-
-	if (psp_dead)
-		return -EBUSY;
-
-	/* 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(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
-		cmd, phys_msb, phys_lsb, psp_timeout);
-
-	print_hex_dump_debug("(in):  ", DUMP_PREFIX_OFFSET, 16, 2, data,
-			     sev_cmd_buffer_len(cmd), false);
-
-	iowrite32(phys_lsb, psp->io_regs + psp->vdata->cmdbuff_addr_lo_reg);
-	iowrite32(phys_msb, psp->io_regs + psp->vdata->cmdbuff_addr_hi_reg);
-
-	psp->sev_int_rcvd = 0;
-
-	reg = cmd;
-	reg <<= PSP_CMDRESP_CMD_SHIFT;
-	reg |= PSP_CMDRESP_IOC;
-	iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg);
-
-	/* wait for command completion */
-	ret = sev_wait_cmd_ioc(psp, &reg, psp_timeout);
-	if (ret) {
-		if (psp_ret)
-			*psp_ret = 0;
-
-		dev_err(psp->dev, "sev command %#x timed out, disabling PSP \n", cmd);
-		psp_dead = true;
-
-		return ret;
-	}
-
-	psp_timeout = psp_cmd_timeout;
-
-	if (psp_ret)
-		*psp_ret = reg & PSP_CMDRESP_ERR_MASK;
-
-	if (reg & PSP_CMDRESP_ERR_MASK) {
-		dev_dbg(psp->dev, "sev command %#x failed (%#010x)\n",
-			cmd, reg & PSP_CMDRESP_ERR_MASK);
-		ret = -EIO;
-	}
-
-	print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data,
-			     sev_cmd_buffer_len(cmd), false);
-
-	return ret;
-}
-
-static int sev_do_cmd(int cmd, void *data, int *psp_ret)
-{
-	int rc;
-
-	mutex_lock(&sev_cmd_mutex);
-	rc = __sev_do_cmd_locked(cmd, data, psp_ret);
-	mutex_unlock(&sev_cmd_mutex);
-
-	return rc;
-}
-
-static int __sev_platform_init_locked(int *error)
-{
-	struct psp_device *psp = psp_master;
-	int rc = 0;
-
-	if (!psp)
-		return -ENODEV;
-
-	if (psp->sev_state == SEV_STATE_INIT)
-		return 0;
-
-	rc = __sev_do_cmd_locked(SEV_CMD_INIT, &psp->init_cmd_buf, error);
-	if (rc)
-		return rc;
-
-	psp->sev_state = SEV_STATE_INIT;
-	dev_dbg(psp->dev, "SEV firmware initialized\n");
-
-	return rc;
-}
-
-int sev_platform_init(int *error)
-{
-	int rc;
-
-	mutex_lock(&sev_cmd_mutex);
-	rc = __sev_platform_init_locked(error);
-	mutex_unlock(&sev_cmd_mutex);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(sev_platform_init);
-
-static int __sev_platform_shutdown_locked(int *error)
-{
-	int ret;
-
-	ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error);
-	if (ret)
-		return ret;
-
-	psp_master->sev_state = SEV_STATE_UNINIT;
-	dev_dbg(psp_master->dev, "SEV firmware shutdown\n");
-
-	return ret;
-}
-
-static int sev_platform_shutdown(int *error)
-{
-	int rc;
-
-	mutex_lock(&sev_cmd_mutex);
-	rc = __sev_platform_shutdown_locked(NULL);
-	mutex_unlock(&sev_cmd_mutex);
-
-	return rc;
-}
-
-static int sev_get_platform_state(int *state, int *error)
-{
-	int rc;
-
-	rc = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS,
-				 &psp_master->status_cmd_buf, error);
-	if (rc)
-		return rc;
-
-	*state = psp_master->status_cmd_buf.state;
-	return rc;
-}
-
-static int sev_ioctl_do_reset(struct sev_issue_cmd *argp)
-{
-	int state, rc;
-
-	/*
-	 * The SEV spec requires that FACTORY_RESET must be issued in
-	 * UNINIT state. Before we go further lets check if any guest is
-	 * active.
-	 *
-	 * If FW is in WORKING state then deny the request otherwise issue
-	 * SHUTDOWN command do INIT -> UNINIT before issuing the FACTORY_RESET.
-	 *
-	 */
-	rc = sev_get_platform_state(&state, &argp->error);
-	if (rc)
-		return rc;
-
-	if (state == SEV_STATE_WORKING)
-		return -EBUSY;
-
-	if (state == SEV_STATE_INIT) {
-		rc = __sev_platform_shutdown_locked(&argp->error);
-		if (rc)
-			return rc;
-	}
-
-	return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, NULL, &argp->error);
-}
-
-static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)
-{
-	struct sev_user_data_status *data = &psp_master->status_cmd_buf;
-	int ret;
-
-	ret = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, data, &argp->error);
-	if (ret)
-		return ret;
-
-	if (copy_to_user((void __user *)argp->data, data, sizeof(*data)))
-		ret = -EFAULT;
-
-	return ret;
-}
-
-static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp)
-{
-	int rc;
-
-	if (psp_master->sev_state == SEV_STATE_UNINIT) {
-		rc = __sev_platform_init_locked(&argp->error);
-		if (rc)
-			return rc;
-	}
-
-	return __sev_do_cmd_locked(cmd, NULL, &argp->error);
-}
-
-static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp)
-{
-	struct sev_user_data_pek_csr input;
-	struct sev_data_pek_csr *data;
-	void *blob = NULL;
-	int ret;
-
-	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
-		return -EFAULT;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	/* userspace wants to query CSR length */
-	if (!input.address || !input.length)
-		goto cmd;
-
-	/* allocate a physically contiguous buffer to store the CSR blob */
-	if (!access_ok(input.address, input.length) ||
-	    input.length > SEV_FW_BLOB_MAX_SIZE) {
-		ret = -EFAULT;
-		goto e_free;
-	}
-
-	blob = kmalloc(input.length, GFP_KERNEL);
-	if (!blob) {
-		ret = -ENOMEM;
-		goto e_free;
-	}
-
-	data->address = __psp_pa(blob);
-	data->len = input.length;
-
-cmd:
-	if (psp_master->sev_state == SEV_STATE_UNINIT) {
-		ret = __sev_platform_init_locked(&argp->error);
-		if (ret)
-			goto e_free_blob;
-	}
-
-	ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, data, &argp->error);
-
-	 /* If we query the CSR length, FW responded with expected data. */
-	input.length = data->len;
-
-	if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) {
-		ret = -EFAULT;
-		goto e_free_blob;
-	}
-
-	if (blob) {
-		if (copy_to_user((void __user *)input.address, blob, input.length))
-			ret = -EFAULT;
-	}
-
-e_free_blob:
-	kfree(blob);
-e_free:
-	kfree(data);
-	return ret;
-}
-
-void *psp_copy_user_blob(u64 __user uaddr, u32 len)
-{
-	if (!uaddr || !len)
-		return ERR_PTR(-EINVAL);
-
-	/* verify that blob length does not exceed our limit */
-	if (len > SEV_FW_BLOB_MAX_SIZE)
-		return ERR_PTR(-EINVAL);
-
-	return memdup_user((void __user *)(uintptr_t)uaddr, len);
-}
-EXPORT_SYMBOL_GPL(psp_copy_user_blob);
-
-static int sev_get_api_version(void)
-{
-	struct sev_user_data_status *status;
-	int error = 0, ret;
-
-	status = &psp_master->status_cmd_buf;
-	ret = sev_platform_status(status, &error);
-	if (ret) {
-		dev_err(psp_master->dev,
-			"SEV: failed to get status. Error: %#x\n", error);
-		return 1;
-	}
-
-	psp_master->api_major = status->api_major;
-	psp_master->api_minor = status->api_minor;
-	psp_master->build = status->build;
-	psp_master->sev_state = status->state;
-
-	return 0;
-}
-
-static int sev_get_firmware(struct device *dev,
-			    const struct firmware **firmware)
-{
-	char fw_name_specific[SEV_FW_NAME_SIZE];
-	char fw_name_subset[SEV_FW_NAME_SIZE];
-
-	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);
-
-	snprintf(fw_name_subset, sizeof(fw_name_subset),
-		 "amd/amd_sev_fam%.2xh_model%.1xxh.sbin",
-		 boot_cpu_data.x86, (boot_cpu_data.x86_model & 0xf0) >> 4);
-
-	/* Check for SEV FW for a particular model.
-	 * Ex. amd_sev_fam17h_model00h.sbin for Family 17h Model 00h
-	 *
-	 * or
-	 *
-	 * Check for SEV FW common to a subset of models.
-	 * Ex. amd_sev_fam17h_model0xh.sbin for
-	 *     Family 17h Model 00h -- Family 17h Model 0Fh
-	 *
-	 * or
-	 *
-	 * Fall-back to using generic name: sev.fw
-	 */
-	if ((firmware_request_nowarn(firmware, fw_name_specific, dev) >= 0) ||
-	    (firmware_request_nowarn(firmware, fw_name_subset, dev) >= 0) ||
-	    (firmware_request_nowarn(firmware, SEV_FW_FILE, dev) >= 0))
-		return 0;
-
-	return -ENOENT;
-}
-
-/* Don't fail if SEV FW couldn't be updated. Continue with existing SEV FW */
-static int sev_update_firmware(struct device *dev)
-{
-	struct sev_data_download_firmware *data;
-	const struct firmware *firmware;
-	int ret, error, order;
-	struct page *p;
-	u64 data_size;
-
-	if (sev_get_firmware(dev, &firmware) == -ENOENT) {
-		dev_dbg(dev, "No SEV firmware file present\n");
-		return -1;
-	}
-
-	/*
-	 * SEV 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 SEV
-	 * FW. Allocate enough memory for data structure + alignment
-	 * padding + SEV FW.
-	 */
-	data_size = ALIGN(sizeof(struct sev_data_download_firmware), 32);
-
-	order = get_order(firmware->size + data_size);
-	p = alloc_pages(GFP_KERNEL, order);
-	if (!p) {
-		ret = -1;
-		goto fw_err;
-	}
-
-	/*
-	 * Copy firmware data to a kernel allocated contiguous
-	 * memory region.
-	 */
-	data = page_address(p);
-	memcpy(page_address(p) + data_size, firmware->data, firmware->size);
-
-	data->address = __psp_pa(page_address(p) + data_size);
-	data->len = firmware->size;
-
-	ret = sev_do_cmd(SEV_CMD_DOWNLOAD_FIRMWARE, data, &error);
-	if (ret)
-		dev_dbg(dev, "Failed to update SEV firmware: %#x\n", error);
-	else
-		dev_info(dev, "SEV firmware update successful\n");
-
-	__free_pages(p, order);
-
-fw_err:
-	release_firmware(firmware);
-
-	return ret;
-}
-
-static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp)
-{
-	struct sev_user_data_pek_cert_import input;
-	struct sev_data_pek_cert_import *data;
-	void *pek_blob, *oca_blob;
-	int ret;
-
-	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
-		return -EFAULT;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	/* copy PEK certificate blobs from userspace */
-	pek_blob = psp_copy_user_blob(input.pek_cert_address, input.pek_cert_len);
-	if (IS_ERR(pek_blob)) {
-		ret = PTR_ERR(pek_blob);
-		goto e_free;
-	}
-
-	data->pek_cert_address = __psp_pa(pek_blob);
-	data->pek_cert_len = input.pek_cert_len;
-
-	/* copy PEK certificate blobs from userspace */
-	oca_blob = psp_copy_user_blob(input.oca_cert_address, input.oca_cert_len);
-	if (IS_ERR(oca_blob)) {
-		ret = PTR_ERR(oca_blob);
-		goto e_free_pek;
-	}
-
-	data->oca_cert_address = __psp_pa(oca_blob);
-	data->oca_cert_len = input.oca_cert_len;
-
-	/* If platform is not in INIT state then transition it to INIT */
-	if (psp_master->sev_state != SEV_STATE_INIT) {
-		ret = __sev_platform_init_locked(&argp->error);
-		if (ret)
-			goto e_free_oca;
-	}
-
-	ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, data, &argp->error);
-
-e_free_oca:
-	kfree(oca_blob);
-e_free_pek:
-	kfree(pek_blob);
-e_free:
-	kfree(data);
-	return ret;
-}
-
-static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp)
-{
-	struct sev_user_data_get_id2 input;
-	struct sev_data_get_id *data;
-	void *id_blob = NULL;
-	int ret;
-
-	/* SEV GET_ID is available from SEV API v0.16 and up */
-	if (!sev_version_greater_or_equal(0, 16))
-		return -ENOTSUPP;
-
-	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
-		return -EFAULT;
-
-	/* Check if we have write access to the userspace buffer */
-	if (input.address &&
-	    input.length &&
-	    !access_ok(input.address, input.length))
-		return -EFAULT;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	if (input.address && input.length) {
-		id_blob = kmalloc(input.length, GFP_KERNEL);
-		if (!id_blob) {
-			kfree(data);
-			return -ENOMEM;
-		}
-
-		data->address = __psp_pa(id_blob);
-		data->len = input.length;
-	}
-
-	ret = __sev_do_cmd_locked(SEV_CMD_GET_ID, data, &argp->error);
-
-	/*
-	 * Firmware will return the length of the ID value (either the minimum
-	 * required length or the actual length written), return it to the user.
-	 */
-	input.length = data->len;
-
-	if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) {
-		ret = -EFAULT;
-		goto e_free;
-	}
-
-	if (id_blob) {
-		if (copy_to_user((void __user *)input.address,
-				 id_blob, data->len)) {
-			ret = -EFAULT;
-			goto e_free;
-		}
-	}
-
-e_free:
-	kfree(id_blob);
-	kfree(data);
-
-	return ret;
-}
-
-static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp)
-{
-	struct sev_data_get_id *data;
-	u64 data_size, user_size;
-	void *id_blob, *mem;
-	int ret;
-
-	/* SEV GET_ID available from SEV API v0.16 and up */
-	if (!sev_version_greater_or_equal(0, 16))
-		return -ENOTSUPP;
-
-	/* SEV FW expects the buffer it fills with the ID to be
-	 * 8-byte aligned. Memory allocated should be enough to
-	 * hold data structure + alignment padding + memory
-	 * where SEV FW writes the ID.
-	 */
-	data_size = ALIGN(sizeof(struct sev_data_get_id), 8);
-	user_size = sizeof(struct sev_user_data_get_id);
-
-	mem = kzalloc(data_size + user_size, GFP_KERNEL);
-	if (!mem)
-		return -ENOMEM;
-
-	data = mem;
-	id_blob = mem + data_size;
-
-	data->address = __psp_pa(id_blob);
-	data->len = user_size;
-
-	ret = __sev_do_cmd_locked(SEV_CMD_GET_ID, data, &argp->error);
-	if (!ret) {
-		if (copy_to_user((void __user *)argp->data, id_blob, data->len))
-			ret = -EFAULT;
-	}
-
-	kfree(mem);
-
-	return ret;
-}
-
-static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp)
-{
-	struct sev_user_data_pdh_cert_export input;
-	void *pdh_blob = NULL, *cert_blob = NULL;
-	struct sev_data_pdh_cert_export *data;
-	int ret;
-
-	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
-		return -EFAULT;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	/* Userspace wants to query the certificate length. */
-	if (!input.pdh_cert_address ||
-	    !input.pdh_cert_len ||
-	    !input.cert_chain_address)
-		goto cmd;
-
-	/* Allocate a physically contiguous buffer to store the PDH blob. */
-	if ((input.pdh_cert_len > SEV_FW_BLOB_MAX_SIZE) ||
-	    !access_ok(input.pdh_cert_address, input.pdh_cert_len)) {
-		ret = -EFAULT;
-		goto e_free;
-	}
-
-	/* Allocate a physically contiguous buffer to store the cert chain blob. */
-	if ((input.cert_chain_len > SEV_FW_BLOB_MAX_SIZE) ||
-	    !access_ok(input.cert_chain_address, input.cert_chain_len)) {
-		ret = -EFAULT;
-		goto e_free;
-	}
-
-	pdh_blob = kmalloc(input.pdh_cert_len, GFP_KERNEL);
-	if (!pdh_blob) {
-		ret = -ENOMEM;
-		goto e_free;
-	}
-
-	data->pdh_cert_address = __psp_pa(pdh_blob);
-	data->pdh_cert_len = input.pdh_cert_len;
-
-	cert_blob = kmalloc(input.cert_chain_len, GFP_KERNEL);
-	if (!cert_blob) {
-		ret = -ENOMEM;
-		goto e_free_pdh;
-	}
-
-	data->cert_chain_address = __psp_pa(cert_blob);
-	data->cert_chain_len = input.cert_chain_len;
-
-cmd:
-	/* If platform is not in INIT state then transition it to INIT. */
-	if (psp_master->sev_state != SEV_STATE_INIT) {
-		ret = __sev_platform_init_locked(&argp->error);
-		if (ret)
-			goto e_free_cert;
-	}
-
-	ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, data, &argp->error);
-
-	/* If we query the length, FW responded with expected data. */
-	input.cert_chain_len = data->cert_chain_len;
-	input.pdh_cert_len = data->pdh_cert_len;
-
-	if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) {
-		ret = -EFAULT;
-		goto e_free_cert;
-	}
-
-	if (pdh_blob) {
-		if (copy_to_user((void __user *)input.pdh_cert_address,
-				 pdh_blob, input.pdh_cert_len)) {
-			ret = -EFAULT;
-			goto e_free_cert;
-		}
-	}
-
-	if (cert_blob) {
-		if (copy_to_user((void __user *)input.cert_chain_address,
-				 cert_blob, input.cert_chain_len))
-			ret = -EFAULT;
-	}
-
-e_free_cert:
-	kfree(cert_blob);
-e_free_pdh:
-	kfree(pdh_blob);
-e_free:
-	kfree(data);
-	return ret;
-}
-
-static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
-{
-	void __user *argp = (void __user *)arg;
-	struct sev_issue_cmd input;
-	int ret = -EFAULT;
-
-	if (!psp_master)
-		return -ENODEV;
-
-	if (ioctl != SEV_ISSUE_CMD)
-		return -EINVAL;
-
-	if (copy_from_user(&input, argp, sizeof(struct sev_issue_cmd)))
-		return -EFAULT;
-
-	if (input.cmd > SEV_MAX)
-		return -EINVAL;
-
-	mutex_lock(&sev_cmd_mutex);
-
-	switch (input.cmd) {
-
-	case SEV_FACTORY_RESET:
-		ret = sev_ioctl_do_reset(&input);
-		break;
-	case SEV_PLATFORM_STATUS:
-		ret = sev_ioctl_do_platform_status(&input);
-		break;
-	case SEV_PEK_GEN:
-		ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PEK_GEN, &input);
-		break;
-	case SEV_PDH_GEN:
-		ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input);
-		break;
-	case SEV_PEK_CSR:
-		ret = sev_ioctl_do_pek_csr(&input);
-		break;
-	case SEV_PEK_CERT_IMPORT:
-		ret = sev_ioctl_do_pek_import(&input);
-		break;
-	case SEV_PDH_CERT_EXPORT:
-		ret = sev_ioctl_do_pdh_export(&input);
-		break;
-	case SEV_GET_ID:
-		pr_warn_once("SEV_GET_ID command is deprecated, use SEV_GET_ID2\n");
-		ret = sev_ioctl_do_get_id(&input);
-		break;
-	case SEV_GET_ID2:
-		ret = sev_ioctl_do_get_id2(&input);
-		break;
-	default:
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
-		ret = -EFAULT;
-out:
-	mutex_unlock(&sev_cmd_mutex);
-
-	return ret;
-}
-
-static const struct file_operations sev_fops = {
-	.owner	= THIS_MODULE,
-	.unlocked_ioctl = sev_ioctl,
-};
-
-int sev_platform_status(struct sev_user_data_status *data, int *error)
-{
-	return sev_do_cmd(SEV_CMD_PLATFORM_STATUS, data, error);
-}
-EXPORT_SYMBOL_GPL(sev_platform_status);
-
-int sev_guest_deactivate(struct sev_data_deactivate *data, int *error)
-{
-	return sev_do_cmd(SEV_CMD_DEACTIVATE, data, error);
-}
-EXPORT_SYMBOL_GPL(sev_guest_deactivate);
-
-int sev_guest_activate(struct sev_data_activate *data, int *error)
-{
-	return sev_do_cmd(SEV_CMD_ACTIVATE, data, error);
-}
-EXPORT_SYMBOL_GPL(sev_guest_activate);
-
-int sev_guest_decommission(struct sev_data_decommission *data, int *error)
-{
-	return sev_do_cmd(SEV_CMD_DECOMMISSION, data, error);
-}
-EXPORT_SYMBOL_GPL(sev_guest_decommission);
-
-int sev_guest_df_flush(int *error)
-{
-	return sev_do_cmd(SEV_CMD_DF_FLUSH, NULL, error);
-}
-EXPORT_SYMBOL_GPL(sev_guest_df_flush);
-
-static void sev_exit(struct kref *ref)
-{
-	struct sev_misc_dev *misc_dev = container_of(ref, struct sev_misc_dev, refcount);
-
-	misc_deregister(&misc_dev->misc);
-}
-
-static int sev_misc_init(struct psp_device *psp)
-{
-	struct device *dev = psp->dev;
-	int ret;
-
-	/*
-	 * SEV feature support can be detected on multiple devices but the SEV
-	 * FW commands must be issued on the master. During probe, we do not
-	 * know the master hence we create /dev/sev on the first device probe.
-	 * sev_do_cmd() finds the right master device to which to issue the
-	 * command to the firmware.
-	 */
-	if (!misc_dev) {
-		struct miscdevice *misc;
-
-		misc_dev = devm_kzalloc(dev, sizeof(*misc_dev), GFP_KERNEL);
-		if (!misc_dev)
-			return -ENOMEM;
-
-		misc = &misc_dev->misc;
-		misc->minor = MISC_DYNAMIC_MINOR;
-		misc->name = DEVICE_NAME;
-		misc->fops = &sev_fops;
-
-		ret = misc_register(misc);
-		if (ret)
-			return ret;
-
-		kref_init(&misc_dev->refcount);
-	} else {
-		kref_get(&misc_dev->refcount);
-	}
-
-	init_waitqueue_head(&psp->sev_int_queue);
-	psp->sev_misc = misc_dev;
-	dev_dbg(dev, "registered SEV device\n");
-
-	return 0;
-}
-
-static int psp_check_sev_support(struct psp_device *psp)
-{
-	/* Check if device supports SEV feature */
-	if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) {
-		dev_dbg(psp->dev, "psp does not support SEV\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-int psp_dev_init(struct sp_device *sp)
-{
-	struct device *dev = sp->dev;
-	struct psp_device *psp;
-	int ret;
-
-	ret = -ENOMEM;
-	psp = psp_alloc_struct(sp);
-	if (!psp)
-		goto e_err;
-
-	sp->psp_data = psp;
-
-	psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata;
-	if (!psp->vdata) {
-		ret = -ENODEV;
-		dev_err(dev, "missing driver data\n");
-		goto e_err;
-	}
-
-	psp->io_regs = sp->io_map;
-
-	ret = psp_check_sev_support(psp);
-	if (ret)
-		goto e_disable;
-
-	/* Disable and clear interrupts until ready */
-	iowrite32(0, psp->io_regs + psp->vdata->inten_reg);
-	iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg);
-
-	/* Request an irq */
-	ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
-	if (ret) {
-		dev_err(dev, "psp: unable to allocate an IRQ\n");
-		goto e_err;
-	}
-
-	ret = sev_misc_init(psp);
-	if (ret)
-		goto e_irq;
-
-	if (sp->set_psp_master_device)
-		sp->set_psp_master_device(sp);
-
-	/* Enable interrupt */
-	iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
-
-	dev_notice(dev, "psp enabled\n");
-
-	return 0;
-
-e_irq:
-	sp_free_psp_irq(psp->sp, psp);
-e_err:
-	sp->psp_data = NULL;
-
-	dev_notice(dev, "psp initialization failed\n");
-
-	return ret;
-
-e_disable:
-	sp->psp_data = NULL;
-
-	return ret;
-}
-
-void psp_dev_destroy(struct sp_device *sp)
-{
-	struct psp_device *psp = sp->psp_data;
-
-	if (!psp)
-		return;
-
-	if (psp->sev_misc)
-		kref_put(&misc_dev->refcount, sev_exit);
-
-	sp_free_psp_irq(sp, psp);
-}
-
-int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd,
-				void *data, int *error)
-{
-	if (!filep || filep->f_op != &sev_fops)
-		return -EBADF;
-
-	return  sev_do_cmd(cmd, data, error);
-}
-EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
-
-void psp_pci_init(void)
-{
-	struct sp_device *sp;
-	int error, rc;
-
-	sp = sp_get_psp_master_device();
-	if (!sp)
-		return;
-
-	psp_master = sp->psp_data;
-
-	psp_timeout = psp_probe_timeout;
-
-	if (sev_get_api_version())
-		goto err;
-
-	/*
-	 * If platform is not in UNINIT state then firmware upgrade and/or
-	 * platform INIT command will fail. These command require UNINIT state.
-	 *
-	 * In a normal boot we should never run into case where the firmware
-	 * is not in UNINIT state on boot. But in case of kexec boot, a reboot
-	 * may not go through a typical shutdown sequence and may leave the
-	 * firmware in INIT or WORKING state.
-	 */
-
-	if (psp_master->sev_state != SEV_STATE_UNINIT) {
-		sev_platform_shutdown(NULL);
-		psp_master->sev_state = SEV_STATE_UNINIT;
-	}
-
-	if (sev_version_greater_or_equal(0, 15) &&
-	    sev_update_firmware(psp_master->dev) == 0)
-		sev_get_api_version();
-
-	/* Initialize the platform */
-	rc = sev_platform_init(&error);
-	if (rc) {
-		dev_err(sp->dev, "SEV: failed to INIT error %#x\n", error);
-		return;
-	}
-
-	dev_info(sp->dev, "SEV API:%d.%d build:%d\n", psp_master->api_major,
-		 psp_master->api_minor, psp_master->build);
-
-	return;
-
-err:
-	psp_master = NULL;
-}
-
-void psp_pci_exit(void)
-{
-	if (!psp_master)
-		return;
-
-	sev_platform_shutdown(NULL);
-}
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
deleted file mode 100644
index 82a084f..0000000
--- a/drivers/crypto/ccp/psp-dev.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * AMD Platform Security Processor (PSP) interface driver
- *
- * Copyright (C) 2017-2018 Advanced Micro Devices, Inc.
- *
- * Author: Brijesh Singh <brijesh.singh@amd.com>
- */
-
-#ifndef __PSP_DEV_H__
-#define __PSP_DEV_H__
-
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/dmapool.h>
-#include <linux/hw_random.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/irqreturn.h>
-#include <linux/dmaengine.h>
-#include <linux/psp-sev.h>
-#include <linux/miscdevice.h>
-
-#include "sp-dev.h"
-
-#define PSP_CMD_COMPLETE		BIT(1)
-
-#define PSP_CMDRESP_CMD_SHIFT		16
-#define PSP_CMDRESP_IOC			BIT(0)
-#define PSP_CMDRESP_RESP		BIT(31)
-#define PSP_CMDRESP_ERR_MASK		0xffff
-
-#define MAX_PSP_NAME_LEN		16
-
-struct sev_misc_dev {
-	struct kref refcount;
-	struct miscdevice misc;
-};
-
-struct psp_device {
-	struct list_head entry;
-
-	struct psp_vdata *vdata;
-	char name[MAX_PSP_NAME_LEN];
-
-	struct device *dev;
-	struct sp_device *sp;
-
-	void __iomem *io_regs;
-
-	int sev_state;
-	unsigned int sev_int_rcvd;
-	wait_queue_head_t sev_int_queue;
-	struct sev_misc_dev *sev_misc;
-	struct sev_user_data_status status_cmd_buf;
-	struct sev_data_init init_cmd_buf;
-
-	u8 api_major;
-	u8 api_minor;
-	u8 build;
-};
-
-#endif /* __PSP_DEV_H */
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
new file mode 100644
index 0000000..77841a8
--- /dev/null
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -0,0 +1,1087 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AMD Secure Encrypted Virtualization (SEV) interface
+ *
+ * Copyright (C) 2016,2019 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <brijesh.singh@amd.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/hw_random.h>
+#include <linux/ccp.h>
+#include <linux/firmware.h>
+
+#include "sp-dev.h"
+#include "sev-dev.h"
+
+#define DEVICE_NAME		"sev"
+#define SEV_FW_FILE		"amd/sev.fw"
+#define SEV_FW_NAME_SIZE	64
+
+static DEFINE_MUTEX(sev_cmd_mutex);
+static struct sev_misc_dev *misc_dev;
+static struct psp_device *psp_master;
+
+static int psp_cmd_timeout = 100;
+module_param(psp_cmd_timeout, int, 0644);
+MODULE_PARM_DESC(psp_cmd_timeout, " default timeout value, in seconds, for PSP commands");
+
+static int psp_probe_timeout = 5;
+module_param(psp_probe_timeout, int, 0644);
+MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe");
+
+static bool psp_dead;
+static int psp_timeout;
+
+static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
+{
+	if (psp_master->api_major > maj)
+		return true;
+	if (psp_master->api_major == maj && psp_master->api_minor >= min)
+		return true;
+	return false;
+}
+
+static struct psp_device *psp_alloc_struct(struct sp_device *sp)
+{
+	struct device *dev = sp->dev;
+	struct psp_device *psp;
+
+	psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL);
+	if (!psp)
+		return NULL;
+
+	psp->dev = dev;
+	psp->sp = sp;
+
+	snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord);
+
+	return psp;
+}
+
+static irqreturn_t psp_irq_handler(int irq, void *data)
+{
+	struct psp_device *psp = data;
+	unsigned int status;
+	int reg;
+
+	/* Read the interrupt status: */
+	status = ioread32(psp->io_regs + psp->vdata->intsts_reg);
+
+	/* Check if it is command completion: */
+	if (!(status & PSP_CMD_COMPLETE))
+		goto done;
+
+	/* Check if it is SEV command completion: */
+	reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg);
+	if (reg & PSP_CMDRESP_RESP) {
+		psp->sev_int_rcvd = 1;
+		wake_up(&psp->sev_int_queue);
+	}
+
+done:
+	/* Clear the interrupt status by writing the same value we read. */
+	iowrite32(status, psp->io_regs + psp->vdata->intsts_reg);
+
+	return IRQ_HANDLED;
+}
+
+static int sev_wait_cmd_ioc(struct psp_device *psp,
+			    unsigned int *reg, unsigned int timeout)
+{
+	int ret;
+
+	ret = wait_event_timeout(psp->sev_int_queue,
+			psp->sev_int_rcvd, timeout * HZ);
+	if (!ret)
+		return -ETIMEDOUT;
+
+	*reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg);
+
+	return 0;
+}
+
+static int sev_cmd_buffer_len(int cmd)
+{
+	switch (cmd) {
+	case SEV_CMD_INIT:			return sizeof(struct sev_data_init);
+	case SEV_CMD_PLATFORM_STATUS:		return sizeof(struct sev_user_data_status);
+	case SEV_CMD_PEK_CSR:			return sizeof(struct sev_data_pek_csr);
+	case SEV_CMD_PEK_CERT_IMPORT:		return sizeof(struct sev_data_pek_cert_import);
+	case SEV_CMD_PDH_CERT_EXPORT:		return sizeof(struct sev_data_pdh_cert_export);
+	case SEV_CMD_LAUNCH_START:		return sizeof(struct sev_data_launch_start);
+	case SEV_CMD_LAUNCH_UPDATE_DATA:	return sizeof(struct sev_data_launch_update_data);
+	case SEV_CMD_LAUNCH_UPDATE_VMSA:	return sizeof(struct sev_data_launch_update_vmsa);
+	case SEV_CMD_LAUNCH_FINISH:		return sizeof(struct sev_data_launch_finish);
+	case SEV_CMD_LAUNCH_MEASURE:		return sizeof(struct sev_data_launch_measure);
+	case SEV_CMD_ACTIVATE:			return sizeof(struct sev_data_activate);
+	case SEV_CMD_DEACTIVATE:		return sizeof(struct sev_data_deactivate);
+	case SEV_CMD_DECOMMISSION:		return sizeof(struct sev_data_decommission);
+	case SEV_CMD_GUEST_STATUS:		return sizeof(struct sev_data_guest_status);
+	case SEV_CMD_DBG_DECRYPT:		return sizeof(struct sev_data_dbg);
+	case SEV_CMD_DBG_ENCRYPT:		return sizeof(struct sev_data_dbg);
+	case SEV_CMD_SEND_START:		return sizeof(struct sev_data_send_start);
+	case SEV_CMD_SEND_UPDATE_DATA:		return sizeof(struct sev_data_send_update_data);
+	case SEV_CMD_SEND_UPDATE_VMSA:		return sizeof(struct sev_data_send_update_vmsa);
+	case SEV_CMD_SEND_FINISH:		return sizeof(struct sev_data_send_finish);
+	case SEV_CMD_RECEIVE_START:		return sizeof(struct sev_data_receive_start);
+	case SEV_CMD_RECEIVE_FINISH:		return sizeof(struct sev_data_receive_finish);
+	case SEV_CMD_RECEIVE_UPDATE_DATA:	return sizeof(struct sev_data_receive_update_data);
+	case SEV_CMD_RECEIVE_UPDATE_VMSA:	return sizeof(struct sev_data_receive_update_vmsa);
+	case SEV_CMD_LAUNCH_UPDATE_SECRET:	return sizeof(struct sev_data_launch_secret);
+	case SEV_CMD_DOWNLOAD_FIRMWARE:		return sizeof(struct sev_data_download_firmware);
+	case SEV_CMD_GET_ID:			return sizeof(struct sev_data_get_id);
+	default:				return 0;
+	}
+
+	return 0;
+}
+
+static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
+{
+	struct psp_device *psp = psp_master;
+	unsigned int phys_lsb, phys_msb;
+	unsigned int reg, ret = 0;
+
+	if (!psp)
+		return -ENODEV;
+
+	if (psp_dead)
+		return -EBUSY;
+
+	/* 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(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
+		cmd, phys_msb, phys_lsb, psp_timeout);
+
+	print_hex_dump_debug("(in):  ", DUMP_PREFIX_OFFSET, 16, 2, data,
+			     sev_cmd_buffer_len(cmd), false);
+
+	iowrite32(phys_lsb, psp->io_regs + psp->vdata->cmdbuff_addr_lo_reg);
+	iowrite32(phys_msb, psp->io_regs + psp->vdata->cmdbuff_addr_hi_reg);
+
+	psp->sev_int_rcvd = 0;
+
+	reg = cmd;
+	reg <<= PSP_CMDRESP_CMD_SHIFT;
+	reg |= PSP_CMDRESP_IOC;
+	iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg);
+
+	/* wait for command completion */
+	ret = sev_wait_cmd_ioc(psp, &reg, psp_timeout);
+	if (ret) {
+		if (psp_ret)
+			*psp_ret = 0;
+
+		dev_err(psp->dev, "sev command %#x timed out, disabling PSP \n", cmd);
+		psp_dead = true;
+
+		return ret;
+	}
+
+	psp_timeout = psp_cmd_timeout;
+
+	if (psp_ret)
+		*psp_ret = reg & PSP_CMDRESP_ERR_MASK;
+
+	if (reg & PSP_CMDRESP_ERR_MASK) {
+		dev_dbg(psp->dev, "sev command %#x failed (%#010x)\n",
+			cmd, reg & PSP_CMDRESP_ERR_MASK);
+		ret = -EIO;
+	}
+
+	print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data,
+			     sev_cmd_buffer_len(cmd), false);
+
+	return ret;
+}
+
+static int sev_do_cmd(int cmd, void *data, int *psp_ret)
+{
+	int rc;
+
+	mutex_lock(&sev_cmd_mutex);
+	rc = __sev_do_cmd_locked(cmd, data, psp_ret);
+	mutex_unlock(&sev_cmd_mutex);
+
+	return rc;
+}
+
+static int __sev_platform_init_locked(int *error)
+{
+	struct psp_device *psp = psp_master;
+	int rc = 0;
+
+	if (!psp)
+		return -ENODEV;
+
+	if (psp->sev_state == SEV_STATE_INIT)
+		return 0;
+
+	rc = __sev_do_cmd_locked(SEV_CMD_INIT, &psp->init_cmd_buf, error);
+	if (rc)
+		return rc;
+
+	psp->sev_state = SEV_STATE_INIT;
+	dev_dbg(psp->dev, "SEV firmware initialized\n");
+
+	return rc;
+}
+
+int sev_platform_init(int *error)
+{
+	int rc;
+
+	mutex_lock(&sev_cmd_mutex);
+	rc = __sev_platform_init_locked(error);
+	mutex_unlock(&sev_cmd_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(sev_platform_init);
+
+static int __sev_platform_shutdown_locked(int *error)
+{
+	int ret;
+
+	ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error);
+	if (ret)
+		return ret;
+
+	psp_master->sev_state = SEV_STATE_UNINIT;
+	dev_dbg(psp_master->dev, "SEV firmware shutdown\n");
+
+	return ret;
+}
+
+static int sev_platform_shutdown(int *error)
+{
+	int rc;
+
+	mutex_lock(&sev_cmd_mutex);
+	rc = __sev_platform_shutdown_locked(NULL);
+	mutex_unlock(&sev_cmd_mutex);
+
+	return rc;
+}
+
+static int sev_get_platform_state(int *state, int *error)
+{
+	int rc;
+
+	rc = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS,
+				 &psp_master->status_cmd_buf, error);
+	if (rc)
+		return rc;
+
+	*state = psp_master->status_cmd_buf.state;
+	return rc;
+}
+
+static int sev_ioctl_do_reset(struct sev_issue_cmd *argp)
+{
+	int state, rc;
+
+	/*
+	 * The SEV spec requires that FACTORY_RESET must be issued in
+	 * UNINIT state. Before we go further lets check if any guest is
+	 * active.
+	 *
+	 * If FW is in WORKING state then deny the request otherwise issue
+	 * SHUTDOWN command do INIT -> UNINIT before issuing the FACTORY_RESET.
+	 *
+	 */
+	rc = sev_get_platform_state(&state, &argp->error);
+	if (rc)
+		return rc;
+
+	if (state == SEV_STATE_WORKING)
+		return -EBUSY;
+
+	if (state == SEV_STATE_INIT) {
+		rc = __sev_platform_shutdown_locked(&argp->error);
+		if (rc)
+			return rc;
+	}
+
+	return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, NULL, &argp->error);
+}
+
+static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)
+{
+	struct sev_user_data_status *data = &psp_master->status_cmd_buf;
+	int ret;
+
+	ret = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, data, &argp->error);
+	if (ret)
+		return ret;
+
+	if (copy_to_user((void __user *)argp->data, data, sizeof(*data)))
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp)
+{
+	int rc;
+
+	if (psp_master->sev_state == SEV_STATE_UNINIT) {
+		rc = __sev_platform_init_locked(&argp->error);
+		if (rc)
+			return rc;
+	}
+
+	return __sev_do_cmd_locked(cmd, NULL, &argp->error);
+}
+
+static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp)
+{
+	struct sev_user_data_pek_csr input;
+	struct sev_data_pek_csr *data;
+	void *blob = NULL;
+	int ret;
+
+	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
+		return -EFAULT;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* userspace wants to query CSR length */
+	if (!input.address || !input.length)
+		goto cmd;
+
+	/* allocate a physically contiguous buffer to store the CSR blob */
+	if (!access_ok(input.address, input.length) ||
+	    input.length > SEV_FW_BLOB_MAX_SIZE) {
+		ret = -EFAULT;
+		goto e_free;
+	}
+
+	blob = kmalloc(input.length, GFP_KERNEL);
+	if (!blob) {
+		ret = -ENOMEM;
+		goto e_free;
+	}
+
+	data->address = __psp_pa(blob);
+	data->len = input.length;
+
+cmd:
+	if (psp_master->sev_state == SEV_STATE_UNINIT) {
+		ret = __sev_platform_init_locked(&argp->error);
+		if (ret)
+			goto e_free_blob;
+	}
+
+	ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, data, &argp->error);
+
+	 /* If we query the CSR length, FW responded with expected data. */
+	input.length = data->len;
+
+	if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) {
+		ret = -EFAULT;
+		goto e_free_blob;
+	}
+
+	if (blob) {
+		if (copy_to_user((void __user *)input.address, blob, input.length))
+			ret = -EFAULT;
+	}
+
+e_free_blob:
+	kfree(blob);
+e_free:
+	kfree(data);
+	return ret;
+}
+
+void *psp_copy_user_blob(u64 __user uaddr, u32 len)
+{
+	if (!uaddr || !len)
+		return ERR_PTR(-EINVAL);
+
+	/* verify that blob length does not exceed our limit */
+	if (len > SEV_FW_BLOB_MAX_SIZE)
+		return ERR_PTR(-EINVAL);
+
+	return memdup_user((void __user *)(uintptr_t)uaddr, len);
+}
+EXPORT_SYMBOL_GPL(psp_copy_user_blob);
+
+static int sev_get_api_version(void)
+{
+	struct sev_user_data_status *status;
+	int error = 0, ret;
+
+	status = &psp_master->status_cmd_buf;
+	ret = sev_platform_status(status, &error);
+	if (ret) {
+		dev_err(psp_master->dev,
+			"SEV: failed to get status. Error: %#x\n", error);
+		return 1;
+	}
+
+	psp_master->api_major = status->api_major;
+	psp_master->api_minor = status->api_minor;
+	psp_master->build = status->build;
+	psp_master->sev_state = status->state;
+
+	return 0;
+}
+
+static int sev_get_firmware(struct device *dev,
+			    const struct firmware **firmware)
+{
+	char fw_name_specific[SEV_FW_NAME_SIZE];
+	char fw_name_subset[SEV_FW_NAME_SIZE];
+
+	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);
+
+	snprintf(fw_name_subset, sizeof(fw_name_subset),
+		 "amd/amd_sev_fam%.2xh_model%.1xxh.sbin",
+		 boot_cpu_data.x86, (boot_cpu_data.x86_model & 0xf0) >> 4);
+
+	/* Check for SEV FW for a particular model.
+	 * Ex. amd_sev_fam17h_model00h.sbin for Family 17h Model 00h
+	 *
+	 * or
+	 *
+	 * Check for SEV FW common to a subset of models.
+	 * Ex. amd_sev_fam17h_model0xh.sbin for
+	 *     Family 17h Model 00h -- Family 17h Model 0Fh
+	 *
+	 * or
+	 *
+	 * Fall-back to using generic name: sev.fw
+	 */
+	if ((firmware_request_nowarn(firmware, fw_name_specific, dev) >= 0) ||
+	    (firmware_request_nowarn(firmware, fw_name_subset, dev) >= 0) ||
+	    (firmware_request_nowarn(firmware, SEV_FW_FILE, dev) >= 0))
+		return 0;
+
+	return -ENOENT;
+}
+
+/* Don't fail if SEV FW couldn't be updated. Continue with existing SEV FW */
+static int sev_update_firmware(struct device *dev)
+{
+	struct sev_data_download_firmware *data;
+	const struct firmware *firmware;
+	int ret, error, order;
+	struct page *p;
+	u64 data_size;
+
+	if (sev_get_firmware(dev, &firmware) == -ENOENT) {
+		dev_dbg(dev, "No SEV firmware file present\n");
+		return -1;
+	}
+
+	/*
+	 * SEV 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 SEV
+	 * FW. Allocate enough memory for data structure + alignment
+	 * padding + SEV FW.
+	 */
+	data_size = ALIGN(sizeof(struct sev_data_download_firmware), 32);
+
+	order = get_order(firmware->size + data_size);
+	p = alloc_pages(GFP_KERNEL, order);
+	if (!p) {
+		ret = -1;
+		goto fw_err;
+	}
+
+	/*
+	 * Copy firmware data to a kernel allocated contiguous
+	 * memory region.
+	 */
+	data = page_address(p);
+	memcpy(page_address(p) + data_size, firmware->data, firmware->size);
+
+	data->address = __psp_pa(page_address(p) + data_size);
+	data->len = firmware->size;
+
+	ret = sev_do_cmd(SEV_CMD_DOWNLOAD_FIRMWARE, data, &error);
+	if (ret)
+		dev_dbg(dev, "Failed to update SEV firmware: %#x\n", error);
+	else
+		dev_info(dev, "SEV firmware update successful\n");
+
+	__free_pages(p, order);
+
+fw_err:
+	release_firmware(firmware);
+
+	return ret;
+}
+
+static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp)
+{
+	struct sev_user_data_pek_cert_import input;
+	struct sev_data_pek_cert_import *data;
+	void *pek_blob, *oca_blob;
+	int ret;
+
+	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
+		return -EFAULT;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* copy PEK certificate blobs from userspace */
+	pek_blob = psp_copy_user_blob(input.pek_cert_address, input.pek_cert_len);
+	if (IS_ERR(pek_blob)) {
+		ret = PTR_ERR(pek_blob);
+		goto e_free;
+	}
+
+	data->pek_cert_address = __psp_pa(pek_blob);
+	data->pek_cert_len = input.pek_cert_len;
+
+	/* copy PEK certificate blobs from userspace */
+	oca_blob = psp_copy_user_blob(input.oca_cert_address, input.oca_cert_len);
+	if (IS_ERR(oca_blob)) {
+		ret = PTR_ERR(oca_blob);
+		goto e_free_pek;
+	}
+
+	data->oca_cert_address = __psp_pa(oca_blob);
+	data->oca_cert_len = input.oca_cert_len;
+
+	/* If platform is not in INIT state then transition it to INIT */
+	if (psp_master->sev_state != SEV_STATE_INIT) {
+		ret = __sev_platform_init_locked(&argp->error);
+		if (ret)
+			goto e_free_oca;
+	}
+
+	ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, data, &argp->error);
+
+e_free_oca:
+	kfree(oca_blob);
+e_free_pek:
+	kfree(pek_blob);
+e_free:
+	kfree(data);
+	return ret;
+}
+
+static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp)
+{
+	struct sev_user_data_get_id2 input;
+	struct sev_data_get_id *data;
+	void *id_blob = NULL;
+	int ret;
+
+	/* SEV GET_ID is available from SEV API v0.16 and up */
+	if (!sev_version_greater_or_equal(0, 16))
+		return -ENOTSUPP;
+
+	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
+		return -EFAULT;
+
+	/* Check if we have write access to the userspace buffer */
+	if (input.address &&
+	    input.length &&
+	    !access_ok(input.address, input.length))
+		return -EFAULT;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (input.address && input.length) {
+		id_blob = kmalloc(input.length, GFP_KERNEL);
+		if (!id_blob) {
+			kfree(data);
+			return -ENOMEM;
+		}
+
+		data->address = __psp_pa(id_blob);
+		data->len = input.length;
+	}
+
+	ret = __sev_do_cmd_locked(SEV_CMD_GET_ID, data, &argp->error);
+
+	/*
+	 * Firmware will return the length of the ID value (either the minimum
+	 * required length or the actual length written), return it to the user.
+	 */
+	input.length = data->len;
+
+	if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) {
+		ret = -EFAULT;
+		goto e_free;
+	}
+
+	if (id_blob) {
+		if (copy_to_user((void __user *)input.address,
+				 id_blob, data->len)) {
+			ret = -EFAULT;
+			goto e_free;
+		}
+	}
+
+e_free:
+	kfree(id_blob);
+	kfree(data);
+
+	return ret;
+}
+
+static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp)
+{
+	struct sev_data_get_id *data;
+	u64 data_size, user_size;
+	void *id_blob, *mem;
+	int ret;
+
+	/* SEV GET_ID available from SEV API v0.16 and up */
+	if (!sev_version_greater_or_equal(0, 16))
+		return -ENOTSUPP;
+
+	/* SEV FW expects the buffer it fills with the ID to be
+	 * 8-byte aligned. Memory allocated should be enough to
+	 * hold data structure + alignment padding + memory
+	 * where SEV FW writes the ID.
+	 */
+	data_size = ALIGN(sizeof(struct sev_data_get_id), 8);
+	user_size = sizeof(struct sev_user_data_get_id);
+
+	mem = kzalloc(data_size + user_size, GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	data = mem;
+	id_blob = mem + data_size;
+
+	data->address = __psp_pa(id_blob);
+	data->len = user_size;
+
+	ret = __sev_do_cmd_locked(SEV_CMD_GET_ID, data, &argp->error);
+	if (!ret) {
+		if (copy_to_user((void __user *)argp->data, id_blob, data->len))
+			ret = -EFAULT;
+	}
+
+	kfree(mem);
+
+	return ret;
+}
+
+static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp)
+{
+	struct sev_user_data_pdh_cert_export input;
+	void *pdh_blob = NULL, *cert_blob = NULL;
+	struct sev_data_pdh_cert_export *data;
+	int ret;
+
+	if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
+		return -EFAULT;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* Userspace wants to query the certificate length. */
+	if (!input.pdh_cert_address ||
+	    !input.pdh_cert_len ||
+	    !input.cert_chain_address)
+		goto cmd;
+
+	/* Allocate a physically contiguous buffer to store the PDH blob. */
+	if ((input.pdh_cert_len > SEV_FW_BLOB_MAX_SIZE) ||
+	    !access_ok(input.pdh_cert_address, input.pdh_cert_len)) {
+		ret = -EFAULT;
+		goto e_free;
+	}
+
+	/* Allocate a physically contiguous buffer to store the cert chain blob. */
+	if ((input.cert_chain_len > SEV_FW_BLOB_MAX_SIZE) ||
+	    !access_ok(input.cert_chain_address, input.cert_chain_len)) {
+		ret = -EFAULT;
+		goto e_free;
+	}
+
+	pdh_blob = kmalloc(input.pdh_cert_len, GFP_KERNEL);
+	if (!pdh_blob) {
+		ret = -ENOMEM;
+		goto e_free;
+	}
+
+	data->pdh_cert_address = __psp_pa(pdh_blob);
+	data->pdh_cert_len = input.pdh_cert_len;
+
+	cert_blob = kmalloc(input.cert_chain_len, GFP_KERNEL);
+	if (!cert_blob) {
+		ret = -ENOMEM;
+		goto e_free_pdh;
+	}
+
+	data->cert_chain_address = __psp_pa(cert_blob);
+	data->cert_chain_len = input.cert_chain_len;
+
+cmd:
+	/* If platform is not in INIT state then transition it to INIT. */
+	if (psp_master->sev_state != SEV_STATE_INIT) {
+		ret = __sev_platform_init_locked(&argp->error);
+		if (ret)
+			goto e_free_cert;
+	}
+
+	ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, data, &argp->error);
+
+	/* If we query the length, FW responded with expected data. */
+	input.cert_chain_len = data->cert_chain_len;
+	input.pdh_cert_len = data->pdh_cert_len;
+
+	if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) {
+		ret = -EFAULT;
+		goto e_free_cert;
+	}
+
+	if (pdh_blob) {
+		if (copy_to_user((void __user *)input.pdh_cert_address,
+				 pdh_blob, input.pdh_cert_len)) {
+			ret = -EFAULT;
+			goto e_free_cert;
+		}
+	}
+
+	if (cert_blob) {
+		if (copy_to_user((void __user *)input.cert_chain_address,
+				 cert_blob, input.cert_chain_len))
+			ret = -EFAULT;
+	}
+
+e_free_cert:
+	kfree(cert_blob);
+e_free_pdh:
+	kfree(pdh_blob);
+e_free:
+	kfree(data);
+	return ret;
+}
+
+static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct sev_issue_cmd input;
+	int ret = -EFAULT;
+
+	if (!psp_master)
+		return -ENODEV;
+
+	if (ioctl != SEV_ISSUE_CMD)
+		return -EINVAL;
+
+	if (copy_from_user(&input, argp, sizeof(struct sev_issue_cmd)))
+		return -EFAULT;
+
+	if (input.cmd > SEV_MAX)
+		return -EINVAL;
+
+	mutex_lock(&sev_cmd_mutex);
+
+	switch (input.cmd) {
+
+	case SEV_FACTORY_RESET:
+		ret = sev_ioctl_do_reset(&input);
+		break;
+	case SEV_PLATFORM_STATUS:
+		ret = sev_ioctl_do_platform_status(&input);
+		break;
+	case SEV_PEK_GEN:
+		ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PEK_GEN, &input);
+		break;
+	case SEV_PDH_GEN:
+		ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input);
+		break;
+	case SEV_PEK_CSR:
+		ret = sev_ioctl_do_pek_csr(&input);
+		break;
+	case SEV_PEK_CERT_IMPORT:
+		ret = sev_ioctl_do_pek_import(&input);
+		break;
+	case SEV_PDH_CERT_EXPORT:
+		ret = sev_ioctl_do_pdh_export(&input);
+		break;
+	case SEV_GET_ID:
+		pr_warn_once("SEV_GET_ID command is deprecated, use SEV_GET_ID2\n");
+		ret = sev_ioctl_do_get_id(&input);
+		break;
+	case SEV_GET_ID2:
+		ret = sev_ioctl_do_get_id2(&input);
+		break;
+	default:
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
+		ret = -EFAULT;
+out:
+	mutex_unlock(&sev_cmd_mutex);
+
+	return ret;
+}
+
+static const struct file_operations sev_fops = {
+	.owner	= THIS_MODULE,
+	.unlocked_ioctl = sev_ioctl,
+};
+
+int sev_platform_status(struct sev_user_data_status *data, int *error)
+{
+	return sev_do_cmd(SEV_CMD_PLATFORM_STATUS, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_platform_status);
+
+int sev_guest_deactivate(struct sev_data_deactivate *data, int *error)
+{
+	return sev_do_cmd(SEV_CMD_DEACTIVATE, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_guest_deactivate);
+
+int sev_guest_activate(struct sev_data_activate *data, int *error)
+{
+	return sev_do_cmd(SEV_CMD_ACTIVATE, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_guest_activate);
+
+int sev_guest_decommission(struct sev_data_decommission *data, int *error)
+{
+	return sev_do_cmd(SEV_CMD_DECOMMISSION, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_guest_decommission);
+
+int sev_guest_df_flush(int *error)
+{
+	return sev_do_cmd(SEV_CMD_DF_FLUSH, NULL, error);
+}
+EXPORT_SYMBOL_GPL(sev_guest_df_flush);
+
+static void sev_exit(struct kref *ref)
+{
+	struct sev_misc_dev *misc_dev = container_of(ref, struct sev_misc_dev, refcount);
+
+	misc_deregister(&misc_dev->misc);
+}
+
+static int sev_misc_init(struct psp_device *psp)
+{
+	struct device *dev = psp->dev;
+	int ret;
+
+	/*
+	 * SEV feature support can be detected on multiple devices but the SEV
+	 * FW commands must be issued on the master. During probe, we do not
+	 * know the master hence we create /dev/sev on the first device probe.
+	 * sev_do_cmd() finds the right master device to which to issue the
+	 * command to the firmware.
+	 */
+	if (!misc_dev) {
+		struct miscdevice *misc;
+
+		misc_dev = devm_kzalloc(dev, sizeof(*misc_dev), GFP_KERNEL);
+		if (!misc_dev)
+			return -ENOMEM;
+
+		misc = &misc_dev->misc;
+		misc->minor = MISC_DYNAMIC_MINOR;
+		misc->name = DEVICE_NAME;
+		misc->fops = &sev_fops;
+
+		ret = misc_register(misc);
+		if (ret)
+			return ret;
+
+		kref_init(&misc_dev->refcount);
+	} else {
+		kref_get(&misc_dev->refcount);
+	}
+
+	init_waitqueue_head(&psp->sev_int_queue);
+	psp->sev_misc = misc_dev;
+	dev_dbg(dev, "registered SEV device\n");
+
+	return 0;
+}
+
+static int psp_check_sev_support(struct psp_device *psp)
+{
+	/* Check if device supports SEV feature */
+	if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) {
+		dev_dbg(psp->dev, "psp does not support SEV\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int psp_dev_init(struct sp_device *sp)
+{
+	struct device *dev = sp->dev;
+	struct psp_device *psp;
+	int ret;
+
+	ret = -ENOMEM;
+	psp = psp_alloc_struct(sp);
+	if (!psp)
+		goto e_err;
+
+	sp->psp_data = psp;
+
+	psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata;
+	if (!psp->vdata) {
+		ret = -ENODEV;
+		dev_err(dev, "missing driver data\n");
+		goto e_err;
+	}
+
+	psp->io_regs = sp->io_map;
+
+	ret = psp_check_sev_support(psp);
+	if (ret)
+		goto e_disable;
+
+	/* Disable and clear interrupts until ready */
+	iowrite32(0, psp->io_regs + psp->vdata->inten_reg);
+	iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg);
+
+	/* Request an irq */
+	ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
+	if (ret) {
+		dev_err(dev, "psp: unable to allocate an IRQ\n");
+		goto e_err;
+	}
+
+	ret = sev_misc_init(psp);
+	if (ret)
+		goto e_irq;
+
+	if (sp->set_psp_master_device)
+		sp->set_psp_master_device(sp);
+
+	/* Enable interrupt */
+	iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
+
+	dev_notice(dev, "psp enabled\n");
+
+	return 0;
+
+e_irq:
+	sp_free_psp_irq(psp->sp, psp);
+e_err:
+	sp->psp_data = NULL;
+
+	dev_notice(dev, "psp initialization failed\n");
+
+	return ret;
+
+e_disable:
+	sp->psp_data = NULL;
+
+	return ret;
+}
+
+void psp_dev_destroy(struct sp_device *sp)
+{
+	struct psp_device *psp = sp->psp_data;
+
+	if (!psp)
+		return;
+
+	if (psp->sev_misc)
+		kref_put(&misc_dev->refcount, sev_exit);
+
+	sp_free_psp_irq(sp, psp);
+}
+
+int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd,
+				void *data, int *error)
+{
+	if (!filep || filep->f_op != &sev_fops)
+		return -EBADF;
+
+	return  sev_do_cmd(cmd, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
+
+void psp_pci_init(void)
+{
+	struct sp_device *sp;
+	int error, rc;
+
+	sp = sp_get_psp_master_device();
+	if (!sp)
+		return;
+
+	psp_master = sp->psp_data;
+
+	psp_timeout = psp_probe_timeout;
+
+	if (sev_get_api_version())
+		goto err;
+
+	/*
+	 * If platform is not in UNINIT state then firmware upgrade and/or
+	 * platform INIT command will fail. These command require UNINIT state.
+	 *
+	 * In a normal boot we should never run into case where the firmware
+	 * is not in UNINIT state on boot. But in case of kexec boot, a reboot
+	 * may not go through a typical shutdown sequence and may leave the
+	 * firmware in INIT or WORKING state.
+	 */
+
+	if (psp_master->sev_state != SEV_STATE_UNINIT) {
+		sev_platform_shutdown(NULL);
+		psp_master->sev_state = SEV_STATE_UNINIT;
+	}
+
+	if (sev_version_greater_or_equal(0, 15) &&
+	    sev_update_firmware(psp_master->dev) == 0)
+		sev_get_api_version();
+
+	/* Initialize the platform */
+	rc = sev_platform_init(&error);
+	if (rc) {
+		dev_err(sp->dev, "SEV: failed to INIT error %#x\n", error);
+		return;
+	}
+
+	dev_info(sp->dev, "SEV API:%d.%d build:%d\n", psp_master->api_major,
+		 psp_master->api_minor, psp_master->build);
+
+	return;
+
+err:
+	psp_master = NULL;
+}
+
+void psp_pci_exit(void)
+{
+	if (!psp_master)
+		return;
+
+	sev_platform_shutdown(NULL);
+}
diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h
new file mode 100644
index 0000000..2ca1a01
--- /dev/null
+++ b/drivers/crypto/ccp/sev-dev.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AMD Secure Encrypted Virtualization (SEV) interface
+ *
+ * Copyright (C) 2017-2019 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <brijesh.singh@amd.com>
+ */
+
+#ifndef __SEV_DEV_H__
+#define __SEV_DEV_H__
+
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/dmapool.h>
+#include <linux/hw_random.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/dmaengine.h>
+#include <linux/psp-sev.h>
+#include <linux/miscdevice.h>
+
+#include "sp-dev.h"
+
+#define PSP_CMD_COMPLETE		BIT(1)
+
+#define PSP_CMDRESP_CMD_SHIFT		16
+#define PSP_CMDRESP_IOC			BIT(0)
+#define PSP_CMDRESP_RESP		BIT(31)
+#define PSP_CMDRESP_ERR_MASK		0xffff
+
+#define MAX_PSP_NAME_LEN		16
+
+struct sev_misc_dev {
+	struct kref refcount;
+	struct miscdevice misc;
+};
+
+struct psp_device {
+	struct list_head entry;
+
+	struct psp_vdata *vdata;
+	char name[MAX_PSP_NAME_LEN];
+
+	struct device *dev;
+	struct sp_device *sp;
+
+	void __iomem *io_regs;
+
+	int sev_state;
+	unsigned int sev_int_rcvd;
+	wait_queue_head_t sev_int_queue;
+	struct sev_misc_dev *sev_misc;
+	struct sev_user_data_status status_cmd_buf;
+	struct sev_data_init init_cmd_buf;
+
+	u8 api_major;
+	u8 api_minor;
+	u8 build;
+};
+
+#endif /* __SEV_DEV_H */
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index b29d2e6..473cf14 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -22,7 +22,7 @@
 #include <linux/ccp.h>

 #include "ccp-dev.h"
-#include "psp-dev.h"
+#include "sev-dev.h"

 #define MSIX_VECTORS			2

--
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH 2/5] crypto: ccp - create a generic psp-dev file
  2019-10-23 11:27 [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Thomas, Rijo-john
  2019-10-23 11:27 ` [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev Thomas, Rijo-john
@ 2019-10-23 11:27 ` Thomas, Rijo-john
  2019-10-23 11:27 ` [RFC PATCH 3/5] crypto: ccp - move SEV vdata to a dedicated data structure Thomas, Rijo-john
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-23 11:27 UTC (permalink / raw)
  To: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Thomas, Rijo-john, Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

The PSP (Platform Security Processor) provides support for key management
commands in Secure Encrypted Virtualization (SEV) mode, along with
software-based Trusted Execution Environment (TEE) to enable third-party
Trusted Applications.

Therefore, introduce psp-dev.c and psp-dev.h files, which can invoke
SEV (or TEE) initialization based on platform feature support.

TEE interface support will be introduced in a later patch.

Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
---
 drivers/crypto/ccp/Makefile  |   3 +-
 drivers/crypto/ccp/psp-dev.c | 180 ++++++++++++++++++++++++++++++
 drivers/crypto/ccp/psp-dev.h |  52 +++++++++
 drivers/crypto/ccp/sev-dev.c | 257 +++++++++++++++++--------------------------
 drivers/crypto/ccp/sev-dev.h |  36 +++---
 drivers/crypto/ccp/sp-pci.c  |   2 +-
 6 files changed, 352 insertions(+), 178 deletions(-)
 create mode 100644 drivers/crypto/ccp/psp-dev.c
 create mode 100644 drivers/crypto/ccp/psp-dev.h

diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index 9dafcf2..3b29ea4 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -8,7 +8,8 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \
 	    ccp-dmaengine.o
 ccp-$(CONFIG_CRYPTO_DEV_CCP_DEBUGFS) += ccp-debugfs.o
 ccp-$(CONFIG_PCI) += sp-pci.o
-ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += sev-dev.o
+ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \
+                                   sev-dev.o

 obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
 ccp-crypto-objs := ccp-crypto-main.o \
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
new file mode 100644
index 0000000..ef8affa
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AMD Platform Security Processor (PSP) interface
+ *
+ * Copyright (C) 2016,2019 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <brijesh.singh@amd.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/irqreturn.h>
+
+#include "sp-dev.h"
+#include "psp-dev.h"
+#include "sev-dev.h"
+
+struct psp_device *psp_master;
+
+static struct psp_device *psp_alloc_struct(struct sp_device *sp)
+{
+	struct device *dev = sp->dev;
+	struct psp_device *psp;
+
+	psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL);
+	if (!psp)
+		return NULL;
+
+	psp->dev = dev;
+	psp->sp = sp;
+
+	snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord);
+
+	return psp;
+}
+
+static irqreturn_t psp_irq_handler(int irq, void *data)
+{
+	struct psp_device *psp = data;
+	unsigned int status;
+
+	/* Read the interrupt status: */
+	status = ioread32(psp->io_regs + psp->vdata->intsts_reg);
+
+	/* invoke subdevice interrupt handlers */
+	if (status) {
+		if (psp->sev_irq_handler)
+			psp->sev_irq_handler(irq, psp->sev_irq_data, status);
+	}
+
+	/* Clear the interrupt status by writing the same value we read. */
+	iowrite32(status, psp->io_regs + psp->vdata->intsts_reg);
+
+	return IRQ_HANDLED;
+}
+
+static int psp_check_sev_support(struct psp_device *psp)
+{
+	/* Check if device supports SEV feature */
+	if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) {
+		dev_dbg(psp->dev, "psp does not support SEV\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int psp_dev_init(struct sp_device *sp)
+{
+	struct device *dev = sp->dev;
+	struct psp_device *psp;
+	int ret;
+
+	ret = -ENOMEM;
+	psp = psp_alloc_struct(sp);
+	if (!psp)
+		goto e_err;
+
+	sp->psp_data = psp;
+
+	psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata;
+	if (!psp->vdata) {
+		ret = -ENODEV;
+		dev_err(dev, "missing driver data\n");
+		goto e_err;
+	}
+
+	psp->io_regs = sp->io_map;
+
+	ret = psp_check_sev_support(psp);
+	if (ret)
+		goto e_disable;
+
+	/* Disable and clear interrupts until ready */
+	iowrite32(0, psp->io_regs + psp->vdata->inten_reg);
+	iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg);
+
+	/* Request an irq */
+	ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
+	if (ret) {
+		dev_err(dev, "psp: unable to allocate an IRQ\n");
+		goto e_err;
+	}
+
+	ret = sev_dev_init(psp);
+	if (ret)
+		goto e_irq;
+
+	if (sp->set_psp_master_device)
+		sp->set_psp_master_device(sp);
+
+	/* Enable interrupt */
+	iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
+
+	dev_notice(dev, "psp enabled\n");
+
+	return 0;
+
+e_irq:
+	sp_free_psp_irq(psp->sp, psp);
+e_err:
+	sp->psp_data = NULL;
+
+	dev_notice(dev, "psp initialization failed\n");
+
+	return ret;
+
+e_disable:
+	sp->psp_data = NULL;
+
+	return ret;
+}
+
+void psp_dev_destroy(struct sp_device *sp)
+{
+	struct psp_device *psp = sp->psp_data;
+
+	if (!psp)
+		return;
+
+	sev_dev_destroy(psp);
+
+	sp_free_psp_irq(sp, psp);
+}
+
+void psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
+			     void *data)
+{
+	psp->sev_irq_data = data;
+	psp->sev_irq_handler = handler;
+}
+
+void psp_clear_sev_irq_handler(struct psp_device *psp)
+{
+	psp_set_sev_irq_handler(psp, NULL, NULL);
+}
+
+struct psp_device *psp_get_master_device(void)
+{
+	struct sp_device *sp = sp_get_psp_master_device();
+
+	return sp ? sp->psp_data : NULL;
+}
+
+void psp_pci_init(void)
+{
+	psp_master = psp_get_master_device();
+
+	if (!psp_master)
+		return;
+
+	sev_pci_init();
+}
+
+void psp_pci_exit(void)
+{
+	if (!psp_master)
+		return;
+
+	sev_pci_exit();
+}
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
new file mode 100644
index 0000000..7c014ac
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AMD Platform Security Processor (PSP) interface driver
+ *
+ * Copyright (C) 2017-2019 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <brijesh.singh@amd.com>
+ */
+
+#ifndef __PSP_DEV_H__
+#define __PSP_DEV_H__
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+
+#include "sp-dev.h"
+
+#define PSP_CMDRESP_RESP		BIT(31)
+#define PSP_CMDRESP_ERR_MASK		0xffff
+
+#define MAX_PSP_NAME_LEN		16
+
+extern struct psp_device *psp_master;
+
+typedef void (*psp_irq_handler_t)(int, void *, unsigned int);
+
+struct psp_device {
+	struct list_head entry;
+
+	struct psp_vdata *vdata;
+	char name[MAX_PSP_NAME_LEN];
+
+	struct device *dev;
+	struct sp_device *sp;
+
+	void __iomem *io_regs;
+
+	psp_irq_handler_t sev_irq_handler;
+	void *sev_irq_data;
+
+	void *sev_data;
+};
+
+void psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
+			     void *data);
+void psp_clear_sev_irq_handler(struct psp_device *psp);
+
+struct psp_device *psp_get_master_device(void);
+
+#endif /* __PSP_DEV_H */
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 77841a8..7e5e7b2 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -21,7 +21,7 @@
 #include <linux/ccp.h>
 #include <linux/firmware.h>

-#include "sp-dev.h"
+#include "psp-dev.h"
 #include "sev-dev.h"

 #define DEVICE_NAME		"sev"
@@ -30,7 +30,6 @@

 static DEFINE_MUTEX(sev_cmd_mutex);
 static struct sev_misc_dev *misc_dev;
-static struct psp_device *psp_master;

 static int psp_cmd_timeout = 100;
 module_param(psp_cmd_timeout, int, 0644);
@@ -45,68 +44,45 @@

 static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
 {
-	if (psp_master->api_major > maj)
-		return true;
-	if (psp_master->api_major == maj && psp_master->api_minor >= min)
-		return true;
-	return false;
-}
-
-static struct psp_device *psp_alloc_struct(struct sp_device *sp)
-{
-	struct device *dev = sp->dev;
-	struct psp_device *psp;
-
-	psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL);
-	if (!psp)
-		return NULL;
+	struct sev_device *sev = psp_master->sev_data;

-	psp->dev = dev;
-	psp->sp = sp;
+	if (sev->api_major > maj)
+		return true;

-	snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord);
+	if (sev->api_major == maj && sev->api_minor >= min)
+		return true;

-	return psp;
+	return false;
 }

-static irqreturn_t psp_irq_handler(int irq, void *data)
+static void sev_irq_handler(int irq, void *data, unsigned int status)
 {
-	struct psp_device *psp = data;
-	unsigned int status;
+	struct sev_device *sev = data;
 	int reg;

-	/* Read the interrupt status: */
-	status = ioread32(psp->io_regs + psp->vdata->intsts_reg);
-
 	/* Check if it is command completion: */
-	if (!(status & PSP_CMD_COMPLETE))
-		goto done;
+	if (!(status & SEV_CMD_COMPLETE))
+		return;

 	/* Check if it is SEV command completion: */
-	reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg);
+	reg = ioread32(sev->io_regs + sev->psp->vdata->cmdresp_reg);
 	if (reg & PSP_CMDRESP_RESP) {
-		psp->sev_int_rcvd = 1;
-		wake_up(&psp->sev_int_queue);
+		sev->int_rcvd = 1;
+		wake_up(&sev->int_queue);
 	}
-
-done:
-	/* Clear the interrupt status by writing the same value we read. */
-	iowrite32(status, psp->io_regs + psp->vdata->intsts_reg);
-
-	return IRQ_HANDLED;
 }

-static int sev_wait_cmd_ioc(struct psp_device *psp,
+static int sev_wait_cmd_ioc(struct sev_device *sev,
 			    unsigned int *reg, unsigned int timeout)
 {
 	int ret;

-	ret = wait_event_timeout(psp->sev_int_queue,
-			psp->sev_int_rcvd, timeout * HZ);
+	ret = wait_event_timeout(sev->int_queue,
+			sev->int_rcvd, timeout * HZ);
 	if (!ret)
 		return -ETIMEDOUT;

-	*reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg);
+	*reg = ioread32(sev->io_regs + sev->psp->vdata->cmdresp_reg);

 	return 0;
 }
@@ -150,42 +126,45 @@ static int sev_cmd_buffer_len(int cmd)
 static int __sev_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)
+	if (!psp || !psp->sev_data)
 		return -ENODEV;

 	if (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(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
+	dev_dbg(sev->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
 		cmd, phys_msb, phys_lsb, psp_timeout);

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

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

-	psp->sev_int_rcvd = 0;
+	sev->int_rcvd = 0;

 	reg = cmd;
-	reg <<= PSP_CMDRESP_CMD_SHIFT;
-	reg |= PSP_CMDRESP_IOC;
-	iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg);
+	reg <<= SEV_CMDRESP_CMD_SHIFT;
+	reg |= SEV_CMDRESP_IOC;
+	iowrite32(reg, sev->io_regs + psp->vdata->cmdresp_reg);

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

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

 		return ret;
@@ -197,7 +176,7 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
 		*psp_ret = reg & PSP_CMDRESP_ERR_MASK;

 	if (reg & PSP_CMDRESP_ERR_MASK) {
-		dev_dbg(psp->dev, "sev command %#x failed (%#010x)\n",
+		dev_dbg(sev->dev, "sev command %#x failed (%#010x)\n",
 			cmd, reg & PSP_CMDRESP_ERR_MASK);
 		ret = -EIO;
 	}
@@ -222,20 +201,23 @@ static int sev_do_cmd(int cmd, void *data, int *psp_ret)
 static int __sev_platform_init_locked(int *error)
 {
 	struct psp_device *psp = psp_master;
+	struct sev_device *sev;
 	int rc = 0;

-	if (!psp)
+	if (!psp || !psp->sev_data)
 		return -ENODEV;

-	if (psp->sev_state == SEV_STATE_INIT)
+	sev = psp->sev_data;
+
+	if (sev->state == SEV_STATE_INIT)
 		return 0;

-	rc = __sev_do_cmd_locked(SEV_CMD_INIT, &psp->init_cmd_buf, error);
+	rc = __sev_do_cmd_locked(SEV_CMD_INIT, &sev->init_cmd_buf, error);
 	if (rc)
 		return rc;

-	psp->sev_state = SEV_STATE_INIT;
-	dev_dbg(psp->dev, "SEV firmware initialized\n");
+	sev->state = SEV_STATE_INIT;
+	dev_dbg(sev->dev, "SEV firmware initialized\n");

 	return rc;
 }
@@ -254,14 +236,15 @@ int sev_platform_init(int *error)

 static int __sev_platform_shutdown_locked(int *error)
 {
+	struct sev_device *sev = psp_master->sev_data;
 	int ret;

 	ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error);
 	if (ret)
 		return ret;

-	psp_master->sev_state = SEV_STATE_UNINIT;
-	dev_dbg(psp_master->dev, "SEV firmware shutdown\n");
+	sev->state = SEV_STATE_UNINIT;
+	dev_dbg(sev->dev, "SEV firmware shutdown\n");

 	return ret;
 }
@@ -279,14 +262,15 @@ static int sev_platform_shutdown(int *error)

 static int sev_get_platform_state(int *state, int *error)
 {
+	struct sev_device *sev = psp_master->sev_data;
 	int rc;

 	rc = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS,
-				 &psp_master->status_cmd_buf, error);
+				 &sev->status_cmd_buf, error);
 	if (rc)
 		return rc;

-	*state = psp_master->status_cmd_buf.state;
+	*state = sev->status_cmd_buf.state;
 	return rc;
 }

@@ -321,7 +305,8 @@ static int sev_ioctl_do_reset(struct sev_issue_cmd *argp)

 static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)
 {
-	struct sev_user_data_status *data = &psp_master->status_cmd_buf;
+	struct sev_device *sev = psp_master->sev_data;
+	struct sev_user_data_status *data = &sev->status_cmd_buf;
 	int ret;

 	ret = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, data, &argp->error);
@@ -336,9 +321,10 @@ static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)

 static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp)
 {
+	struct sev_device *sev = psp_master->sev_data;
 	int rc;

-	if (psp_master->sev_state == SEV_STATE_UNINIT) {
+	if (sev->state == SEV_STATE_UNINIT) {
 		rc = __sev_platform_init_locked(&argp->error);
 		if (rc)
 			return rc;
@@ -349,6 +335,7 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp)

 static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp)
 {
+	struct sev_device *sev = psp_master->sev_data;
 	struct sev_user_data_pek_csr input;
 	struct sev_data_pek_csr *data;
 	void *blob = NULL;
@@ -382,7 +369,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp)
 	data->len = input.length;

 cmd:
-	if (psp_master->sev_state == SEV_STATE_UNINIT) {
+	if (sev->state == SEV_STATE_UNINIT) {
 		ret = __sev_platform_init_locked(&argp->error);
 		if (ret)
 			goto e_free_blob;
@@ -425,21 +412,22 @@ void *psp_copy_user_blob(u64 __user uaddr, u32 len)

 static int sev_get_api_version(void)
 {
+	struct sev_device *sev = psp_master->sev_data;
 	struct sev_user_data_status *status;
 	int error = 0, ret;

-	status = &psp_master->status_cmd_buf;
+	status = &sev->status_cmd_buf;
 	ret = sev_platform_status(status, &error);
 	if (ret) {
-		dev_err(psp_master->dev,
+		dev_err(sev->dev,
 			"SEV: failed to get status. Error: %#x\n", error);
 		return 1;
 	}

-	psp_master->api_major = status->api_major;
-	psp_master->api_minor = status->api_minor;
-	psp_master->build = status->build;
-	psp_master->sev_state = status->state;
+	sev->api_major = status->api_major;
+	sev->api_minor = status->api_minor;
+	sev->build = status->build;
+	sev->state = status->state;

 	return 0;
 }
@@ -535,6 +523,7 @@ static int sev_update_firmware(struct device *dev)

 static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp)
 {
+	struct sev_device *sev = psp_master->sev_data;
 	struct sev_user_data_pek_cert_import input;
 	struct sev_data_pek_cert_import *data;
 	void *pek_blob, *oca_blob;
@@ -568,7 +557,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp)
 	data->oca_cert_len = input.oca_cert_len;

 	/* If platform is not in INIT state then transition it to INIT */
-	if (psp_master->sev_state != SEV_STATE_INIT) {
+	if (sev->state != SEV_STATE_INIT) {
 		ret = __sev_platform_init_locked(&argp->error);
 		if (ret)
 			goto e_free_oca;
@@ -690,6 +679,7 @@ static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp)

 static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp)
 {
+	struct sev_device *sev = psp_master->sev_data;
 	struct sev_user_data_pdh_cert_export input;
 	void *pdh_blob = NULL, *cert_blob = NULL;
 	struct sev_data_pdh_cert_export *data;
@@ -742,7 +732,7 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp)

 cmd:
 	/* If platform is not in INIT state then transition it to INIT. */
-	if (psp_master->sev_state != SEV_STATE_INIT) {
+	if (sev->state != SEV_STATE_INIT) {
 		ret = __sev_platform_init_locked(&argp->error);
 		if (ret)
 			goto e_free_cert;
@@ -788,7 +778,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
 	struct sev_issue_cmd input;
 	int ret = -EFAULT;

-	if (!psp_master)
+	if (!psp_master || !psp_master->sev_data)
 		return -ENODEV;

 	if (ioctl != SEV_ISSUE_CMD)
@@ -887,9 +877,9 @@ static void sev_exit(struct kref *ref)
 	misc_deregister(&misc_dev->misc);
 }

-static int sev_misc_init(struct psp_device *psp)
+static int sev_misc_init(struct sev_device *sev)
 {
-	struct device *dev = psp->dev;
+	struct device *dev = sev->dev;
 	int ret;

 	/*
@@ -920,101 +910,61 @@ static int sev_misc_init(struct psp_device *psp)
 		kref_get(&misc_dev->refcount);
 	}

-	init_waitqueue_head(&psp->sev_int_queue);
-	psp->sev_misc = misc_dev;
+	init_waitqueue_head(&sev->int_queue);
+	sev->misc = misc_dev;
 	dev_dbg(dev, "registered SEV device\n");

 	return 0;
 }

-static int psp_check_sev_support(struct psp_device *psp)
-{
-	/* Check if device supports SEV feature */
-	if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) {
-		dev_dbg(psp->dev, "psp does not support SEV\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-int psp_dev_init(struct sp_device *sp)
+int sev_dev_init(struct psp_device *psp)
 {
-	struct device *dev = sp->dev;
-	struct psp_device *psp;
-	int ret;
-
-	ret = -ENOMEM;
-	psp = psp_alloc_struct(sp);
-	if (!psp)
-		goto e_err;
-
-	sp->psp_data = psp;
+	struct device *dev = psp->dev;
+	struct sev_device *sev;
+	int ret = -ENOMEM;

-	psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata;
-	if (!psp->vdata) {
-		ret = -ENODEV;
-		dev_err(dev, "missing driver data\n");
+	sev = devm_kzalloc(dev, sizeof(*sev), GFP_KERNEL);
+	if (!sev)
 		goto e_err;
-	}

-	psp->io_regs = sp->io_map;
+	psp->sev_data = sev;

-	ret = psp_check_sev_support(psp);
-	if (ret)
-		goto e_disable;
+	sev->dev = dev;
+	sev->psp = psp;

-	/* Disable and clear interrupts until ready */
-	iowrite32(0, psp->io_regs + psp->vdata->inten_reg);
-	iowrite32(-1, psp->io_regs + psp->vdata->intsts_reg);
+	sev->io_regs = psp->io_regs;

-	/* Request an irq */
-	ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
-	if (ret) {
-		dev_err(dev, "psp: unable to allocate an IRQ\n");
-		goto e_err;
-	}
+	psp_set_sev_irq_handler(psp, sev_irq_handler, sev);

-	ret = sev_misc_init(psp);
+	ret = sev_misc_init(sev);
 	if (ret)
 		goto e_irq;

-	if (sp->set_psp_master_device)
-		sp->set_psp_master_device(sp);
-
-	/* Enable interrupt */
-	iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
-
-	dev_notice(dev, "psp enabled\n");
+	dev_notice(dev, "sev enabled\n");

 	return 0;

 e_irq:
-	sp_free_psp_irq(psp->sp, psp);
+	psp_clear_sev_irq_handler(psp);
 e_err:
-	sp->psp_data = NULL;
+	psp->sev_data = NULL;

-	dev_notice(dev, "psp initialization failed\n");
-
-	return ret;
-
-e_disable:
-	sp->psp_data = NULL;
+	dev_notice(dev, "sev initialization failed\n");

 	return ret;
 }

-void psp_dev_destroy(struct sp_device *sp)
+void sev_dev_destroy(struct psp_device *psp)
 {
-	struct psp_device *psp = sp->psp_data;
+	struct sev_device *sev = psp->sev_data;

-	if (!psp)
+	if (!sev)
 		return;

-	if (psp->sev_misc)
+	if (sev->misc)
 		kref_put(&misc_dev->refcount, sev_exit);

-	sp_free_psp_irq(sp, psp);
+	psp_clear_sev_irq_handler(psp);
 }

 int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd,
@@ -1023,21 +973,18 @@ int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd,
 	if (!filep || filep->f_op != &sev_fops)
 		return -EBADF;

-	return  sev_do_cmd(cmd, data, error);
+	return sev_do_cmd(cmd, data, error);
 }
 EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);

-void psp_pci_init(void)
+void sev_pci_init(void)
 {
-	struct sp_device *sp;
+	struct sev_device *sev = psp_master->sev_data;
 	int error, rc;

-	sp = sp_get_psp_master_device();
-	if (!sp)
+	if (!sev)
 		return;

-	psp_master = sp->psp_data;
-
 	psp_timeout = psp_probe_timeout;

 	if (sev_get_api_version())
@@ -1053,34 +1000,34 @@ void psp_pci_init(void)
 	 * firmware in INIT or WORKING state.
 	 */

-	if (psp_master->sev_state != SEV_STATE_UNINIT) {
+	if (sev->state != SEV_STATE_UNINIT) {
 		sev_platform_shutdown(NULL);
-		psp_master->sev_state = SEV_STATE_UNINIT;
+		sev->state = SEV_STATE_UNINIT;
 	}

 	if (sev_version_greater_or_equal(0, 15) &&
-	    sev_update_firmware(psp_master->dev) == 0)
+	    sev_update_firmware(sev->dev) == 0)
 		sev_get_api_version();

 	/* Initialize the platform */
 	rc = sev_platform_init(&error);
 	if (rc) {
-		dev_err(sp->dev, "SEV: failed to INIT error %#x\n", error);
+		dev_err(sev->dev, "SEV: failed to INIT error %#x\n", error);
 		return;
 	}

-	dev_info(sp->dev, "SEV API:%d.%d build:%d\n", psp_master->api_major,
-		 psp_master->api_minor, psp_master->build);
+	dev_info(sev->dev, "SEV API:%d.%d build:%d\n", sev->api_major,
+		 sev->api_minor, sev->build);

 	return;

 err:
-	psp_master = NULL;
+	psp_master->sev_data = NULL;
 }

-void psp_pci_exit(void)
+void sev_pci_exit(void)
 {
-	if (!psp_master)
+	if (!psp_master->sev_data)
 		return;

 	sev_platform_shutdown(NULL);
diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h
index 2ca1a01..20d51c9 100644
--- a/drivers/crypto/ccp/sev-dev.h
+++ b/drivers/crypto/ccp/sev-dev.h
@@ -24,37 +24,25 @@
 #include <linux/psp-sev.h>
 #include <linux/miscdevice.h>

-#include "sp-dev.h"
-
-#define PSP_CMD_COMPLETE		BIT(1)
-
-#define PSP_CMDRESP_CMD_SHIFT		16
-#define PSP_CMDRESP_IOC			BIT(0)
-#define PSP_CMDRESP_RESP		BIT(31)
-#define PSP_CMDRESP_ERR_MASK		0xffff
-
-#define MAX_PSP_NAME_LEN		16
+#define SEV_CMD_COMPLETE		BIT(1)
+#define SEV_CMDRESP_CMD_SHIFT		16
+#define SEV_CMDRESP_IOC			BIT(0)

 struct sev_misc_dev {
 	struct kref refcount;
 	struct miscdevice misc;
 };

-struct psp_device {
-	struct list_head entry;
-
-	struct psp_vdata *vdata;
-	char name[MAX_PSP_NAME_LEN];
-
+struct sev_device {
 	struct device *dev;
-	struct sp_device *sp;
+	struct psp_device *psp;

 	void __iomem *io_regs;

-	int sev_state;
-	unsigned int sev_int_rcvd;
-	wait_queue_head_t sev_int_queue;
-	struct sev_misc_dev *sev_misc;
+	int state;
+	unsigned int int_rcvd;
+	wait_queue_head_t int_queue;
+	struct sev_misc_dev *misc;
 	struct sev_user_data_status status_cmd_buf;
 	struct sev_data_init init_cmd_buf;

@@ -63,4 +51,10 @@ struct psp_device {
 	u8 build;
 };

+int sev_dev_init(struct psp_device *psp);
+void sev_dev_destroy(struct psp_device *psp);
+
+void sev_pci_init(void);
+void sev_pci_exit(void);
+
 #endif /* __SEV_DEV_H */
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index 473cf14..b29d2e6 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -22,7 +22,7 @@
 #include <linux/ccp.h>

 #include "ccp-dev.h"
-#include "sev-dev.h"
+#include "psp-dev.h"

 #define MSIX_VECTORS			2

--
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH 3/5] crypto: ccp - move SEV vdata to a dedicated data structure
  2019-10-23 11:27 [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Thomas, Rijo-john
  2019-10-23 11:27 ` [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev Thomas, Rijo-john
  2019-10-23 11:27 ` [RFC PATCH 2/5] crypto: ccp - create a generic psp-dev file Thomas, Rijo-john
@ 2019-10-23 11:27 ` Thomas, Rijo-john
  2019-10-23 11:27 ` [RFC PATCH 4/5] crypto: ccp - add TEE support for Raven Ridge Thomas, Rijo-john
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-23 11:27 UTC (permalink / raw)
  To: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Thomas, Rijo-john, Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

PSP can support both SEV and TEE interface. Therefore, move
SEV specific registers to a dedicated data structure.
TEE interface specific registers will be added in a later
patch.

Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
---
 drivers/crypto/ccp/sev-dev.c | 17 ++++++++++++-----
 drivers/crypto/ccp/sev-dev.h |  2 ++
 drivers/crypto/ccp/sp-dev.h  |  6 +++++-
 drivers/crypto/ccp/sp-pci.c  | 16 ++++++++++++----
 4 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 7e5e7b2..f546f8d 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -65,7 +65,7 @@ static void sev_irq_handler(int irq, void *data, unsigned int status)
 		return;

 	/* Check if it is SEV command completion: */
-	reg = ioread32(sev->io_regs + sev->psp->vdata->cmdresp_reg);
+	reg = ioread32(sev->io_regs + sev->vdata->cmdresp_reg);
 	if (reg & PSP_CMDRESP_RESP) {
 		sev->int_rcvd = 1;
 		wake_up(&sev->int_queue);
@@ -82,7 +82,7 @@ static int sev_wait_cmd_ioc(struct sev_device *sev,
 	if (!ret)
 		return -ETIMEDOUT;

-	*reg = ioread32(sev->io_regs + sev->psp->vdata->cmdresp_reg);
+	*reg = ioread32(sev->io_regs + sev->vdata->cmdresp_reg);

 	return 0;
 }
@@ -148,15 +148,15 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
 	print_hex_dump_debug("(in):  ", DUMP_PREFIX_OFFSET, 16, 2, data,
 			     sev_cmd_buffer_len(cmd), false);

-	iowrite32(phys_lsb, sev->io_regs + psp->vdata->cmdbuff_addr_lo_reg);
-	iowrite32(phys_msb, sev->io_regs + psp->vdata->cmdbuff_addr_hi_reg);
+	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 = cmd;
 	reg <<= SEV_CMDRESP_CMD_SHIFT;
 	reg |= SEV_CMDRESP_IOC;
-	iowrite32(reg, sev->io_regs + psp->vdata->cmdresp_reg);
+	iowrite32(reg, sev->io_regs + sev->vdata->cmdresp_reg);

 	/* wait for command completion */
 	ret = sev_wait_cmd_ioc(sev, &reg, psp_timeout);
@@ -934,6 +934,13 @@ int sev_dev_init(struct psp_device *psp)

 	sev->io_regs = psp->io_regs;

+	sev->vdata = (struct sev_vdata *)psp->vdata->sev;
+	if (!sev->vdata) {
+		ret = -ENODEV;
+		dev_err(dev, "sev: missing driver data\n");
+		goto e_err;
+	}
+
 	psp_set_sev_irq_handler(psp, sev_irq_handler, sev);

 	ret = sev_misc_init(sev);
diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h
index 20d51c9..55cae86 100644
--- a/drivers/crypto/ccp/sev-dev.h
+++ b/drivers/crypto/ccp/sev-dev.h
@@ -39,6 +39,8 @@ struct sev_device {

 	void __iomem *io_regs;

+	struct sev_vdata *vdata;
+
 	int state;
 	unsigned int int_rcvd;
 	wait_queue_head_t int_queue;
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index 53c1256..0394c75 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -39,10 +39,14 @@ struct ccp_vdata {
 	const unsigned int rsamax;
 };

-struct psp_vdata {
+struct sev_vdata {
 	const unsigned int cmdresp_reg;
 	const unsigned int cmdbuff_addr_lo_reg;
 	const unsigned int cmdbuff_addr_hi_reg;
+};
+
+struct psp_vdata {
+	const struct sev_vdata *sev;
 	const unsigned int feature_reg;
 	const unsigned int inten_reg;
 	const unsigned int intsts_reg;
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index b29d2e6..733693d 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -262,19 +262,27 @@ static int sp_pci_resume(struct pci_dev *pdev)
 #endif

 #ifdef CONFIG_CRYPTO_DEV_SP_PSP
-static const struct psp_vdata pspv1 = {
+static const struct sev_vdata sevv1 = {
 	.cmdresp_reg		= 0x10580,
 	.cmdbuff_addr_lo_reg	= 0x105e0,
 	.cmdbuff_addr_hi_reg	= 0x105e4,
+};
+
+static const struct sev_vdata sevv2 = {
+	.cmdresp_reg		= 0x10980,
+	.cmdbuff_addr_lo_reg	= 0x109e0,
+	.cmdbuff_addr_hi_reg	= 0x109e4,
+};
+
+static const struct psp_vdata pspv1 = {
+	.sev			= &sevv1,
 	.feature_reg		= 0x105fc,
 	.inten_reg		= 0x10610,
 	.intsts_reg		= 0x10614,
 };

 static const struct psp_vdata pspv2 = {
-	.cmdresp_reg		= 0x10980,
-	.cmdbuff_addr_lo_reg	= 0x109e0,
-	.cmdbuff_addr_hi_reg	= 0x109e4,
+	.sev			= &sevv2,
 	.feature_reg		= 0x109fc,
 	.inten_reg		= 0x10690,
 	.intsts_reg		= 0x10694,
--
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH 4/5] crypto: ccp - add TEE support for Raven Ridge
  2019-10-23 11:27 [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Thomas, Rijo-john
                   ` (2 preceding siblings ...)
  2019-10-23 11:27 ` [RFC PATCH 3/5] crypto: ccp - move SEV vdata to a dedicated data structure Thomas, Rijo-john
@ 2019-10-23 11:27 ` Thomas, Rijo-john
  2019-10-23 11:49   ` Ard Biesheuvel
  2019-10-23 11:27 ` [RFC PATCH 5/5] crypto: ccp - provide in-kernel API to submit TEE commands Thomas, Rijo-john
  2019-10-23 16:27 ` [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Lendacky, Thomas
  5 siblings, 1 reply; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-23 11:27 UTC (permalink / raw)
  To: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Thomas, Rijo-john, Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

Adds a PCI device entry for Raven Ridge. Raven Ridge is an APU with a
dedicated AMD Secure Processor having Trusted Execution Environment (TEE)
support. The TEE provides a secure environment for running Trusted
Applications (TAs) which implement security-sensitive parts of a feature.

This patch configures AMD Secure Processor's TEE interface by initializing
a ring buffer (shared memory between Rich OS and Trusted OS) which can hold
multiple command buffer entries. The TEE interface is facilitated by a set
of CPU to PSP mailbox registers.

The next patch will address how commands are submitted to the ring buffer.

Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
---
 drivers/crypto/ccp/Makefile  |   3 +-
 drivers/crypto/ccp/psp-dev.c |  74 +++++++++++++-
 drivers/crypto/ccp/psp-dev.h |   8 ++
 drivers/crypto/ccp/sp-dev.h  |  11 +-
 drivers/crypto/ccp/sp-pci.c  |  27 ++++-
 drivers/crypto/ccp/tee-dev.c | 237 +++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/ccp/tee-dev.h | 108 ++++++++++++++++++++
 7 files changed, 461 insertions(+), 7 deletions(-)
 create mode 100644 drivers/crypto/ccp/tee-dev.c
 create mode 100644 drivers/crypto/ccp/tee-dev.h

diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index 3b29ea4..db362fe 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -9,7 +9,8 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \
 ccp-$(CONFIG_CRYPTO_DEV_CCP_DEBUGFS) += ccp-debugfs.o
 ccp-$(CONFIG_PCI) += sp-pci.o
 ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \
-                                   sev-dev.o
+                                   sev-dev.o \
+                                   tee-dev.o

 obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
 ccp-crypto-objs := ccp-crypto-main.o \
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
index ef8affa..90bcd5f 100644
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -13,6 +13,7 @@
 #include "sp-dev.h"
 #include "psp-dev.h"
 #include "sev-dev.h"
+#include "tee-dev.h"

 struct psp_device *psp_master;

@@ -45,6 +46,9 @@ static irqreturn_t psp_irq_handler(int irq, void *data)
 	if (status) {
 		if (psp->sev_irq_handler)
 			psp->sev_irq_handler(irq, psp->sev_irq_data, status);
+
+		if (psp->tee_irq_handler)
+			psp->tee_irq_handler(irq, psp->tee_irq_data, status);
 	}

 	/* Clear the interrupt status by writing the same value we read. */
@@ -53,10 +57,11 @@ static irqreturn_t psp_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }

-static int psp_check_sev_support(struct psp_device *psp)
+static int psp_check_sev_support(struct psp_device *psp,
+				 unsigned int capability)
 {
 	/* Check if device supports SEV feature */
-	if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) {
+	if (!(capability & 1)) {
 		dev_dbg(psp->dev, "psp does not support SEV\n");
 		return -ENODEV;
 	}
@@ -64,10 +69,54 @@ static int psp_check_sev_support(struct psp_device *psp)
 	return 0;
 }

+static int psp_check_tee_support(struct psp_device *psp,
+				 unsigned int capability)
+{
+	/* Check if device supports TEE feature */
+	if (!(capability & 2)) {
+		dev_dbg(psp->dev, "psp does not support TEE\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int psp_check_support(struct psp_device *psp, unsigned int capability)
+{
+	int sev_support = psp_check_sev_support(psp, capability);
+	int tee_support = psp_check_tee_support(psp, capability);
+
+	/* Check if device supprts SEV and TEE feature */
+	if (sev_support && tee_support)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int psp_init(struct psp_device *psp, unsigned int capability)
+{
+	int ret;
+
+	if (!psp_check_sev_support(psp, capability)) {
+		ret = sev_dev_init(psp);
+		if (ret)
+			return ret;
+	}
+
+	if (!psp_check_tee_support(psp, capability)) {
+		ret = tee_dev_init(psp);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 int psp_dev_init(struct sp_device *sp)
 {
 	struct device *dev = sp->dev;
 	struct psp_device *psp;
+	unsigned int capability;
 	int ret;

 	ret = -ENOMEM;
@@ -86,7 +135,10 @@ int psp_dev_init(struct sp_device *sp)

 	psp->io_regs = sp->io_map;

-	ret = psp_check_sev_support(psp);
+	/* Read the feature register to get the PSP capability */
+	capability = ioread32(psp->io_regs + psp->vdata->feature_reg);
+
+	ret = psp_check_support(psp, capability);
 	if (ret)
 		goto e_disable;

@@ -101,7 +153,7 @@ int psp_dev_init(struct sp_device *sp)
 		goto e_err;
 	}

-	ret = sev_dev_init(psp);
+	ret = psp_init(psp, capability);
 	if (ret)
 		goto e_irq;

@@ -139,6 +191,8 @@ void psp_dev_destroy(struct sp_device *sp)

 	sev_dev_destroy(psp);

+	tee_dev_destroy(psp);
+
 	sp_free_psp_irq(sp, psp);
 }

@@ -154,6 +208,18 @@ void psp_clear_sev_irq_handler(struct psp_device *psp)
 	psp_set_sev_irq_handler(psp, NULL, NULL);
 }

+void psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
+			     void *data)
+{
+	psp->tee_irq_data = data;
+	psp->tee_irq_handler = handler;
+}
+
+void psp_clear_tee_irq_handler(struct psp_device *psp)
+{
+	psp_set_tee_irq_handler(psp, NULL, NULL);
+}
+
 struct psp_device *psp_get_master_device(void)
 {
 	struct sp_device *sp = sp_get_psp_master_device();
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
index 7c014ac..ef38e41 100644
--- a/drivers/crypto/ccp/psp-dev.h
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -40,13 +40,21 @@ struct psp_device {
 	psp_irq_handler_t sev_irq_handler;
 	void *sev_irq_data;

+	psp_irq_handler_t tee_irq_handler;
+	void *tee_irq_data;
+
 	void *sev_data;
+	void *tee_data;
 };

 void psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
 			     void *data);
 void psp_clear_sev_irq_handler(struct psp_device *psp);

+void psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
+			     void *data);
+void psp_clear_tee_irq_handler(struct psp_device *psp);
+
 struct psp_device *psp_get_master_device(void);

 #endif /* __PSP_DEV_H */
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index 0394c75..4235946 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -2,7 +2,7 @@
 /*
  * AMD Secure Processor driver
  *
- * Copyright (C) 2017-2018 Advanced Micro Devices, Inc.
+ * Copyright (C) 2017-2019 Advanced Micro Devices, Inc.
  *
  * Author: Tom Lendacky <thomas.lendacky@amd.com>
  * Author: Gary R Hook <gary.hook@amd.com>
@@ -45,8 +45,17 @@ struct sev_vdata {
 	const unsigned int cmdbuff_addr_hi_reg;
 };

+struct tee_vdata {
+	const unsigned int cmdresp_reg;
+	const unsigned int cmdbuff_addr_lo_reg;
+	const unsigned int cmdbuff_addr_hi_reg;
+	const unsigned int ring_wptr_reg;
+	const unsigned int ring_rptr_reg;
+};
+
 struct psp_vdata {
 	const struct sev_vdata *sev;
+	const struct tee_vdata *tee;
 	const unsigned int feature_reg;
 	const unsigned int inten_reg;
 	const unsigned int intsts_reg;
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index 733693d..56c1f61 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -2,7 +2,7 @@
 /*
  * AMD Secure Processor device driver
  *
- * Copyright (C) 2013,2018 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2019 Advanced Micro Devices, Inc.
  *
  * Author: Tom Lendacky <thomas.lendacky@amd.com>
  * Author: Gary R Hook <gary.hook@amd.com>
@@ -274,6 +274,14 @@ static int sp_pci_resume(struct pci_dev *pdev)
 	.cmdbuff_addr_hi_reg	= 0x109e4,
 };

+static const struct tee_vdata teev1 = {
+	.cmdresp_reg		= 0x10544,
+	.cmdbuff_addr_lo_reg	= 0x10548,
+	.cmdbuff_addr_hi_reg	= 0x1054c,
+	.ring_wptr_reg          = 0x10550,
+	.ring_rptr_reg          = 0x10554,
+};
+
 static const struct psp_vdata pspv1 = {
 	.sev			= &sevv1,
 	.feature_reg		= 0x105fc,
@@ -287,6 +295,13 @@ static int sp_pci_resume(struct pci_dev *pdev)
 	.inten_reg		= 0x10690,
 	.intsts_reg		= 0x10694,
 };
+
+static const struct psp_vdata pspv3 = {
+	.tee			= &teev1,
+	.feature_reg		= 0x109fc,
+	.inten_reg		= 0x10690,
+	.intsts_reg		= 0x10694,
+};
 #endif

 static const struct sp_dev_vdata dev_vdata[] = {
@@ -320,12 +335,22 @@ static int sp_pci_resume(struct pci_dev *pdev)
 		.psp_vdata = &pspv2,
 #endif
 	},
+	{	/* 4 */
+		.bar = 2,
+#ifdef CONFIG_CRYPTO_DEV_SP_CCP
+		.ccp_vdata = &ccpv5a,
+#endif
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+		.psp_vdata = &pspv3,
+#endif
+	},
 };
 static const struct pci_device_id sp_pci_table[] = {
 	{ PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] },
 	{ PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] },
 	{ PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] },
 	{ PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] },
+	{ PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] },
 	/* Last entry must be zero */
 	{ 0, }
 };
diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c
new file mode 100644
index 0000000..b2b0215
--- /dev/null
+++ b/drivers/crypto/ccp/tee-dev.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: MIT
+/*
+ * AMD Trusted Execution Environment (TEE) interface
+ *
+ * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
+ *
+ * Copyright 2019 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/psp-sev.h>
+
+#include "psp-dev.h"
+#include "tee-dev.h"
+
+static bool psp_dead;
+
+static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
+{
+	struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
+	void *start_addr;
+
+	if (!ring_size)
+		return -EINVAL;
+
+	/* We need actual physical address instead of DMA address, since
+	 * Trusted OS running on AMD Secure Processor will map this region
+	 */
+	start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size));
+	if (!start_addr)
+		return -ENOMEM;
+
+	rb_mgr->ring_start = start_addr;
+	rb_mgr->ring_size = ring_size;
+	rb_mgr->ring_pa = __psp_pa(start_addr);
+
+	return 0;
+}
+
+static void tee_free_ring(struct psp_tee_device *tee)
+{
+	struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
+
+	if (!rb_mgr->ring_start)
+		return;
+
+	free_pages((unsigned long)rb_mgr->ring_start,
+		   get_order(rb_mgr->ring_size));
+
+	rb_mgr->ring_start = NULL;
+	rb_mgr->ring_size = 0;
+	rb_mgr->ring_pa = 0;
+}
+
+static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
+			     unsigned int *reg)
+{
+	/* ~10ms sleep per loop => nloop = timeout * 100 */
+	int nloop = timeout * 100;
+
+	while (--nloop) {
+		*reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg);
+		if (*reg & PSP_CMDRESP_RESP)
+			return 0;
+
+		usleep_range(10000, 10100);
+	}
+
+	dev_err(tee->dev, "tee: command timed out, disabling PSP\n");
+	psp_dead = true;
+
+	return -ETIMEDOUT;
+}
+
+static
+struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
+{
+	struct tee_init_ring_cmd *cmd;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa);
+	cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa);
+	cmd->size = tee->rb_mgr.ring_size;
+
+	dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n",
+		cmd->hi_addr, cmd->low_addr, cmd->size);
+
+	return cmd;
+}
+
+static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
+{
+	kfree(cmd);
+}
+
+static int tee_init_ring(struct psp_tee_device *tee)
+{
+	int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
+	struct tee_init_ring_cmd *cmd;
+	phys_addr_t cmd_buffer;
+	unsigned int reg;
+	int ret;
+
+	BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024);
+
+	ret = tee_alloc_ring(tee, ring_size);
+	if (ret) {
+		dev_err(tee->dev, "tee: ring allocation failed %d\n", ret);
+		return ret;
+	}
+
+	tee->rb_mgr.wptr = 0;
+
+	cmd = tee_alloc_cmd_buffer(tee);
+	if (!cmd) {
+		tee_free_ring(tee);
+		return -ENOMEM;
+	}
+
+	cmd_buffer = __psp_pa((void *)cmd);
+
+	/* Send command buffer details to Trusted OS by writing to
+	 * CPU-PSP message registers
+	 */
+
+	iowrite32(lower_32_bits(cmd_buffer),
+		  tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg);
+	iowrite32(upper_32_bits(cmd_buffer),
+		  tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg);
+	iowrite32(TEE_RING_INIT_CMD,
+		  tee->io_regs + tee->vdata->cmdresp_reg);
+
+	ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
+	if (ret) {
+		dev_err(tee->dev, "tee: ring init command timed out\n");
+		tee_free_ring(tee);
+		goto free_buf;
+	}
+
+	if (reg & PSP_CMDRESP_ERR_MASK) {
+		dev_err(tee->dev, "tee: ring init command failed (%#010x)\n",
+			reg & PSP_CMDRESP_ERR_MASK);
+		tee_free_ring(tee);
+		ret = -EIO;
+	}
+
+free_buf:
+	tee_free_cmd_buffer(cmd);
+
+	return ret;
+}
+
+static void tee_destroy_ring(struct psp_tee_device *tee)
+{
+	unsigned int reg;
+	int ret;
+
+	if (!tee->rb_mgr.ring_start)
+		return;
+
+	if (psp_dead)
+		goto free_ring;
+
+	iowrite32(TEE_RING_DESTROY_CMD,
+		  tee->io_regs + tee->vdata->cmdresp_reg);
+
+	ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
+	if (ret) {
+		dev_err(tee->dev, "tee: ring destroy command timed out\n");
+	} else if (reg & PSP_CMDRESP_ERR_MASK) {
+		dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n",
+			reg & PSP_CMDRESP_ERR_MASK);
+	}
+
+free_ring:
+	tee_free_ring(tee);
+}
+
+int tee_dev_init(struct psp_device *psp)
+{
+	struct device *dev = psp->dev;
+	struct psp_tee_device *tee;
+	int ret;
+
+	ret = -ENOMEM;
+	tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL);
+	if (!tee)
+		goto e_err;
+
+	psp->tee_data = tee;
+
+	tee->dev = dev;
+	tee->psp = psp;
+
+	tee->io_regs = psp->io_regs;
+
+	tee->vdata = (struct tee_vdata *)psp->vdata->tee;
+	if (!tee->vdata) {
+		ret = -ENODEV;
+		dev_err(dev, "tee: missing driver data\n");
+		goto e_err;
+	}
+
+	ret = tee_init_ring(tee);
+	if (ret) {
+		dev_err(dev, "tee: failed to init ring buffer\n");
+		goto e_err;
+	}
+
+	dev_notice(dev, "tee enabled\n");
+
+	return 0;
+
+e_err:
+	psp->tee_data = NULL;
+
+	dev_notice(dev, "tee initialization failed\n");
+
+	return ret;
+}
+
+void tee_dev_destroy(struct psp_device *psp)
+{
+	struct psp_tee_device *tee = psp->tee_data;
+
+	if (!tee)
+		return;
+
+	tee_destroy_ring(tee);
+}
diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h
new file mode 100644
index 0000000..0d51a0a7
--- /dev/null
+++ b/drivers/crypto/ccp/tee-dev.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2019 Advanced Micro Devices, Inc.
+ *
+ * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
+ *
+ */
+
+/* This file describes the TEE communication interface between host and AMD
+ * Secure Processor
+ */
+
+#ifndef __TEE_DEV_H__
+#define __TEE_DEV_H__
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+
+#define TEE_DEFAULT_TIMEOUT		10
+#define MAX_BUFFER_SIZE			992
+
+/**
+ * enum tee_ring_cmd_id - TEE interface commands for ring buffer configuration
+ * @TEE_RING_INIT_CMD:		Initialize ring buffer
+ * @TEE_RING_DESTROY_CMD:	Destroy ring buffer
+ * @TEE_RING_MAX_CMD:		Maximum command id
+ */
+enum tee_ring_cmd_id {
+	TEE_RING_INIT_CMD		= 0x00010000,
+	TEE_RING_DESTROY_CMD		= 0x00020000,
+	TEE_RING_MAX_CMD		= 0x000F0000,
+};
+
+/**
+ * struct tee_init_ring_cmd - Command to init TEE ring buffer
+ * @low_addr:  bits [31:0] of the physical address of ring buffer
+ * @hi_addr:   bits [63:32] of the physical address of ring buffer
+ * @size:      size of ring buffer in bytes
+ */
+struct tee_init_ring_cmd {
+	u32 low_addr;
+	u32 hi_addr;
+	u32 size;
+};
+
+#define MAX_RING_BUFFER_ENTRIES		32
+
+/**
+ * struct ring_buf_manager - Helper structure to manage ring buffer.
+ * @ring_start:  starting address of ring buffer
+ * @ring_size:   size of ring buffer in bytes
+ * @ring_pa:     physical address of ring buffer
+ * @wptr:        index to the last written entry in ring buffer
+ */
+struct ring_buf_manager {
+	void *ring_start;
+	u32 ring_size;
+	phys_addr_t ring_pa;
+	u32 wptr;
+};
+
+struct psp_tee_device {
+	struct device *dev;
+	struct psp_device *psp;
+	void __iomem *io_regs;
+	struct tee_vdata *vdata;
+	struct ring_buf_manager rb_mgr;
+};
+
+/**
+ * enum tee_cmd_state - TEE command states for the ring buffer interface
+ * @TEE_CMD_STATE_INIT:      initial state of command when sent from host
+ * @TEE_CMD_STATE_PROCESS:   command being processed by TEE environment
+ * @TEE_CMD_STATE_COMPLETED: command processing completed
+ */
+enum tee_cmd_state {
+	TEE_CMD_STATE_INIT,
+	TEE_CMD_STATE_PROCESS,
+	TEE_CMD_STATE_COMPLETED,
+};
+
+/**
+ * struct tee_ring_cmd - Structure of the command buffer in TEE ring
+ * @cmd_id:      refers to &enum tee_cmd_id. Command id for the ring buffer
+ *               interface
+ * @cmd_state:   refers to &enum tee_cmd_state
+ * @status:      status of TEE command execution
+ * @res0:        reserved region
+ * @pdata:       private data (currently unused)
+ * @res1:        reserved region
+ * @buf:         TEE command specific buffer
+ */
+struct tee_ring_cmd {
+	u32 cmd_id;
+	u32 cmd_state;
+	u32 status;
+	u32 res0[1];
+	u64 pdata;
+	u32 res1[2];
+	u8 buf[MAX_BUFFER_SIZE];
+
+	/* Total size: 1024 bytes */
+} __packed;
+
+int tee_dev_init(struct psp_device *psp);
+void tee_dev_destroy(struct psp_device *psp);
+
+#endif /* __TEE_DEV_H__ */
--
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH 5/5] crypto: ccp - provide in-kernel API to submit TEE commands
  2019-10-23 11:27 [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Thomas, Rijo-john
                   ` (3 preceding siblings ...)
  2019-10-23 11:27 ` [RFC PATCH 4/5] crypto: ccp - add TEE support for Raven Ridge Thomas, Rijo-john
@ 2019-10-23 11:27 ` Thomas, Rijo-john
  2019-10-25  4:08   ` kbuild test robot
  2019-10-23 16:27 ` [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Lendacky, Thomas
  5 siblings, 1 reply; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-23 11:27 UTC (permalink / raw)
  To: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Thomas, Rijo-john, Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

Extend the functionality of AMD Secure Processor (SP) driver by
providing an in-kernel API to submit commands to TEE ring buffer for
processing by Trusted OS running on AMD Secure Processor.

Following TEE commands are supported by Trusted OS:

* TEE_CMD_ID_LOAD_TA : Load Trusted Application (TA) binary into
  TEE environment
* TEE_CMD_ID_UNLOAD_TA : Unload TA binary from TEE environment
* TEE_CMD_ID_OPEN_SESSION : Open session with loaded TA
* TEE_CMD_ID_CLOSE_SESSION : Close session with loaded TA
* TEE_CMD_ID_INVOKE_CMD : Invoke a command with loaded TA
* TEE_CMD_ID_MAP_SHARED_MEM : Map shared memory
* TEE_CMD_ID_UNMAP_SHARED_MEM : Unmap shared memory

Linux AMD-TEE driver will use this API to submit command buffers
for processing in Trusted Execution Environment. The AMD-TEE driver
shall be introduced in a separate patch.

Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
---
 drivers/crypto/ccp/tee-dev.c | 126 +++++++++++++++++++++++++++++++++++++++++++
 drivers/crypto/ccp/tee-dev.h |   1 +
 include/linux/psp-tee.h      |  72 +++++++++++++++++++++++++
 3 files changed, 199 insertions(+)
 create mode 100644 include/linux/psp-tee.h

diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c
index b2b0215..d35b439 100644
--- a/drivers/crypto/ccp/tee-dev.c
+++ b/drivers/crypto/ccp/tee-dev.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/gfp.h>
 #include <linux/psp-sev.h>
+#include <linux/psp-tee.h>

 #include "psp-dev.h"
 #include "tee-dev.h"
@@ -37,6 +38,7 @@ static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
 	rb_mgr->ring_start = start_addr;
 	rb_mgr->ring_size = ring_size;
 	rb_mgr->ring_pa = __psp_pa(start_addr);
+	mutex_init(&rb_mgr->mutex);

 	return 0;
 }
@@ -54,6 +56,7 @@ static void tee_free_ring(struct psp_tee_device *tee)
 	rb_mgr->ring_start = NULL;
 	rb_mgr->ring_size = 0;
 	rb_mgr->ring_pa = 0;
+	mutex_destroy(&rb_mgr->mutex);
 }

 static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
@@ -235,3 +238,126 @@ void tee_dev_destroy(struct psp_device *psp)

 	tee_destroy_ring(tee);
 }
+
+static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,
+			  void *buf, size_t len, struct tee_ring_cmd **resp)
+{
+	struct tee_ring_cmd *cmd;
+	u32 rptr, wptr;
+	int nloop = 1000, ret = 0;
+
+	*resp = NULL;
+
+	mutex_lock(&tee->rb_mgr.mutex);
+
+	wptr = tee->rb_mgr.wptr;
+
+	/* Check if ring buffer is full */
+	do {
+		rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg);
+
+		if (!(wptr + sizeof(struct tee_ring_cmd) == rptr))
+			break;
+
+		dev_info(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
+			 rptr, wptr);
+
+		/* Wait if ring buffer is full */
+		mutex_unlock(&tee->rb_mgr.mutex);
+		schedule_timeout_interruptible(msecs_to_jiffies(10));
+		mutex_lock(&tee->rb_mgr.mutex);
+
+	} while (--nloop);
+
+	if (!nloop && (wptr + sizeof(struct tee_ring_cmd) == rptr)) {
+		dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
+			rptr, wptr);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	/* Pointer to empty data entry in ring buffer */
+	cmd = (struct tee_ring_cmd *)(tee->rb_mgr.ring_start + wptr);
+
+	/* Write command data into ring buffer */
+	cmd->cmd_id = cmd_id;
+	cmd->cmd_state = TEE_CMD_STATE_INIT;
+	memset(&cmd->buf[0], 0, sizeof(cmd->buf));
+	memcpy(&cmd->buf[0], buf, len);
+
+	/* Update local copy of write pointer */
+	tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd);
+	if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size)
+		tee->rb_mgr.wptr = 0;
+
+	/* Trigger interrupt to Trusted OS */
+	iowrite32(tee->rb_mgr.wptr, tee->io_regs + tee->vdata->ring_wptr_reg);
+
+	/* The response is provided by Trusted OS in same
+	 * location as submitted data entry within ring buffer.
+	 */
+	*resp = cmd;
+
+unlock:
+	mutex_unlock(&tee->rb_mgr.mutex);
+
+	return ret;
+}
+
+static int tee_wait_cmd_completion(struct psp_tee_device *tee,
+				   struct tee_ring_cmd *resp,
+				   unsigned int timeout)
+{
+	/* ~5ms sleep per loop => nloop = timeout * 200 */
+	int nloop = timeout * 200;
+
+	while (--nloop) {
+		if (resp->cmd_state == TEE_CMD_STATE_COMPLETED)
+			return 0;
+
+		usleep_range(5000, 5100);
+	}
+
+	dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n",
+		resp->cmd_id);
+
+	psp_dead = true;
+
+	return -ETIMEDOUT;
+}
+
+int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
+			u32 *status)
+{
+	struct psp_device *psp = psp_get_master_device();
+	struct psp_tee_device *tee;
+	struct tee_ring_cmd *resp;
+	int ret;
+
+	if (!buf || !status || !len || len > sizeof(resp->buf))
+		return -EINVAL;
+
+	*status = 0;
+
+	if (!psp || !psp->tee_data)
+		return -ENODEV;
+
+	if (psp_dead)
+		return -EBUSY;
+
+	tee = psp->tee_data;
+
+	ret = tee_submit_cmd(tee, cmd_id, buf, len, &resp);
+	if (ret)
+		return ret;
+
+	ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT);
+	if (ret)
+		return ret;
+
+	memcpy(buf, &resp->buf[0], len);
+	*status = resp->status;
+
+	return 0;
+}
+EXPORT_SYMBOL(psp_tee_process_cmd);
diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h
index 0d51a0a7..42d5021 100644
--- a/drivers/crypto/ccp/tee-dev.h
+++ b/drivers/crypto/ccp/tee-dev.h
@@ -53,6 +53,7 @@ struct tee_init_ring_cmd {
  * @wptr:        index to the last written entry in ring buffer
  */
 struct ring_buf_manager {
+	struct mutex mutex;	/* synchronizes access to ring buffer */
 	void *ring_start;
 	u32 ring_size;
 	phys_addr_t ring_pa;
diff --git a/include/linux/psp-tee.h b/include/linux/psp-tee.h
new file mode 100644
index 0000000..954a7ac
--- /dev/null
+++ b/include/linux/psp-tee.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * AMD Trusted Execution Environment (TEE) interface
+ *
+ * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
+ *
+ * Copyright 2019 Advanced Micro Devices, Inc.
+ *
+ */
+
+#ifndef __PSP_TEE_H_
+#define __PSP_TEE_H_
+
+#include <linux/types.h>
+
+/* This file defines the Trusted Execution Environment (TEE) interface commands
+ * and the API exported by AMD Secure Processor driver to communicate with
+ * AMD-TEE Trusted OS.
+ */
+
+/**
+ * enum tee_cmd_id - TEE Interface Command IDs
+ * @TEE_CMD_ID_LOAD_TA:          Load Trusted Application (TA) binary into
+ *                               TEE environment
+ * @TEE_CMD_ID_UNLOAD_TA:        Unload TA binary from TEE environment
+ * @TEE_CMD_ID_OPEN_SESSION:     Open session with loaded TA
+ * @TEE_CMD_ID_CLOSE_SESSION:    Close session with loaded TA
+ * @TEE_CMD_ID_INVOKE_CMD:       Invoke a command with loaded TA
+ * @TEE_CMD_ID_MAP_SHARED_MEM:   Map shared memory
+ * @TEE_CMD_ID_UNMAP_SHARED_MEM: Unmap shared memory
+ */
+enum tee_cmd_id {
+	TEE_CMD_ID_LOAD_TA = 1,
+	TEE_CMD_ID_UNLOAD_TA,
+	TEE_CMD_ID_OPEN_SESSION,
+	TEE_CMD_ID_CLOSE_SESSION,
+	TEE_CMD_ID_INVOKE_CMD,
+	TEE_CMD_ID_MAP_SHARED_MEM,
+	TEE_CMD_ID_UNMAP_SHARED_MEM,
+};
+
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+/**
+ * psp_tee_process_cmd() - Process command in Trusted Execution Environment
+ * @cmd_id:     TEE command ID (&enum tee_cmd_id)
+ * @buf:        Command buffer for TEE processing. On success, is updated
+ *              with the response
+ * @len:        Length of command buffer in bytes
+ * @status:     On success, holds the TEE command execution status
+ *
+ * This function submits a command to the Trusted OS for processing in the
+ * TEE environment and waits for a response or until the command times out.
+ *
+ * Returns:
+ * 0 if TEE successfully processed the command
+ * -%ENODEV    if PSP device not available
+ * -%EINVAL    if invalid input
+ * -%ETIMEDOUT if TEE command timed out
+ * -%EBUSY     if PSP device is not responsive
+ */
+int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
+			u32 *status);
+
+#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
+
+static inline int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf,
+				      size_t len, u32 *status)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
+#endif /* __PSP_TEE_H_ */
--
1.9.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev
  2019-10-23 11:27 ` [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev Thomas, Rijo-john
@ 2019-10-23 11:48   ` Ard Biesheuvel
  2019-10-24 11:19     ` Thomas, Rijo-john
  0 siblings, 1 reply; 13+ messages in thread
From: Ard Biesheuvel @ 2019-10-23 11:48 UTC (permalink / raw)
  To: Thomas, Rijo-john
  Cc: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto, Singh, Brijesh, Easow, Nimesh,
	Rangasamy, Devaraj

Hello Thomas,

On Wed, 23 Oct 2019 at 13:27, Thomas, Rijo-john
<Rijo-john.Thomas@amd.com> wrote:
>
> This is a preliminary patch for creating a generic PSP device driver
> file, which will have support for both SEV and TEE (Trusted Execution
> Environment) interface.
>
> This patch does not introduce any new functionality, but simply renames
> psp-dev.c and psp-dev.h files to sev-dev.c and sev-dev.h files
> respectively.
>
> Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
> Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>

This is not the correct way to credit a co-author.

You are sending the patch, so your signoff should come last.

If Devaraj is a co-author of this work, you should add the following
lines *before* your signoff

Co-authored-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>

If Devaraj is the sole author of this work, and you are just sending
it out, you should set the authorship on the patch to Devaraj (so it
will be From: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>)

> ---
>  drivers/crypto/ccp/Makefile  |    2 +-
>  drivers/crypto/ccp/psp-dev.c | 1087 ------------------------------------------
>  drivers/crypto/ccp/psp-dev.h |   66 ---
>  drivers/crypto/ccp/sev-dev.c | 1087 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/crypto/ccp/sev-dev.h |   66 +++
>  drivers/crypto/ccp/sp-pci.c  |    2 +-
>  6 files changed, 1155 insertions(+), 1155 deletions(-)
>  delete mode 100644 drivers/crypto/ccp/psp-dev.c
>  delete mode 100644 drivers/crypto/ccp/psp-dev.h
>  create mode 100644 drivers/crypto/ccp/sev-dev.c
>  create mode 100644 drivers/crypto/ccp/sev-dev.h
>

Please regenerate the patch so that the rename is reflected in the diffstat.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 4/5] crypto: ccp - add TEE support for Raven Ridge
  2019-10-23 11:27 ` [RFC PATCH 4/5] crypto: ccp - add TEE support for Raven Ridge Thomas, Rijo-john
@ 2019-10-23 11:49   ` Ard Biesheuvel
  2019-10-24 11:20     ` Thomas, Rijo-john
  0 siblings, 1 reply; 13+ messages in thread
From: Ard Biesheuvel @ 2019-10-23 11:49 UTC (permalink / raw)
  To: Thomas, Rijo-john, Jens Wiklander
  Cc: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto, Singh, Brijesh, Easow, Nimesh,
	Rangasamy, Devaraj

(+ Jens)

On Wed, 23 Oct 2019 at 13:27, Thomas, Rijo-john
<Rijo-john.Thomas@amd.com> wrote:
>
> Adds a PCI device entry for Raven Ridge. Raven Ridge is an APU with a
> dedicated AMD Secure Processor having Trusted Execution Environment (TEE)
> support. The TEE provides a secure environment for running Trusted
> Applications (TAs) which implement security-sensitive parts of a feature.
>
> This patch configures AMD Secure Processor's TEE interface by initializing
> a ring buffer (shared memory between Rich OS and Trusted OS) which can hold
> multiple command buffer entries. The TEE interface is facilitated by a set
> of CPU to PSP mailbox registers.
>
> The next patch will address how commands are submitted to the ring buffer.
>
> Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
> Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
> ---
>  drivers/crypto/ccp/Makefile  |   3 +-
>  drivers/crypto/ccp/psp-dev.c |  74 +++++++++++++-
>  drivers/crypto/ccp/psp-dev.h |   8 ++
>  drivers/crypto/ccp/sp-dev.h  |  11 +-
>  drivers/crypto/ccp/sp-pci.c  |  27 ++++-
>  drivers/crypto/ccp/tee-dev.c | 237 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/crypto/ccp/tee-dev.h | 108 ++++++++++++++++++++
>  7 files changed, 461 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/crypto/ccp/tee-dev.c
>  create mode 100644 drivers/crypto/ccp/tee-dev.h
>

How does this patch tie into the TEE subsystem we have in drivers/tee?




> diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
> index 3b29ea4..db362fe 100644
> --- a/drivers/crypto/ccp/Makefile
> +++ b/drivers/crypto/ccp/Makefile
> @@ -9,7 +9,8 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \
>  ccp-$(CONFIG_CRYPTO_DEV_CCP_DEBUGFS) += ccp-debugfs.o
>  ccp-$(CONFIG_PCI) += sp-pci.o
>  ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \
> -                                   sev-dev.o
> +                                   sev-dev.o \
> +                                   tee-dev.o
>
>  obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
>  ccp-crypto-objs := ccp-crypto-main.o \
> diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
> index ef8affa..90bcd5f 100644
> --- a/drivers/crypto/ccp/psp-dev.c
> +++ b/drivers/crypto/ccp/psp-dev.c
> @@ -13,6 +13,7 @@
>  #include "sp-dev.h"
>  #include "psp-dev.h"
>  #include "sev-dev.h"
> +#include "tee-dev.h"
>
>  struct psp_device *psp_master;
>
> @@ -45,6 +46,9 @@ static irqreturn_t psp_irq_handler(int irq, void *data)
>         if (status) {
>                 if (psp->sev_irq_handler)
>                         psp->sev_irq_handler(irq, psp->sev_irq_data, status);
> +
> +               if (psp->tee_irq_handler)
> +                       psp->tee_irq_handler(irq, psp->tee_irq_data, status);
>         }
>
>         /* Clear the interrupt status by writing the same value we read. */
> @@ -53,10 +57,11 @@ static irqreturn_t psp_irq_handler(int irq, void *data)
>         return IRQ_HANDLED;
>  }
>
> -static int psp_check_sev_support(struct psp_device *psp)
> +static int psp_check_sev_support(struct psp_device *psp,
> +                                unsigned int capability)
>  {
>         /* Check if device supports SEV feature */
> -       if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) {
> +       if (!(capability & 1)) {
>                 dev_dbg(psp->dev, "psp does not support SEV\n");
>                 return -ENODEV;
>         }
> @@ -64,10 +69,54 @@ static int psp_check_sev_support(struct psp_device *psp)
>         return 0;
>  }
>
> +static int psp_check_tee_support(struct psp_device *psp,
> +                                unsigned int capability)
> +{
> +       /* Check if device supports TEE feature */
> +       if (!(capability & 2)) {
> +               dev_dbg(psp->dev, "psp does not support TEE\n");
> +               return -ENODEV;
> +       }
> +
> +       return 0;
> +}
> +
> +static int psp_check_support(struct psp_device *psp, unsigned int capability)
> +{
> +       int sev_support = psp_check_sev_support(psp, capability);
> +       int tee_support = psp_check_tee_support(psp, capability);
> +
> +       /* Check if device supprts SEV and TEE feature */
> +       if (sev_support && tee_support)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static int psp_init(struct psp_device *psp, unsigned int capability)
> +{
> +       int ret;
> +
> +       if (!psp_check_sev_support(psp, capability)) {
> +               ret = sev_dev_init(psp);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       if (!psp_check_tee_support(psp, capability)) {
> +               ret = tee_dev_init(psp);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +
>  int psp_dev_init(struct sp_device *sp)
>  {
>         struct device *dev = sp->dev;
>         struct psp_device *psp;
> +       unsigned int capability;
>         int ret;
>
>         ret = -ENOMEM;
> @@ -86,7 +135,10 @@ int psp_dev_init(struct sp_device *sp)
>
>         psp->io_regs = sp->io_map;
>
> -       ret = psp_check_sev_support(psp);
> +       /* Read the feature register to get the PSP capability */
> +       capability = ioread32(psp->io_regs + psp->vdata->feature_reg);
> +
> +       ret = psp_check_support(psp, capability);
>         if (ret)
>                 goto e_disable;
>
> @@ -101,7 +153,7 @@ int psp_dev_init(struct sp_device *sp)
>                 goto e_err;
>         }
>
> -       ret = sev_dev_init(psp);
> +       ret = psp_init(psp, capability);
>         if (ret)
>                 goto e_irq;
>
> @@ -139,6 +191,8 @@ void psp_dev_destroy(struct sp_device *sp)
>
>         sev_dev_destroy(psp);
>
> +       tee_dev_destroy(psp);
> +
>         sp_free_psp_irq(sp, psp);
>  }
>
> @@ -154,6 +208,18 @@ void psp_clear_sev_irq_handler(struct psp_device *psp)
>         psp_set_sev_irq_handler(psp, NULL, NULL);
>  }
>
> +void psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
> +                            void *data)
> +{
> +       psp->tee_irq_data = data;
> +       psp->tee_irq_handler = handler;
> +}
> +
> +void psp_clear_tee_irq_handler(struct psp_device *psp)
> +{
> +       psp_set_tee_irq_handler(psp, NULL, NULL);
> +}
> +
>  struct psp_device *psp_get_master_device(void)
>  {
>         struct sp_device *sp = sp_get_psp_master_device();
> diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
> index 7c014ac..ef38e41 100644
> --- a/drivers/crypto/ccp/psp-dev.h
> +++ b/drivers/crypto/ccp/psp-dev.h
> @@ -40,13 +40,21 @@ struct psp_device {
>         psp_irq_handler_t sev_irq_handler;
>         void *sev_irq_data;
>
> +       psp_irq_handler_t tee_irq_handler;
> +       void *tee_irq_data;
> +
>         void *sev_data;
> +       void *tee_data;
>  };
>
>  void psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
>                              void *data);
>  void psp_clear_sev_irq_handler(struct psp_device *psp);
>
> +void psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
> +                            void *data);
> +void psp_clear_tee_irq_handler(struct psp_device *psp);
> +
>  struct psp_device *psp_get_master_device(void);
>
>  #endif /* __PSP_DEV_H */
> diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
> index 0394c75..4235946 100644
> --- a/drivers/crypto/ccp/sp-dev.h
> +++ b/drivers/crypto/ccp/sp-dev.h
> @@ -2,7 +2,7 @@
>  /*
>   * AMD Secure Processor driver
>   *
> - * Copyright (C) 2017-2018 Advanced Micro Devices, Inc.
> + * Copyright (C) 2017-2019 Advanced Micro Devices, Inc.
>   *
>   * Author: Tom Lendacky <thomas.lendacky@amd.com>
>   * Author: Gary R Hook <gary.hook@amd.com>
> @@ -45,8 +45,17 @@ struct sev_vdata {
>         const unsigned int cmdbuff_addr_hi_reg;
>  };
>
> +struct tee_vdata {
> +       const unsigned int cmdresp_reg;
> +       const unsigned int cmdbuff_addr_lo_reg;
> +       const unsigned int cmdbuff_addr_hi_reg;
> +       const unsigned int ring_wptr_reg;
> +       const unsigned int ring_rptr_reg;
> +};
> +
>  struct psp_vdata {
>         const struct sev_vdata *sev;
> +       const struct tee_vdata *tee;
>         const unsigned int feature_reg;
>         const unsigned int inten_reg;
>         const unsigned int intsts_reg;
> diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
> index 733693d..56c1f61 100644
> --- a/drivers/crypto/ccp/sp-pci.c
> +++ b/drivers/crypto/ccp/sp-pci.c
> @@ -2,7 +2,7 @@
>  /*
>   * AMD Secure Processor device driver
>   *
> - * Copyright (C) 2013,2018 Advanced Micro Devices, Inc.
> + * Copyright (C) 2013,2019 Advanced Micro Devices, Inc.
>   *
>   * Author: Tom Lendacky <thomas.lendacky@amd.com>
>   * Author: Gary R Hook <gary.hook@amd.com>
> @@ -274,6 +274,14 @@ static int sp_pci_resume(struct pci_dev *pdev)
>         .cmdbuff_addr_hi_reg    = 0x109e4,
>  };
>
> +static const struct tee_vdata teev1 = {
> +       .cmdresp_reg            = 0x10544,
> +       .cmdbuff_addr_lo_reg    = 0x10548,
> +       .cmdbuff_addr_hi_reg    = 0x1054c,
> +       .ring_wptr_reg          = 0x10550,
> +       .ring_rptr_reg          = 0x10554,
> +};
> +
>  static const struct psp_vdata pspv1 = {
>         .sev                    = &sevv1,
>         .feature_reg            = 0x105fc,
> @@ -287,6 +295,13 @@ static int sp_pci_resume(struct pci_dev *pdev)
>         .inten_reg              = 0x10690,
>         .intsts_reg             = 0x10694,
>  };
> +
> +static const struct psp_vdata pspv3 = {
> +       .tee                    = &teev1,
> +       .feature_reg            = 0x109fc,
> +       .inten_reg              = 0x10690,
> +       .intsts_reg             = 0x10694,
> +};
>  #endif
>
>  static const struct sp_dev_vdata dev_vdata[] = {
> @@ -320,12 +335,22 @@ static int sp_pci_resume(struct pci_dev *pdev)
>                 .psp_vdata = &pspv2,
>  #endif
>         },
> +       {       /* 4 */
> +               .bar = 2,
> +#ifdef CONFIG_CRYPTO_DEV_SP_CCP
> +               .ccp_vdata = &ccpv5a,
> +#endif
> +#ifdef CONFIG_CRYPTO_DEV_SP_PSP
> +               .psp_vdata = &pspv3,
> +#endif
> +       },
>  };
>  static const struct pci_device_id sp_pci_table[] = {
>         { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] },
>         { PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] },
>         { PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] },
>         { PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] },
> +       { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] },
>         /* Last entry must be zero */
>         { 0, }
>  };
> diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c
> new file mode 100644
> index 0000000..b2b0215
> --- /dev/null
> +++ b/drivers/crypto/ccp/tee-dev.c
> @@ -0,0 +1,237 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * AMD Trusted Execution Environment (TEE) interface
> + *
> + * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
> + *
> + * Copyright 2019 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/mutex.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/gfp.h>
> +#include <linux/psp-sev.h>
> +
> +#include "psp-dev.h"
> +#include "tee-dev.h"
> +
> +static bool psp_dead;
> +
> +static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
> +{
> +       struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
> +       void *start_addr;
> +
> +       if (!ring_size)
> +               return -EINVAL;
> +
> +       /* We need actual physical address instead of DMA address, since
> +        * Trusted OS running on AMD Secure Processor will map this region
> +        */
> +       start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size));
> +       if (!start_addr)
> +               return -ENOMEM;
> +
> +       rb_mgr->ring_start = start_addr;
> +       rb_mgr->ring_size = ring_size;
> +       rb_mgr->ring_pa = __psp_pa(start_addr);
> +
> +       return 0;
> +}
> +
> +static void tee_free_ring(struct psp_tee_device *tee)
> +{
> +       struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
> +
> +       if (!rb_mgr->ring_start)
> +               return;
> +
> +       free_pages((unsigned long)rb_mgr->ring_start,
> +                  get_order(rb_mgr->ring_size));
> +
> +       rb_mgr->ring_start = NULL;
> +       rb_mgr->ring_size = 0;
> +       rb_mgr->ring_pa = 0;
> +}
> +
> +static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
> +                            unsigned int *reg)
> +{
> +       /* ~10ms sleep per loop => nloop = timeout * 100 */
> +       int nloop = timeout * 100;
> +
> +       while (--nloop) {
> +               *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg);
> +               if (*reg & PSP_CMDRESP_RESP)
> +                       return 0;
> +
> +               usleep_range(10000, 10100);
> +       }
> +
> +       dev_err(tee->dev, "tee: command timed out, disabling PSP\n");
> +       psp_dead = true;
> +
> +       return -ETIMEDOUT;
> +}
> +
> +static
> +struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
> +{
> +       struct tee_init_ring_cmd *cmd;
> +
> +       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> +       if (!cmd)
> +               return NULL;
> +
> +       cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa);
> +       cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa);
> +       cmd->size = tee->rb_mgr.ring_size;
> +
> +       dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n",
> +               cmd->hi_addr, cmd->low_addr, cmd->size);
> +
> +       return cmd;
> +}
> +
> +static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
> +{
> +       kfree(cmd);
> +}
> +
> +static int tee_init_ring(struct psp_tee_device *tee)
> +{
> +       int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
> +       struct tee_init_ring_cmd *cmd;
> +       phys_addr_t cmd_buffer;
> +       unsigned int reg;
> +       int ret;
> +
> +       BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024);
> +
> +       ret = tee_alloc_ring(tee, ring_size);
> +       if (ret) {
> +               dev_err(tee->dev, "tee: ring allocation failed %d\n", ret);
> +               return ret;
> +       }
> +
> +       tee->rb_mgr.wptr = 0;
> +
> +       cmd = tee_alloc_cmd_buffer(tee);
> +       if (!cmd) {
> +               tee_free_ring(tee);
> +               return -ENOMEM;
> +       }
> +
> +       cmd_buffer = __psp_pa((void *)cmd);
> +
> +       /* Send command buffer details to Trusted OS by writing to
> +        * CPU-PSP message registers
> +        */
> +
> +       iowrite32(lower_32_bits(cmd_buffer),
> +                 tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg);
> +       iowrite32(upper_32_bits(cmd_buffer),
> +                 tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg);
> +       iowrite32(TEE_RING_INIT_CMD,
> +                 tee->io_regs + tee->vdata->cmdresp_reg);
> +
> +       ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
> +       if (ret) {
> +               dev_err(tee->dev, "tee: ring init command timed out\n");
> +               tee_free_ring(tee);
> +               goto free_buf;
> +       }
> +
> +       if (reg & PSP_CMDRESP_ERR_MASK) {
> +               dev_err(tee->dev, "tee: ring init command failed (%#010x)\n",
> +                       reg & PSP_CMDRESP_ERR_MASK);
> +               tee_free_ring(tee);
> +               ret = -EIO;
> +       }
> +
> +free_buf:
> +       tee_free_cmd_buffer(cmd);
> +
> +       return ret;
> +}
> +
> +static void tee_destroy_ring(struct psp_tee_device *tee)
> +{
> +       unsigned int reg;
> +       int ret;
> +
> +       if (!tee->rb_mgr.ring_start)
> +               return;
> +
> +       if (psp_dead)
> +               goto free_ring;
> +
> +       iowrite32(TEE_RING_DESTROY_CMD,
> +                 tee->io_regs + tee->vdata->cmdresp_reg);
> +
> +       ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
> +       if (ret) {
> +               dev_err(tee->dev, "tee: ring destroy command timed out\n");
> +       } else if (reg & PSP_CMDRESP_ERR_MASK) {
> +               dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n",
> +                       reg & PSP_CMDRESP_ERR_MASK);
> +       }
> +
> +free_ring:
> +       tee_free_ring(tee);
> +}
> +
> +int tee_dev_init(struct psp_device *psp)
> +{
> +       struct device *dev = psp->dev;
> +       struct psp_tee_device *tee;
> +       int ret;
> +
> +       ret = -ENOMEM;
> +       tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL);
> +       if (!tee)
> +               goto e_err;
> +
> +       psp->tee_data = tee;
> +
> +       tee->dev = dev;
> +       tee->psp = psp;
> +
> +       tee->io_regs = psp->io_regs;
> +
> +       tee->vdata = (struct tee_vdata *)psp->vdata->tee;
> +       if (!tee->vdata) {
> +               ret = -ENODEV;
> +               dev_err(dev, "tee: missing driver data\n");
> +               goto e_err;
> +       }
> +
> +       ret = tee_init_ring(tee);
> +       if (ret) {
> +               dev_err(dev, "tee: failed to init ring buffer\n");
> +               goto e_err;
> +       }
> +
> +       dev_notice(dev, "tee enabled\n");
> +
> +       return 0;
> +
> +e_err:
> +       psp->tee_data = NULL;
> +
> +       dev_notice(dev, "tee initialization failed\n");
> +
> +       return ret;
> +}
> +
> +void tee_dev_destroy(struct psp_device *psp)
> +{
> +       struct psp_tee_device *tee = psp->tee_data;
> +
> +       if (!tee)
> +               return;
> +
> +       tee_destroy_ring(tee);
> +}
> diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h
> new file mode 100644
> index 0000000..0d51a0a7
> --- /dev/null
> +++ b/drivers/crypto/ccp/tee-dev.h
> @@ -0,0 +1,108 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright 2019 Advanced Micro Devices, Inc.
> + *
> + * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
> + *
> + */
> +
> +/* This file describes the TEE communication interface between host and AMD
> + * Secure Processor
> + */
> +
> +#ifndef __TEE_DEV_H__
> +#define __TEE_DEV_H__
> +
> +#include <linux/device.h>
> +#include <linux/mutex.h>
> +
> +#define TEE_DEFAULT_TIMEOUT            10
> +#define MAX_BUFFER_SIZE                        992
> +
> +/**
> + * enum tee_ring_cmd_id - TEE interface commands for ring buffer configuration
> + * @TEE_RING_INIT_CMD:         Initialize ring buffer
> + * @TEE_RING_DESTROY_CMD:      Destroy ring buffer
> + * @TEE_RING_MAX_CMD:          Maximum command id
> + */
> +enum tee_ring_cmd_id {
> +       TEE_RING_INIT_CMD               = 0x00010000,
> +       TEE_RING_DESTROY_CMD            = 0x00020000,
> +       TEE_RING_MAX_CMD                = 0x000F0000,
> +};
> +
> +/**
> + * struct tee_init_ring_cmd - Command to init TEE ring buffer
> + * @low_addr:  bits [31:0] of the physical address of ring buffer
> + * @hi_addr:   bits [63:32] of the physical address of ring buffer
> + * @size:      size of ring buffer in bytes
> + */
> +struct tee_init_ring_cmd {
> +       u32 low_addr;
> +       u32 hi_addr;
> +       u32 size;
> +};
> +
> +#define MAX_RING_BUFFER_ENTRIES                32
> +
> +/**
> + * struct ring_buf_manager - Helper structure to manage ring buffer.
> + * @ring_start:  starting address of ring buffer
> + * @ring_size:   size of ring buffer in bytes
> + * @ring_pa:     physical address of ring buffer
> + * @wptr:        index to the last written entry in ring buffer
> + */
> +struct ring_buf_manager {
> +       void *ring_start;
> +       u32 ring_size;
> +       phys_addr_t ring_pa;
> +       u32 wptr;
> +};
> +
> +struct psp_tee_device {
> +       struct device *dev;
> +       struct psp_device *psp;
> +       void __iomem *io_regs;
> +       struct tee_vdata *vdata;
> +       struct ring_buf_manager rb_mgr;
> +};
> +
> +/**
> + * enum tee_cmd_state - TEE command states for the ring buffer interface
> + * @TEE_CMD_STATE_INIT:      initial state of command when sent from host
> + * @TEE_CMD_STATE_PROCESS:   command being processed by TEE environment
> + * @TEE_CMD_STATE_COMPLETED: command processing completed
> + */
> +enum tee_cmd_state {
> +       TEE_CMD_STATE_INIT,
> +       TEE_CMD_STATE_PROCESS,
> +       TEE_CMD_STATE_COMPLETED,
> +};
> +
> +/**
> + * struct tee_ring_cmd - Structure of the command buffer in TEE ring
> + * @cmd_id:      refers to &enum tee_cmd_id. Command id for the ring buffer
> + *               interface
> + * @cmd_state:   refers to &enum tee_cmd_state
> + * @status:      status of TEE command execution
> + * @res0:        reserved region
> + * @pdata:       private data (currently unused)
> + * @res1:        reserved region
> + * @buf:         TEE command specific buffer
> + */
> +struct tee_ring_cmd {
> +       u32 cmd_id;
> +       u32 cmd_state;
> +       u32 status;
> +       u32 res0[1];
> +       u64 pdata;
> +       u32 res1[2];
> +       u8 buf[MAX_BUFFER_SIZE];
> +
> +       /* Total size: 1024 bytes */
> +} __packed;
> +
> +int tee_dev_init(struct psp_device *psp);
> +void tee_dev_destroy(struct psp_device *psp);
> +
> +#endif /* __TEE_DEV_H__ */
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver
  2019-10-23 11:27 [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Thomas, Rijo-john
                   ` (4 preceding siblings ...)
  2019-10-23 11:27 ` [RFC PATCH 5/5] crypto: ccp - provide in-kernel API to submit TEE commands Thomas, Rijo-john
@ 2019-10-23 16:27 ` Lendacky, Thomas
  2019-10-24 11:21   ` Thomas, Rijo-john
  5 siblings, 1 reply; 13+ messages in thread
From: Lendacky, Thomas @ 2019-10-23 16:27 UTC (permalink / raw)
  To: Thomas, Rijo-john, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

On 10/23/19 6:27 AM, Thomas, Rijo-john wrote:
> The goal of this patch series is to introduce TEE (Trusted Execution
> Environment) interface support to AMD Secure Processor driver. The
> TEE is a secure area of a processor which ensures that sensitive data
> is stored, processed and protected in an isolated and trusted
> environment. The Platform Security Processor (PSP) is a dedicated
> processor which provides TEE to enable HW platform security. It offers
> protection against software attacks generated in Rich Operating System
> (Rich OS) such as Linux running on x86.
> 
> Based on the platform feature support, the PSP is capable of supporting
> either SEV (Secure Encrypted Virtualization) and/or TEE. The first three
> patches in this series is about moving SEV specific functions and data
> structures from PSP device driver file to a dedicated SEV interface
> driver file. The last two patches add TEE interface support to AMD
> Secure Processor driver. This TEE interface will be used by AMD-TEE
> driver to submit command buffers for processing in PSP Trusted Execution
> Environment.

There are some outstanding patches that have been submitted that modify
some of the same files you are modifying, so you'll need to rebase after
those patches are applied. Also, one patch was applied through the KVM
tree, not sure how to handle that.

For reference, here are the submitted patches:

https://lore.kernel.org/kvm/6108561e392460ade67f7f70d9bfa9f56a925d0a.1570137447.git.thomas.lendacky@amd.com/
https://lore.kernel.org/linux-crypto/20191017223459.64281-1-Ashish.Kalra@amd.com/
https://lore.kernel.org/linux-crypto/157166548259.28287.18118802909801681546.stgit@taos/

Thanks,
Tom

> 
> Rijo Thomas (5):
>   crypto: ccp - rename psp-dev files to sev-dev
>   crypto: ccp - create a generic psp-dev file
>   crypto: ccp - move SEV vdata to a dedicated data structure
>   crypto: ccp - add TEE support for Raven Ridge
>   crypto: ccp - provide in-kernel API to submit TEE commands
> 
>  drivers/crypto/ccp/Makefile  |    4 +-
>  drivers/crypto/ccp/psp-dev.c |  983 +++------------------------------------
>  drivers/crypto/ccp/psp-dev.h |   50 +-
>  drivers/crypto/ccp/sev-dev.c | 1041 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/crypto/ccp/sev-dev.h |   62 +++
>  drivers/crypto/ccp/sp-dev.h  |   17 +-
>  drivers/crypto/ccp/sp-pci.c  |   43 +-
>  drivers/crypto/ccp/tee-dev.c |  363 +++++++++++++++
>  drivers/crypto/ccp/tee-dev.h |  109 +++++
>  include/linux/psp-tee.h      |   72 +++
>  10 files changed, 1796 insertions(+), 948 deletions(-)
>  create mode 100644 drivers/crypto/ccp/sev-dev.c
>  create mode 100644 drivers/crypto/ccp/sev-dev.h
>  create mode 100644 drivers/crypto/ccp/tee-dev.c
>  create mode 100644 drivers/crypto/ccp/tee-dev.h
>  create mode 100644 include/linux/psp-tee.h
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev
  2019-10-23 11:48   ` Ard Biesheuvel
@ 2019-10-24 11:19     ` Thomas, Rijo-john
  0 siblings, 0 replies; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-24 11:19 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto, Singh, Brijesh, Easow, Nimesh,
	Rangasamy, Devaraj

Hello Ard,

On 23/10/19 5:18 PM, Ard Biesheuvel wrote:
> Hello Thomas,
> 
> On Wed, 23 Oct 2019 at 13:27, Thomas, Rijo-john
> <Rijo-john.Thomas@amd.com> wrote:
>>
>> This is a preliminary patch for creating a generic PSP device driver
>> file, which will have support for both SEV and TEE (Trusted Execution
>> Environment) interface.
>>
>> This patch does not introduce any new functionality, but simply renames
>> psp-dev.c and psp-dev.h files to sev-dev.c and sev-dev.h files
>> respectively.
>>
>> Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
>> Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
> 
> This is not the correct way to credit a co-author.
> 
> You are sending the patch, so your signoff should come last.
> 
> If Devaraj is a co-author of this work, you should add the following
> lines *before* your signoff
> 
> Co-authored-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
> Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
> 
> If Devaraj is the sole author of this work, and you are just sending
> it out, you should set the authorship on the patch to Devaraj (so it
> will be From: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>)
> 

Okay, in my next patch revision I shall correct this.
Devaraj is the co-author.

So, the lines would like like:

Co-authored-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>

>> ---
>>  drivers/crypto/ccp/Makefile  |    2 +-
>>  drivers/crypto/ccp/psp-dev.c | 1087 ------------------------------------------
>>  drivers/crypto/ccp/psp-dev.h |   66 ---
>>  drivers/crypto/ccp/sev-dev.c | 1087 ++++++++++++++++++++++++++++++++++++++++++
>>  drivers/crypto/ccp/sev-dev.h |   66 +++
>>  drivers/crypto/ccp/sp-pci.c  |    2 +-
>>  6 files changed, 1155 insertions(+), 1155 deletions(-)
>>  delete mode 100644 drivers/crypto/ccp/psp-dev.c
>>  delete mode 100644 drivers/crypto/ccp/psp-dev.h
>>  create mode 100644 drivers/crypto/ccp/sev-dev.c
>>  create mode 100644 drivers/crypto/ccp/sev-dev.h
>>
> 
> Please regenerate the patch so that the rename is reflected in the diffstat.
> 

Okay, I will regenerate the patch with proper diffstat.

Thanks,
Rijo

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 4/5] crypto: ccp - add TEE support for Raven Ridge
  2019-10-23 11:49   ` Ard Biesheuvel
@ 2019-10-24 11:20     ` Thomas, Rijo-john
  0 siblings, 0 replies; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-24 11:20 UTC (permalink / raw)
  To: Ard Biesheuvel, Jens Wiklander
  Cc: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto, Singh, Brijesh, Easow, Nimesh,
	Rangasamy, Devaraj

Hello Ard,

On 23/10/19 5:19 PM, Ard Biesheuvel wrote:
> (+ Jens)
> 
> On Wed, 23 Oct 2019 at 13:27, Thomas, Rijo-john
> <Rijo-john.Thomas@amd.com> wrote:
>>
>> Adds a PCI device entry for Raven Ridge. Raven Ridge is an APU with a
>> dedicated AMD Secure Processor having Trusted Execution Environment (TEE)
>> support. The TEE provides a secure environment for running Trusted
>> Applications (TAs) which implement security-sensitive parts of a feature.
>>
>> This patch configures AMD Secure Processor's TEE interface by initializing
>> a ring buffer (shared memory between Rich OS and Trusted OS) which can hold
>> multiple command buffer entries. The TEE interface is facilitated by a set
>> of CPU to PSP mailbox registers.
>>
>> The next patch will address how commands are submitted to the ring buffer.
>>
>> Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com>
>> Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
>> ---
>>  drivers/crypto/ccp/Makefile  |   3 +-
>>  drivers/crypto/ccp/psp-dev.c |  74 +++++++++++++-
>>  drivers/crypto/ccp/psp-dev.h |   8 ++
>>  drivers/crypto/ccp/sp-dev.h  |  11 +-
>>  drivers/crypto/ccp/sp-pci.c  |  27 ++++-
>>  drivers/crypto/ccp/tee-dev.c | 237 +++++++++++++++++++++++++++++++++++++++++++
>>  drivers/crypto/ccp/tee-dev.h | 108 ++++++++++++++++++++
>>  7 files changed, 461 insertions(+), 7 deletions(-)
>>  create mode 100644 drivers/crypto/ccp/tee-dev.c
>>  create mode 100644 drivers/crypto/ccp/tee-dev.h
>>
> 
> How does this patch tie into the TEE subsystem we have in drivers/tee?
> 
> 

In the next patch in this series:

crypto: ccp - provide in-kernel API to submit TEE commands

Link : https://patchwork.kernel.org/patch/11206441/

we introduce an API psp_tee_process_cmd(), which will be called by AMD-TEE
driver. The AMD-TEE drivers registers itself with the TEE subsystem and uses
psp_tee_process_cmd() to submit command buffers for processing by Trusted OS
running on AMD Secure Processor.

The AMD-TEE driver is introduced as a separate patchset and can be found here:
https://lkml.org/lkml/2019/10/23/457

Thanks,
Rijo

> 
> 
>> diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
>> index 3b29ea4..db362fe 100644
>> --- a/drivers/crypto/ccp/Makefile
>> +++ b/drivers/crypto/ccp/Makefile
>> @@ -9,7 +9,8 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \
>>  ccp-$(CONFIG_CRYPTO_DEV_CCP_DEBUGFS) += ccp-debugfs.o
>>  ccp-$(CONFIG_PCI) += sp-pci.o
>>  ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \
>> -                                   sev-dev.o
>> +                                   sev-dev.o \
>> +                                   tee-dev.o
>>
>>  obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
>>  ccp-crypto-objs := ccp-crypto-main.o \
>> diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
>> index ef8affa..90bcd5f 100644
>> --- a/drivers/crypto/ccp/psp-dev.c
>> +++ b/drivers/crypto/ccp/psp-dev.c
>> @@ -13,6 +13,7 @@
>>  #include "sp-dev.h"
>>  #include "psp-dev.h"
>>  #include "sev-dev.h"
>> +#include "tee-dev.h"
>>
>>  struct psp_device *psp_master;
>>
>> @@ -45,6 +46,9 @@ static irqreturn_t psp_irq_handler(int irq, void *data)
>>         if (status) {
>>                 if (psp->sev_irq_handler)
>>                         psp->sev_irq_handler(irq, psp->sev_irq_data, status);
>> +
>> +               if (psp->tee_irq_handler)
>> +                       psp->tee_irq_handler(irq, psp->tee_irq_data, status);
>>         }
>>
>>         /* Clear the interrupt status by writing the same value we read. */
>> @@ -53,10 +57,11 @@ static irqreturn_t psp_irq_handler(int irq, void *data)
>>         return IRQ_HANDLED;
>>  }
>>
>> -static int psp_check_sev_support(struct psp_device *psp)
>> +static int psp_check_sev_support(struct psp_device *psp,
>> +                                unsigned int capability)
>>  {
>>         /* Check if device supports SEV feature */
>> -       if (!(ioread32(psp->io_regs + psp->vdata->feature_reg) & 1)) {
>> +       if (!(capability & 1)) {
>>                 dev_dbg(psp->dev, "psp does not support SEV\n");
>>                 return -ENODEV;
>>         }
>> @@ -64,10 +69,54 @@ static int psp_check_sev_support(struct psp_device *psp)
>>         return 0;
>>  }
>>
>> +static int psp_check_tee_support(struct psp_device *psp,
>> +                                unsigned int capability)
>> +{
>> +       /* Check if device supports TEE feature */
>> +       if (!(capability & 2)) {
>> +               dev_dbg(psp->dev, "psp does not support TEE\n");
>> +               return -ENODEV;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int psp_check_support(struct psp_device *psp, unsigned int capability)
>> +{
>> +       int sev_support = psp_check_sev_support(psp, capability);
>> +       int tee_support = psp_check_tee_support(psp, capability);
>> +
>> +       /* Check if device supprts SEV and TEE feature */
>> +       if (sev_support && tee_support)
>> +               return -ENODEV;
>> +
>> +       return 0;
>> +}
>> +
>> +static int psp_init(struct psp_device *psp, unsigned int capability)
>> +{
>> +       int ret;
>> +
>> +       if (!psp_check_sev_support(psp, capability)) {
>> +               ret = sev_dev_init(psp);
>> +               if (ret)
>> +                       return ret;
>> +       }
>> +
>> +       if (!psp_check_tee_support(psp, capability)) {
>> +               ret = tee_dev_init(psp);
>> +               if (ret)
>> +                       return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>  int psp_dev_init(struct sp_device *sp)
>>  {
>>         struct device *dev = sp->dev;
>>         struct psp_device *psp;
>> +       unsigned int capability;
>>         int ret;
>>
>>         ret = -ENOMEM;
>> @@ -86,7 +135,10 @@ int psp_dev_init(struct sp_device *sp)
>>
>>         psp->io_regs = sp->io_map;
>>
>> -       ret = psp_check_sev_support(psp);
>> +       /* Read the feature register to get the PSP capability */
>> +       capability = ioread32(psp->io_regs + psp->vdata->feature_reg);
>> +
>> +       ret = psp_check_support(psp, capability);
>>         if (ret)
>>                 goto e_disable;
>>
>> @@ -101,7 +153,7 @@ int psp_dev_init(struct sp_device *sp)
>>                 goto e_err;
>>         }
>>
>> -       ret = sev_dev_init(psp);
>> +       ret = psp_init(psp, capability);
>>         if (ret)
>>                 goto e_irq;
>>
>> @@ -139,6 +191,8 @@ void psp_dev_destroy(struct sp_device *sp)
>>
>>         sev_dev_destroy(psp);
>>
>> +       tee_dev_destroy(psp);
>> +
>>         sp_free_psp_irq(sp, psp);
>>  }
>>
>> @@ -154,6 +208,18 @@ void psp_clear_sev_irq_handler(struct psp_device *psp)
>>         psp_set_sev_irq_handler(psp, NULL, NULL);
>>  }
>>
>> +void psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
>> +                            void *data)
>> +{
>> +       psp->tee_irq_data = data;
>> +       psp->tee_irq_handler = handler;
>> +}
>> +
>> +void psp_clear_tee_irq_handler(struct psp_device *psp)
>> +{
>> +       psp_set_tee_irq_handler(psp, NULL, NULL);
>> +}
>> +
>>  struct psp_device *psp_get_master_device(void)
>>  {
>>         struct sp_device *sp = sp_get_psp_master_device();
>> diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
>> index 7c014ac..ef38e41 100644
>> --- a/drivers/crypto/ccp/psp-dev.h
>> +++ b/drivers/crypto/ccp/psp-dev.h
>> @@ -40,13 +40,21 @@ struct psp_device {
>>         psp_irq_handler_t sev_irq_handler;
>>         void *sev_irq_data;
>>
>> +       psp_irq_handler_t tee_irq_handler;
>> +       void *tee_irq_data;
>> +
>>         void *sev_data;
>> +       void *tee_data;
>>  };
>>
>>  void psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
>>                              void *data);
>>  void psp_clear_sev_irq_handler(struct psp_device *psp);
>>
>> +void psp_set_tee_irq_handler(struct psp_device *psp, psp_irq_handler_t handler,
>> +                            void *data);
>> +void psp_clear_tee_irq_handler(struct psp_device *psp);
>> +
>>  struct psp_device *psp_get_master_device(void);
>>
>>  #endif /* __PSP_DEV_H */
>> diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
>> index 0394c75..4235946 100644
>> --- a/drivers/crypto/ccp/sp-dev.h
>> +++ b/drivers/crypto/ccp/sp-dev.h
>> @@ -2,7 +2,7 @@
>>  /*
>>   * AMD Secure Processor driver
>>   *
>> - * Copyright (C) 2017-2018 Advanced Micro Devices, Inc.
>> + * Copyright (C) 2017-2019 Advanced Micro Devices, Inc.
>>   *
>>   * Author: Tom Lendacky <thomas.lendacky@amd.com>
>>   * Author: Gary R Hook <gary.hook@amd.com>
>> @@ -45,8 +45,17 @@ struct sev_vdata {
>>         const unsigned int cmdbuff_addr_hi_reg;
>>  };
>>
>> +struct tee_vdata {
>> +       const unsigned int cmdresp_reg;
>> +       const unsigned int cmdbuff_addr_lo_reg;
>> +       const unsigned int cmdbuff_addr_hi_reg;
>> +       const unsigned int ring_wptr_reg;
>> +       const unsigned int ring_rptr_reg;
>> +};
>> +
>>  struct psp_vdata {
>>         const struct sev_vdata *sev;
>> +       const struct tee_vdata *tee;
>>         const unsigned int feature_reg;
>>         const unsigned int inten_reg;
>>         const unsigned int intsts_reg;
>> diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
>> index 733693d..56c1f61 100644
>> --- a/drivers/crypto/ccp/sp-pci.c
>> +++ b/drivers/crypto/ccp/sp-pci.c
>> @@ -2,7 +2,7 @@
>>  /*
>>   * AMD Secure Processor device driver
>>   *
>> - * Copyright (C) 2013,2018 Advanced Micro Devices, Inc.
>> + * Copyright (C) 2013,2019 Advanced Micro Devices, Inc.
>>   *
>>   * Author: Tom Lendacky <thomas.lendacky@amd.com>
>>   * Author: Gary R Hook <gary.hook@amd.com>
>> @@ -274,6 +274,14 @@ static int sp_pci_resume(struct pci_dev *pdev)
>>         .cmdbuff_addr_hi_reg    = 0x109e4,
>>  };
>>
>> +static const struct tee_vdata teev1 = {
>> +       .cmdresp_reg            = 0x10544,
>> +       .cmdbuff_addr_lo_reg    = 0x10548,
>> +       .cmdbuff_addr_hi_reg    = 0x1054c,
>> +       .ring_wptr_reg          = 0x10550,
>> +       .ring_rptr_reg          = 0x10554,
>> +};
>> +
>>  static const struct psp_vdata pspv1 = {
>>         .sev                    = &sevv1,
>>         .feature_reg            = 0x105fc,
>> @@ -287,6 +295,13 @@ static int sp_pci_resume(struct pci_dev *pdev)
>>         .inten_reg              = 0x10690,
>>         .intsts_reg             = 0x10694,
>>  };
>> +
>> +static const struct psp_vdata pspv3 = {
>> +       .tee                    = &teev1,
>> +       .feature_reg            = 0x109fc,
>> +       .inten_reg              = 0x10690,
>> +       .intsts_reg             = 0x10694,
>> +};
>>  #endif
>>
>>  static const struct sp_dev_vdata dev_vdata[] = {
>> @@ -320,12 +335,22 @@ static int sp_pci_resume(struct pci_dev *pdev)
>>                 .psp_vdata = &pspv2,
>>  #endif
>>         },
>> +       {       /* 4 */
>> +               .bar = 2,
>> +#ifdef CONFIG_CRYPTO_DEV_SP_CCP
>> +               .ccp_vdata = &ccpv5a,
>> +#endif
>> +#ifdef CONFIG_CRYPTO_DEV_SP_PSP
>> +               .psp_vdata = &pspv3,
>> +#endif
>> +       },
>>  };
>>  static const struct pci_device_id sp_pci_table[] = {
>>         { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] },
>>         { PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] },
>>         { PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] },
>>         { PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] },
>> +       { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] },
>>         /* Last entry must be zero */
>>         { 0, }
>>  };
>> diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c
>> new file mode 100644
>> index 0000000..b2b0215
>> --- /dev/null
>> +++ b/drivers/crypto/ccp/tee-dev.c
>> @@ -0,0 +1,237 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * AMD Trusted Execution Environment (TEE) interface
>> + *
>> + * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
>> + *
>> + * Copyright 2019 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#include <linux/types.h>
>> +#include <linux/mutex.h>
>> +#include <linux/delay.h>
>> +#include <linux/slab.h>
>> +#include <linux/gfp.h>
>> +#include <linux/psp-sev.h>
>> +
>> +#include "psp-dev.h"
>> +#include "tee-dev.h"
>> +
>> +static bool psp_dead;
>> +
>> +static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
>> +{
>> +       struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
>> +       void *start_addr;
>> +
>> +       if (!ring_size)
>> +               return -EINVAL;
>> +
>> +       /* We need actual physical address instead of DMA address, since
>> +        * Trusted OS running on AMD Secure Processor will map this region
>> +        */
>> +       start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size));
>> +       if (!start_addr)
>> +               return -ENOMEM;
>> +
>> +       rb_mgr->ring_start = start_addr;
>> +       rb_mgr->ring_size = ring_size;
>> +       rb_mgr->ring_pa = __psp_pa(start_addr);
>> +
>> +       return 0;
>> +}
>> +
>> +static void tee_free_ring(struct psp_tee_device *tee)
>> +{
>> +       struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
>> +
>> +       if (!rb_mgr->ring_start)
>> +               return;
>> +
>> +       free_pages((unsigned long)rb_mgr->ring_start,
>> +                  get_order(rb_mgr->ring_size));
>> +
>> +       rb_mgr->ring_start = NULL;
>> +       rb_mgr->ring_size = 0;
>> +       rb_mgr->ring_pa = 0;
>> +}
>> +
>> +static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
>> +                            unsigned int *reg)
>> +{
>> +       /* ~10ms sleep per loop => nloop = timeout * 100 */
>> +       int nloop = timeout * 100;
>> +
>> +       while (--nloop) {
>> +               *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg);
>> +               if (*reg & PSP_CMDRESP_RESP)
>> +                       return 0;
>> +
>> +               usleep_range(10000, 10100);
>> +       }
>> +
>> +       dev_err(tee->dev, "tee: command timed out, disabling PSP\n");
>> +       psp_dead = true;
>> +
>> +       return -ETIMEDOUT;
>> +}
>> +
>> +static
>> +struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
>> +{
>> +       struct tee_init_ring_cmd *cmd;
>> +
>> +       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
>> +       if (!cmd)
>> +               return NULL;
>> +
>> +       cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa);
>> +       cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa);
>> +       cmd->size = tee->rb_mgr.ring_size;
>> +
>> +       dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n",
>> +               cmd->hi_addr, cmd->low_addr, cmd->size);
>> +
>> +       return cmd;
>> +}
>> +
>> +static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
>> +{
>> +       kfree(cmd);
>> +}
>> +
>> +static int tee_init_ring(struct psp_tee_device *tee)
>> +{
>> +       int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
>> +       struct tee_init_ring_cmd *cmd;
>> +       phys_addr_t cmd_buffer;
>> +       unsigned int reg;
>> +       int ret;
>> +
>> +       BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024);
>> +
>> +       ret = tee_alloc_ring(tee, ring_size);
>> +       if (ret) {
>> +               dev_err(tee->dev, "tee: ring allocation failed %d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       tee->rb_mgr.wptr = 0;
>> +
>> +       cmd = tee_alloc_cmd_buffer(tee);
>> +       if (!cmd) {
>> +               tee_free_ring(tee);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       cmd_buffer = __psp_pa((void *)cmd);
>> +
>> +       /* Send command buffer details to Trusted OS by writing to
>> +        * CPU-PSP message registers
>> +        */
>> +
>> +       iowrite32(lower_32_bits(cmd_buffer),
>> +                 tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg);
>> +       iowrite32(upper_32_bits(cmd_buffer),
>> +                 tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg);
>> +       iowrite32(TEE_RING_INIT_CMD,
>> +                 tee->io_regs + tee->vdata->cmdresp_reg);
>> +
>> +       ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
>> +       if (ret) {
>> +               dev_err(tee->dev, "tee: ring init command timed out\n");
>> +               tee_free_ring(tee);
>> +               goto free_buf;
>> +       }
>> +
>> +       if (reg & PSP_CMDRESP_ERR_MASK) {
>> +               dev_err(tee->dev, "tee: ring init command failed (%#010x)\n",
>> +                       reg & PSP_CMDRESP_ERR_MASK);
>> +               tee_free_ring(tee);
>> +               ret = -EIO;
>> +       }
>> +
>> +free_buf:
>> +       tee_free_cmd_buffer(cmd);
>> +
>> +       return ret;
>> +}
>> +
>> +static void tee_destroy_ring(struct psp_tee_device *tee)
>> +{
>> +       unsigned int reg;
>> +       int ret;
>> +
>> +       if (!tee->rb_mgr.ring_start)
>> +               return;
>> +
>> +       if (psp_dead)
>> +               goto free_ring;
>> +
>> +       iowrite32(TEE_RING_DESTROY_CMD,
>> +                 tee->io_regs + tee->vdata->cmdresp_reg);
>> +
>> +       ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
>> +       if (ret) {
>> +               dev_err(tee->dev, "tee: ring destroy command timed out\n");
>> +       } else if (reg & PSP_CMDRESP_ERR_MASK) {
>> +               dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n",
>> +                       reg & PSP_CMDRESP_ERR_MASK);
>> +       }
>> +
>> +free_ring:
>> +       tee_free_ring(tee);
>> +}
>> +
>> +int tee_dev_init(struct psp_device *psp)
>> +{
>> +       struct device *dev = psp->dev;
>> +       struct psp_tee_device *tee;
>> +       int ret;
>> +
>> +       ret = -ENOMEM;
>> +       tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL);
>> +       if (!tee)
>> +               goto e_err;
>> +
>> +       psp->tee_data = tee;
>> +
>> +       tee->dev = dev;
>> +       tee->psp = psp;
>> +
>> +       tee->io_regs = psp->io_regs;
>> +
>> +       tee->vdata = (struct tee_vdata *)psp->vdata->tee;
>> +       if (!tee->vdata) {
>> +               ret = -ENODEV;
>> +               dev_err(dev, "tee: missing driver data\n");
>> +               goto e_err;
>> +       }
>> +
>> +       ret = tee_init_ring(tee);
>> +       if (ret) {
>> +               dev_err(dev, "tee: failed to init ring buffer\n");
>> +               goto e_err;
>> +       }
>> +
>> +       dev_notice(dev, "tee enabled\n");
>> +
>> +       return 0;
>> +
>> +e_err:
>> +       psp->tee_data = NULL;
>> +
>> +       dev_notice(dev, "tee initialization failed\n");
>> +
>> +       return ret;
>> +}
>> +
>> +void tee_dev_destroy(struct psp_device *psp)
>> +{
>> +       struct psp_tee_device *tee = psp->tee_data;
>> +
>> +       if (!tee)
>> +               return;
>> +
>> +       tee_destroy_ring(tee);
>> +}
>> diff --git a/drivers/crypto/ccp/tee-dev.h b/drivers/crypto/ccp/tee-dev.h
>> new file mode 100644
>> index 0000000..0d51a0a7
>> --- /dev/null
>> +++ b/drivers/crypto/ccp/tee-dev.h
>> @@ -0,0 +1,108 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright 2019 Advanced Micro Devices, Inc.
>> + *
>> + * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
>> + *
>> + */
>> +
>> +/* This file describes the TEE communication interface between host and AMD
>> + * Secure Processor
>> + */
>> +
>> +#ifndef __TEE_DEV_H__
>> +#define __TEE_DEV_H__
>> +
>> +#include <linux/device.h>
>> +#include <linux/mutex.h>
>> +
>> +#define TEE_DEFAULT_TIMEOUT            10
>> +#define MAX_BUFFER_SIZE                        992
>> +
>> +/**
>> + * enum tee_ring_cmd_id - TEE interface commands for ring buffer configuration
>> + * @TEE_RING_INIT_CMD:         Initialize ring buffer
>> + * @TEE_RING_DESTROY_CMD:      Destroy ring buffer
>> + * @TEE_RING_MAX_CMD:          Maximum command id
>> + */
>> +enum tee_ring_cmd_id {
>> +       TEE_RING_INIT_CMD               = 0x00010000,
>> +       TEE_RING_DESTROY_CMD            = 0x00020000,
>> +       TEE_RING_MAX_CMD                = 0x000F0000,
>> +};
>> +
>> +/**
>> + * struct tee_init_ring_cmd - Command to init TEE ring buffer
>> + * @low_addr:  bits [31:0] of the physical address of ring buffer
>> + * @hi_addr:   bits [63:32] of the physical address of ring buffer
>> + * @size:      size of ring buffer in bytes
>> + */
>> +struct tee_init_ring_cmd {
>> +       u32 low_addr;
>> +       u32 hi_addr;
>> +       u32 size;
>> +};
>> +
>> +#define MAX_RING_BUFFER_ENTRIES                32
>> +
>> +/**
>> + * struct ring_buf_manager - Helper structure to manage ring buffer.
>> + * @ring_start:  starting address of ring buffer
>> + * @ring_size:   size of ring buffer in bytes
>> + * @ring_pa:     physical address of ring buffer
>> + * @wptr:        index to the last written entry in ring buffer
>> + */
>> +struct ring_buf_manager {
>> +       void *ring_start;
>> +       u32 ring_size;
>> +       phys_addr_t ring_pa;
>> +       u32 wptr;
>> +};
>> +
>> +struct psp_tee_device {
>> +       struct device *dev;
>> +       struct psp_device *psp;
>> +       void __iomem *io_regs;
>> +       struct tee_vdata *vdata;
>> +       struct ring_buf_manager rb_mgr;
>> +};
>> +
>> +/**
>> + * enum tee_cmd_state - TEE command states for the ring buffer interface
>> + * @TEE_CMD_STATE_INIT:      initial state of command when sent from host
>> + * @TEE_CMD_STATE_PROCESS:   command being processed by TEE environment
>> + * @TEE_CMD_STATE_COMPLETED: command processing completed
>> + */
>> +enum tee_cmd_state {
>> +       TEE_CMD_STATE_INIT,
>> +       TEE_CMD_STATE_PROCESS,
>> +       TEE_CMD_STATE_COMPLETED,
>> +};
>> +
>> +/**
>> + * struct tee_ring_cmd - Structure of the command buffer in TEE ring
>> + * @cmd_id:      refers to &enum tee_cmd_id. Command id for the ring buffer
>> + *               interface
>> + * @cmd_state:   refers to &enum tee_cmd_state
>> + * @status:      status of TEE command execution
>> + * @res0:        reserved region
>> + * @pdata:       private data (currently unused)
>> + * @res1:        reserved region
>> + * @buf:         TEE command specific buffer
>> + */
>> +struct tee_ring_cmd {
>> +       u32 cmd_id;
>> +       u32 cmd_state;
>> +       u32 status;
>> +       u32 res0[1];
>> +       u64 pdata;
>> +       u32 res1[2];
>> +       u8 buf[MAX_BUFFER_SIZE];
>> +
>> +       /* Total size: 1024 bytes */
>> +} __packed;
>> +
>> +int tee_dev_init(struct psp_device *psp);
>> +void tee_dev_destroy(struct psp_device *psp);
>> +
>> +#endif /* __TEE_DEV_H__ */
>> --
>> 1.9.1
>>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver
  2019-10-23 16:27 ` [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Lendacky, Thomas
@ 2019-10-24 11:21   ` Thomas, Rijo-john
  0 siblings, 0 replies; 13+ messages in thread
From: Thomas, Rijo-john @ 2019-10-24 11:21 UTC (permalink / raw)
  To: Lendacky, Thomas, Hook, Gary, Herbert Xu, David S . Miller,
	linux-kernel, linux-crypto
  Cc: Singh, Brijesh, Easow, Nimesh, Rangasamy, Devaraj

Hello Tom,

On 23/10/19 9:57 PM, Lendacky, Thomas wrote:
> On 10/23/19 6:27 AM, Thomas, Rijo-john wrote:
>> The goal of this patch series is to introduce TEE (Trusted Execution
>> Environment) interface support to AMD Secure Processor driver. The
>> TEE is a secure area of a processor which ensures that sensitive data
>> is stored, processed and protected in an isolated and trusted
>> environment. The Platform Security Processor (PSP) is a dedicated
>> processor which provides TEE to enable HW platform security. It offers
>> protection against software attacks generated in Rich Operating System
>> (Rich OS) such as Linux running on x86.
>>
>> Based on the platform feature support, the PSP is capable of supporting
>> either SEV (Secure Encrypted Virtualization) and/or TEE. The first three
>> patches in this series is about moving SEV specific functions and data
>> structures from PSP device driver file to a dedicated SEV interface
>> driver file. The last two patches add TEE interface support to AMD
>> Secure Processor driver. This TEE interface will be used by AMD-TEE
>> driver to submit command buffers for processing in PSP Trusted Execution
>> Environment.
> 
> There are some outstanding patches that have been submitted that modify
> some of the same files you are modifying, so you'll need to rebase after
> those patches are applied. Also, one patch was applied through the KVM
> tree, not sure how to handle that.
> 
> For reference, here are the submitted patches:
> 
> https://lore.kernel.org/kvm/6108561e392460ade67f7f70d9bfa9f56a925d0a.1570137447.git.thomas.lendacky@amd.com/
> https://lore.kernel.org/linux-crypto/20191017223459.64281-1-Ashish.Kalra@amd.com/
> https://lore.kernel.org/linux-crypto/157166548259.28287.18118802909801681546.stgit@taos/

I will take a note of this. I will rebase once these patches are merged.

Thanks,
Rijo

> 
> Thanks,
> Tom
> 
>>
>> Rijo Thomas (5):
>>   crypto: ccp - rename psp-dev files to sev-dev
>>   crypto: ccp - create a generic psp-dev file
>>   crypto: ccp - move SEV vdata to a dedicated data structure
>>   crypto: ccp - add TEE support for Raven Ridge
>>   crypto: ccp - provide in-kernel API to submit TEE commands
>>
>>  drivers/crypto/ccp/Makefile  |    4 +-
>>  drivers/crypto/ccp/psp-dev.c |  983 +++------------------------------------
>>  drivers/crypto/ccp/psp-dev.h |   50 +-
>>  drivers/crypto/ccp/sev-dev.c | 1041 ++++++++++++++++++++++++++++++++++++++++++
>>  drivers/crypto/ccp/sev-dev.h |   62 +++
>>  drivers/crypto/ccp/sp-dev.h  |   17 +-
>>  drivers/crypto/ccp/sp-pci.c  |   43 +-
>>  drivers/crypto/ccp/tee-dev.c |  363 +++++++++++++++
>>  drivers/crypto/ccp/tee-dev.h |  109 +++++
>>  include/linux/psp-tee.h      |   72 +++
>>  10 files changed, 1796 insertions(+), 948 deletions(-)
>>  create mode 100644 drivers/crypto/ccp/sev-dev.c
>>  create mode 100644 drivers/crypto/ccp/sev-dev.h
>>  create mode 100644 drivers/crypto/ccp/tee-dev.c
>>  create mode 100644 drivers/crypto/ccp/tee-dev.h
>>  create mode 100644 include/linux/psp-tee.h
>>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH 5/5] crypto: ccp - provide in-kernel API to submit TEE commands
  2019-10-23 11:27 ` [RFC PATCH 5/5] crypto: ccp - provide in-kernel API to submit TEE commands Thomas, Rijo-john
@ 2019-10-25  4:08   ` kbuild test robot
  0 siblings, 0 replies; 13+ messages in thread
From: kbuild test robot @ 2019-10-25  4:08 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 1861 bytes --]

Hi Rijo-john",

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on cryptodev/master]
[cannot apply to v5.4-rc4 next-20191024]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Rijo-john/Add-TEE-interface-support-to-AMD-Secure-Processor-driver/20191025-075941
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=sh 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from <command-line>:0:0:
   include/linux/psp-tee.h: In function 'psp_tee_process_cmd':
>> include/linux/psp-tee.h:69:10: error: 'ENODEV' undeclared (first use in this function)
     return -ENODEV;
             ^~~~~~
   include/linux/psp-tee.h:69:10: note: each undeclared identifier is reported only once for each function it appears in

vim +/ENODEV +69 include/linux/psp-tee.h

    65	
    66	static inline int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf,
    67					      size_t len, u32 *status)
    68	{
  > 69		return -ENODEV;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 52251 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2019-10-25  4:08 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-23 11:27 [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Thomas, Rijo-john
2019-10-23 11:27 ` [RFC PATCH 1/5] crypto: ccp - rename psp-dev files to sev-dev Thomas, Rijo-john
2019-10-23 11:48   ` Ard Biesheuvel
2019-10-24 11:19     ` Thomas, Rijo-john
2019-10-23 11:27 ` [RFC PATCH 2/5] crypto: ccp - create a generic psp-dev file Thomas, Rijo-john
2019-10-23 11:27 ` [RFC PATCH 3/5] crypto: ccp - move SEV vdata to a dedicated data structure Thomas, Rijo-john
2019-10-23 11:27 ` [RFC PATCH 4/5] crypto: ccp - add TEE support for Raven Ridge Thomas, Rijo-john
2019-10-23 11:49   ` Ard Biesheuvel
2019-10-24 11:20     ` Thomas, Rijo-john
2019-10-23 11:27 ` [RFC PATCH 5/5] crypto: ccp - provide in-kernel API to submit TEE commands Thomas, Rijo-john
2019-10-25  4:08   ` kbuild test robot
2019-10-23 16:27 ` [RFC PATCH 0/5] Add TEE interface support to AMD Secure Processor driver Lendacky, Thomas
2019-10-24 11:21   ` Thomas, Rijo-john

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.