Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a6170df authored by Brijesh Singh's avatar Brijesh Singh
Browse files

crypto: ccp: Add Platform Security Processor (PSP) device support



The Platform Security Processor (PSP) is part of the AMD Secure
Processor (AMD-SP) functionality. The PSP is a dedicated processor
that 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.

Note that the key management functionality provided by the SEV firmware
can be used outside of the kvm-amd driver hence it doesn't need to
depend on CONFIG_KVM_AMD.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Gary Hook <gary.hook@amd.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: linux-crypto@vger.kernel.org
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Improvements-by: default avatarBorislav Petkov <bp@suse.de>
Signed-off-by: default avatarBrijesh Singh <brijesh.singh@amd.com>
Reviewed-by: default avatarBorislav Petkov <bp@suse.de>
parent 592d5e74
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -33,3 +33,14 @@ config CRYPTO_DEV_CCP_CRYPTO
	  Support for using the cryptographic API with the AMD Cryptographic
	  Coprocessor. This module supports offload of SHA and AES algorithms.
	  If you choose 'M' here, this module will be called ccp_crypto.

config CRYPTO_DEV_SP_PSP
	bool "Platform Security Processor (PSP) device"
	default y
	depends on CRYPTO_DEV_CCP_DD && X86_64
	help
	 Provide support for the AMD Platform Security Processor (PSP).
	 The PSP is a dedicated processor that 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.
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \
	    ccp-dmaengine.o \
	    ccp-debugfs.o
ccp-$(CONFIG_PCI) += sp-pci.o
ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o

obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
ccp-crypto-objs := ccp-crypto-main.o \
+105 −0
Original line number Diff line number Diff line
/*
 * AMD Platform Security Processor (PSP) interface
 *
 * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
 *
 * Author: Brijesh Singh <brijesh.singh@amd.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#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 "sp-dev.h"
#include "psp-dev.h"

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)
{
	return IRQ_HANDLED;
}

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 + psp->vdata->offset;

	/* Disable and clear interrupts until ready */
	iowrite32(0, psp->io_regs + PSP_P2CMSG_INTEN);
	iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTSTS);

	/* 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;
	}

	if (sp->set_psp_master_device)
		sp->set_psp_master_device(sp);

	/* Enable interrupt */
	iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN);

	return 0;

e_err:
	sp->psp_data = NULL;

	dev_notice(dev, "psp initialization failed\n");

	return ret;
}

void psp_dev_destroy(struct sp_device *sp)
{
	struct psp_device *psp = sp->psp_data;

	sp_free_psp_irq(sp, psp);
}
+59 −0
Original line number Diff line number Diff line
/*
 * AMD Platform Security Processor (PSP) interface driver
 *
 * Copyright (C) 2017 Advanced Micro Devices, Inc.
 *
 * Author: Brijesh Singh <brijesh.singh@amd.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#ifndef __PSP_DEV_H__
#define __PSP_DEV_H__

#include <linux/device.h>
#include <linux/pci.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 "sp-dev.h"

#define PSP_P2CMSG_INTEN		0x0110
#define PSP_P2CMSG_INTSTS		0x0114

#define PSP_C2PMSG_ATTR_0		0x0118
#define PSP_C2PMSG_ATTR_1		0x011c
#define PSP_C2PMSG_ATTR_2		0x0120
#define PSP_C2PMSG_ATTR_3		0x0124
#define PSP_P2CMSG_ATTR_0		0x0128

#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 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;
};

#endif /* __PSP_DEV_H */
+26 −0
Original line number Diff line number Diff line
@@ -198,6 +198,8 @@ int sp_init(struct sp_device *sp)
	if (sp->dev_vdata->ccp_vdata)
		ccp_dev_init(sp);

	if (sp->dev_vdata->psp_vdata)
		psp_dev_init(sp);
	return 0;
}

@@ -206,6 +208,9 @@ void sp_destroy(struct sp_device *sp)
	if (sp->dev_vdata->ccp_vdata)
		ccp_dev_destroy(sp);

	if (sp->dev_vdata->psp_vdata)
		psp_dev_destroy(sp);

	sp_del_device(sp);
}

@@ -237,6 +242,27 @@ int sp_resume(struct sp_device *sp)
}
#endif

struct sp_device *sp_get_psp_master_device(void)
{
	struct sp_device *i, *ret = NULL;
	unsigned long flags;

	write_lock_irqsave(&sp_unit_lock, flags);
	if (list_empty(&sp_units))
		goto unlock;

	list_for_each_entry(i, &sp_units, entry) {
		if (i->psp_data)
			break;
	}

	if (i->get_psp_master_device)
		ret = i->get_psp_master_device();
unlock:
	write_unlock_irqrestore(&sp_unit_lock, flags);
	return ret;
}

static int __init sp_mod_init(void)
{
#ifdef CONFIG_X86
Loading