This part of Secure Encryted Virtualization (SEV) patch series focuses on KVM
changes required to create and manage SEV guests.
SEV is an extension to the AMD-V architecture which supports running encrypted
virtual machine (VMs) under the control of a hypervisor. Encrypted VMs have their
pages (code and data) secured such that only the guest itself has access to
unencrypted version. Each encrypted VM is associated with a unique encryption key;
if its data is accessed to a different entity using a different key the encrypted
guest's data will be incorrectly decrypted, leading to unintelligible data.
This security model ensures that hypervisor will no longer able to inspect or
alter any guest code or data.
The key management of this feature is handled by a separate processor known as
the AMD Secure Processor (AMD-SP) which is present on AMD SOCs. The SEV Key
Management Specification (see below) provides a set of commands which can be
used by hypervisor to load virtual machine keys through the AMD-SP driver.
The patch series adds a new ioctl in KVM driver (KVM_MEMORY_ENCRYPTION_OP). The
ioctl will be used by qemu to issue SEV guest-specific commands defined in Key
Management Specification.
The following links provide additional details:
AMD Memory Encryption whitepaper:
http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
AMD64 Architecture Programmer's Manual:
http://support.amd.com/TechDocs/24593.pdf
SME is section 7.10
SEV is section 15.34
Secure Encrypted Virutualization Key Management:
http://support.amd.com/TechDocs/55766_SEV-KM API_Specification.pdf
KVM Forum Presentation:
http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
SEV Guest BIOS support:
SEV support has been interated into EDKII/OVMF BIOS
https://github.com/tianocore/edk2
SEV Part 1 patch series: https://marc.info/?l=linux-kernel&m=150556529528089&w=2
--
The series is based on kvm/master commit : 5753743fa510 (KVM: VMX: remove WARN_ON_ONCE in kvm_vcpu_trigger_posted_interrupt)
TODO:
* Add SEV guest migration command support
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: "Radim Krčmář" <[email protected]>
Cc: Joerg Roedel <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Changes since v3:
* Re-design the PSP interface support patch
* Rename the ioctls based on the feedbacks
* Improve documentation
* Fix i386 build issues
* Add LAUNCH_SECRET command
* Add new Kconfig option to enable SEV support
* Changes to address v3 feedbacks.
Changes since v2:
* Add KVM_MEMORY_ENCRYPT_REGISTER/UNREGISTER_RAM ioct to register encrypted
memory ranges (recommend by Paolo)
* Extend kvm_x86_ops to provide new memory_encryption_enabled ops
* Enhance DEBUG DECRYPT/ENCRYPT commands to work with more than one page \
(recommended by Paolo)
* Optimize LAUNCH_UPDATE command to reduce the number of calls to AMD-SP driver
* Changes to address v2 feedbacks
Brijesh Singh (26):
Documentation/virtual/kvm: Add AMD Secure Encrypted Virtualization
(SEV)
crypto: ccp: Add Platform Security Processor (PSP) device support
ccp: crypto: Define SEV key management command id
crypto: ccp: Add Secure Encrypted Virtualization (SEV) command support
KVM: SVM: Prepare to reserve asid for SEV guest
KVM: SVM: Reserve ASID range for SEV guest
KVM: X86: Extend CPUID range to include new leaf
KVM: Introduce KVM_MEMORY_ENCRYPT_OP ioctl
KVM: Introduce KVM_MEMORY_ENCRYPT_REGISTER_REGION ioctl
KVM: Define SEV key management command id
KVM: SVM: Add KVM_SEV_INIT command
KVM: SVM: VMRUN should use assosiated ASID when SEV is enabled
KVM: SVM: Add support for SEV LAUNCH_START command
KVM: SVM: Add support for SEV LAUNCH_UPDATE_DATA command
KVM: SVM: Add support for SEV LAUNCH_MEASURE command
KVM: SVM: Add support for SEV LAUNCH_FINISH command
KVM: svm: Add support for SEV GUEST_STATUS command
KVM: SVM: Add support for SEV DEBUG_DECRYPT command
KVM: SVM: Add support for SEV DEBUG_ENCRYPT command
KVM: SVM: Add support for SEV LAUNCH_SECRET command
KVM: SVM: Pin guest memory when SEV is active
KVM: X86: Add memory encryption enabled ops
KVM: SVM: Clear C-bit from the page fault address
KVM: SVM: Do not install #UD intercept when SEV is enabled
KVM: X86: Restart the guest when insn_len is zero and SEV is enabled
KVM: X86: Add CONFIG_KVM_AMD_SEV
Tom Lendacky (3):
x86/CPU/AMD: Add the Secure Encrypted Virtualization CPU feature
kvm: svm: prepare for new bit definition in nested_ctl
kvm: svm: Add SEV feature definitions to KVM
Documentation/virtual/kvm/00-INDEX | 3 +
.../virtual/kvm/amd-memory-encryption.txt | 210 ++++
Documentation/virtual/kvm/api.txt | 37 +
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/kvm_host.h | 16 +
arch/x86/include/asm/msr-index.h | 2 +
arch/x86/include/asm/svm.h | 3 +
arch/x86/kernel/cpu/amd.c | 66 +-
arch/x86/kernel/cpu/scattered.c | 1 +
arch/x86/kvm/Kconfig | 8 +
arch/x86/kvm/cpuid.c | 2 +-
arch/x86/kvm/mmu.c | 17 +
arch/x86/kvm/svm.c | 1265 +++++++++++++++++++-
arch/x86/kvm/x86.c | 48 +
drivers/crypto/ccp/Kconfig | 11 +
drivers/crypto/ccp/Makefile | 1 +
drivers/crypto/ccp/psp-dev.c | 852 +++++++++++++
drivers/crypto/ccp/psp-dev.h | 78 ++
drivers/crypto/ccp/sp-dev.c | 32 +
drivers/crypto/ccp/sp-dev.h | 27 +-
drivers/crypto/ccp/sp-pci.c | 46 +
include/linux/psp-sev.h | 683 +++++++++++
include/uapi/linux/kvm.h | 152 +++
include/uapi/linux/psp-sev.h | 114 ++
24 files changed, 3646 insertions(+), 29 deletions(-)
create mode 100644 Documentation/virtual/kvm/amd-memory-encryption.txt
create mode 100644 drivers/crypto/ccp/psp-dev.c
create mode 100644 drivers/crypto/ccp/psp-dev.h
create mode 100644 include/linux/psp-sev.h
create mode 100644 include/uapi/linux/psp-sev.h
--
2.9.5
AMDs new Secure Encrypted Virtualization (SEV) feature allows the memory
contents of a virtual machines to be transparently encrypted with a key
unique to the guest VM. The programming and management of the encryption
keys are handled by the AMD Secure Processor (AMD-SP), which exposes the
commands for these tasks. The complete spec is available at:
http://support.amd.com/TechDocs/55766_SEV-KM%20API_Specification.pdf
Extend the AMD-SP driver to provide the following support:
- an in-kernel APIs to communicate with a SEV firmware. The APIs can be
used by the hypervisor to create encryption context for the SEV guests.
- an userspace IOCTL to manage the platform certificates
Cc: Paolo Bonzini <[email protected]>
Cc: "Radim Krčmář" <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Brijesh Singh <[email protected]>
---
drivers/crypto/ccp/psp-dev.c | 743 ++++++++++++++++++++++++++++++++++++++++++-
drivers/crypto/ccp/psp-dev.h | 17 +
include/linux/psp-sev.h | 171 ++++++++++
include/uapi/linux/psp-sev.h | 114 +++++++
4 files changed, 1044 insertions(+), 1 deletion(-)
create mode 100644 include/uapi/linux/psp-sev.h
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
index e60e53272e71..c74e383666f8 100644
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -23,9 +23,20 @@
#include <linux/hw_random.h>
#include <linux/ccp.h>
+#include <uapi/linux/psp-sev.h>
+
#include "sp-dev.h"
#include "psp-dev.h"
+#define DEVICE_NAME "sev"
+
+static unsigned int sev_poll;
+module_param(sev_poll, uint, 0444);
+MODULE_PARM_DESC(sev_poll, "Poll for sev command completion - any non-zero value");
+
+DEFINE_MUTEX(sev_cmd_mutex);
+static bool sev_fops_registered;
+
const struct psp_vdata psp_entry = {
.offset = 0x10500,
};
@@ -49,9 +60,732 @@ static struct psp_device *psp_alloc_struct(struct sp_device *sp)
irqreturn_t psp_irq_handler(int irq, void *data)
{
+ unsigned int status;
+ struct psp_device *psp = data;
+
+ /* read the interrupt status */
+ status = ioread32(psp->io_regs + PSP_P2CMSG_INTSTS);
+
+ /* check if its command completion */
+ if (status & (1 << PSP_CMD_COMPLETE_REG)) {
+ int reg;
+
+ /* check if its SEV command completion */
+ reg = ioread32(psp->io_regs + PSP_CMDRESP);
+ if (reg & PSP_CMDRESP_RESP) {
+ psp->sev_int_rcvd = 1;
+ wake_up(&psp->sev_int_queue);
+ }
+ }
+
+ /* clear the interrupt status by writing 1 */
+ iowrite32(status, psp->io_regs + PSP_P2CMSG_INTSTS);
+
return IRQ_HANDLED;
}
+static struct psp_device *psp_get_master_device(void)
+{
+ struct sp_device *sp = sp_get_psp_master_device();
+
+ return sp ? sp->psp_data : NULL;
+}
+
+static int sev_wait_cmd_poll(struct psp_device *psp, unsigned int timeout,
+ unsigned int *reg)
+{
+ int wait = timeout * 10; /* 100ms sleep => timeout * 10 */
+
+ while (--wait) {
+ msleep(100);
+
+ *reg = ioread32(psp->io_regs + PSP_CMDRESP);
+ if (*reg & PSP_CMDRESP_RESP)
+ break;
+ }
+
+ if (!wait) {
+ dev_err(psp->dev, "sev command timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int sev_wait_cmd_ioc(struct psp_device *psp, unsigned int *reg)
+{
+ psp->sev_int_rcvd = 0;
+
+ wait_event(psp->sev_int_queue, psp->sev_int_rcvd);
+ *reg = ioread32(psp->io_regs + PSP_CMDRESP);
+
+ return 0;
+}
+
+static int sev_wait_cmd(struct psp_device *psp, unsigned int *reg)
+{
+ return (*reg & PSP_CMDRESP_IOC) ? sev_wait_cmd_ioc(psp, reg)
+ : sev_wait_cmd_poll(psp, 10, reg);
+}
+
+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_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_UPDATE_SECRET:
+ return sizeof(struct sev_data_launch_secret);
+ 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:
+ 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_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_RECEIVE_FINISH:
+ return sizeof(struct sev_data_receive_finish);
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int sev_handle_cmd(int cmd, void *data, int *psp_ret)
+{
+ struct psp_device *psp = psp_get_master_device();
+ unsigned int phys_lsb, phys_msb;
+ unsigned int reg, ret;
+
+ if (!psp)
+ return -ENODEV;
+
+ /* Set the physical address for the PSP */
+ 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\n",
+ cmd, phys_msb, phys_lsb);
+ print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data,
+ sev_cmd_buffer_len(cmd), false);
+
+ /* Only one command at a time... */
+ mutex_lock(&sev_cmd_mutex);
+
+ iowrite32(phys_lsb, psp->io_regs + PSP_CMDBUFF_ADDR_LO);
+ iowrite32(phys_msb, psp->io_regs + PSP_CMDBUFF_ADDR_HI);
+
+ reg = cmd;
+ reg <<= PSP_CMDRESP_CMD_SHIFT;
+ reg |= sev_poll ? 0 : PSP_CMDRESP_IOC;
+ iowrite32(reg, psp->io_regs + PSP_CMDRESP);
+
+ ret = sev_wait_cmd(psp, ®);
+ if (ret)
+ goto unlock;
+
+ 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;
+ }
+
+unlock:
+ mutex_unlock(&sev_cmd_mutex);
+ print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data,
+ sev_cmd_buffer_len(cmd), false);
+ return ret;
+}
+
+static int sev_platform_get_state(int *state, int *error)
+{
+ struct sev_data_status *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = sev_handle_cmd(SEV_CMD_PLATFORM_STATUS, data, error);
+ if (!ret)
+ *state = data->state;
+
+ kfree(data);
+ return ret;
+}
+
+static int sev_firmware_init(int *error)
+{
+ struct sev_data_init *data;
+ int rc;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ rc = sev_handle_cmd(SEV_CMD_INIT, data, error);
+
+ kfree(data);
+ return rc;
+}
+
+static inline int sev_ioctl_factory_reset(struct sev_issue_cmd *argp)
+{
+ return sev_handle_cmd(SEV_CMD_FACTORY_RESET, 0, &argp->error);
+}
+
+static int sev_ioctl_platform_status(struct sev_issue_cmd *argp)
+{
+ struct sev_data_status *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = sev_handle_cmd(SEV_CMD_PLATFORM_STATUS, data, &argp->error);
+ if (ret)
+ goto e_free;
+
+ if (copy_to_user((void __user *)(uintptr_t) argp->data,
+ data, sizeof(*data))) {
+ ret = -EFAULT;
+ goto e_free;
+ }
+e_free:
+ kfree(data);
+ return ret;
+}
+
+static void *copy_user_blob(u64 __user uaddr, u32 len)
+{
+ void *data;
+
+ 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);
+
+ data = kmalloc(len, GFP_KERNEL);
+ if (IS_ERR(data))
+ return ERR_PTR(-ENOMEM);
+
+ if (copy_from_user(data, (void __user *)(uintptr_t)uaddr, len))
+ goto e_free;
+
+ return data;
+e_free:
+ kfree(data);
+ return ERR_PTR(-EFAULT);
+}
+
+static int sev_ioctl_pek_csr(struct sev_issue_cmd *argp)
+{
+ struct sev_user_data_pek_csr input;
+ struct sev_data_pek_csr *data;
+ int do_shutdown = 0;
+ int ret, state;
+ void *blob;
+
+ if (copy_from_user(&input, (void __user *)(uintptr_t)argp->data,
+ sizeof(struct sev_user_data_pek_csr)))
+ return -EFAULT;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+
+ /* copy the PEK certificate blob from userspace */
+ blob = NULL;
+ if (input.address) {
+ blob = copy_user_blob(input.address, input.length);
+ if (IS_ERR(blob)) {
+ ret = PTR_ERR(blob);
+ goto e_free;
+ }
+
+ data->address = __psp_pa(blob);
+ data->len = input.length;
+ }
+
+ ret = sev_platform_get_state(&state, &argp->error);
+ if (ret)
+ goto e_free_blob;
+
+ /*
+ * PEK_CERT command can be issued only when we are in INIT state.
+ * if current state is WORKING then reject it, if state is UNINIT
+ * then transition the platform to INIT state before issuing the
+ * command.
+ */
+ if (state == SEV_STATE_WORKING) {
+ ret = -EBUSY;
+ goto e_free_blob;
+ } else if (state == SEV_STATE_UNINIT) {
+ ret = sev_firmware_init(&argp->error);
+ if (ret)
+ goto e_free_blob;
+ do_shutdown = 1;
+ }
+
+ ret = sev_handle_cmd(SEV_CMD_PEK_CSR, data, &argp->error);
+
+ input.length = data->len;
+
+ if (copy_to_user((void __user *)(uintptr_t)argp->data, &input,
+ sizeof(struct sev_user_data_pek_csr)))
+ ret = -EFAULT;
+
+ /* transition the plaform into INIT state */
+ if (do_shutdown)
+ sev_handle_cmd(SEV_CMD_SHUTDOWN, 0, NULL);
+
+e_free_blob:
+ kfree(blob);
+e_free:
+ kfree(data);
+ return ret;
+}
+
+static int sev_ioctl_pdh_gen(struct sev_issue_cmd *argp)
+{
+ int ret, state, do_shutdown = 0;
+
+ /*
+ * PDH_GEN command can be issued when platform is in INIT or WORKING
+ * state. If we are in UNINIT state then transition into INIT state
+ * before issuing the command.
+ */
+ ret = sev_platform_get_state(&state, &argp->error);
+ if (ret)
+ return ret;
+
+ if (state == SEV_STATE_UNINIT) {
+ /* transition the plaform into INIT state */
+ ret = sev_firmware_init(&argp->error);
+ if (ret)
+ return ret;
+ do_shutdown = 1;
+ }
+
+ ret = sev_handle_cmd(SEV_CMD_PDH_GEN, 0, &argp->error);
+
+ if (do_shutdown)
+ sev_handle_cmd(SEV_CMD_SHUTDOWN, 0, NULL);
+
+ return ret;
+}
+
+static int sev_ioctl_pek_gen(struct sev_issue_cmd *argp)
+{
+ int do_shutdown = 0;
+ int ret, state;
+
+ /*
+ * PEK_GEN command can be issued only when firmware is in INIT state.
+ * If firmware is in UNINIT state then we transition it into INIT state
+ * and issue the command.
+ */
+ ret = sev_platform_get_state(&state, &argp->error);
+ if (ret)
+ return ret;
+
+ if (state == SEV_STATE_WORKING) {
+ return -EBUSY;
+ } else if (state == SEV_STATE_UNINIT) {
+ /* transition the plaform into INIT state */
+ ret = sev_firmware_init(&argp->error);
+ if (ret)
+ return ret;
+
+ do_shutdown = 1;
+ }
+
+ ret = sev_handle_cmd(SEV_CMD_PEK_GEN, 0, &argp->error);
+
+ if (do_shutdown)
+ sev_handle_cmd(SEV_CMD_SHUTDOWN, 0, NULL);
+
+ return ret;
+}
+
+static int sev_ioctl_pek_cert_import(struct sev_issue_cmd *argp)
+{
+ struct sev_user_data_pek_cert_import input;
+ struct sev_data_pek_cert_import *data;
+ int ret, state, do_shutdown = 0;
+ void *pek_blob, *oca_blob;
+
+ if (copy_from_user(&input, (void __user *)(uintptr_t) argp->data,
+ sizeof(struct sev_user_data_pek_cert_import)))
+ return -EFAULT;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* copy PEK certificate blobs from userspace */
+ pek_blob = 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 = 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;
+
+ ret = sev_platform_get_state(&state, &argp->error);
+ if (ret)
+ goto e_free_oca;
+
+ /*
+ * PEK_CERT_IMPORT command can be issued only when platform is in INIT
+ * state. If we are in UNINIT state then transition into INIT state
+ * before issuing the command.
+ */
+ if (state == SEV_STATE_WORKING) {
+ ret = -EBUSY;
+ goto e_free_oca;
+ } else if (state == SEV_STATE_UNINIT) {
+ /* transition platform init INIT state */
+ ret = sev_firmware_init(&argp->error);
+ if (ret)
+ goto e_free_oca;
+ do_shutdown = 1;
+ }
+
+ ret = sev_handle_cmd(SEV_CMD_PEK_CERT_IMPORT, data, &argp->error);
+
+ if (do_shutdown)
+ sev_handle_cmd(SEV_CMD_SHUTDOWN, 0, NULL);
+e_free_oca:
+ kfree(oca_blob);
+e_free_pek:
+ kfree(pek_blob);
+e_free:
+ kfree(data);
+ return ret;
+}
+
+static int sev_ioctl_pdh_cert_export(struct sev_issue_cmd *argp)
+{
+ struct sev_user_data_pdh_cert_export input;
+ struct sev_data_pdh_cert_export *data;
+ int ret, state, need_shutdown = 0;
+ void *pdh_blob, *cert_blob;
+
+ if (copy_from_user(&input, (void __user *)(uintptr_t)argp->data,
+ sizeof(struct sev_user_data_pdh_cert_export)))
+ return -EFAULT;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ pdh_blob = NULL;
+ if (input.pdh_cert_address) {
+ if (input.pdh_cert_len > SEV_FW_BLOB_MAX_SIZE) {
+ ret = -EINVAL;
+ 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 = NULL;
+ if (input.cert_chain_address) {
+ if (input.cert_chain_len > SEV_FW_BLOB_MAX_SIZE) {
+ ret = -EINVAL;
+ goto e_free_pdh;
+ }
+
+ 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;
+ }
+
+ ret = sev_platform_get_state(&state, &argp->error);
+ if (ret)
+ goto e_free_cert;
+
+ /*
+ * CERT_EXPORT command can be issued in INIT or WORKING state.
+ * If we are in UNINIT state then transition into INIT state and
+ * shutdown before exiting. But if platform is in WORKING state
+ * then EXPORT the certificate but do not shutdown the platform.
+ */
+ if (state == SEV_STATE_UNINIT) {
+ ret = sev_firmware_init(&argp->error);
+ if (ret)
+ goto e_free_cert;
+
+ need_shutdown = 1;
+ }
+
+ ret = sev_handle_cmd(SEV_CMD_PDH_CERT_EXPORT, data, &argp->error);
+
+ input.cert_chain_len = data->cert_chain_len;
+ input.pdh_cert_len = data->pdh_cert_len;
+
+ /* copy certificate length to userspace */
+ if (copy_to_user((void __user *)(uintptr_t)argp->data, &input,
+ sizeof(struct sev_user_data_pdh_cert_export)))
+ ret = -EFAULT;
+
+ if (ret)
+ goto e_shutdown;
+
+ /* copy PDH certificate to userspace */
+ if (pdh_blob &&
+ copy_to_user((void __user *)(uintptr_t)input.pdh_cert_address,
+ pdh_blob, input.pdh_cert_len)) {
+ ret = -EFAULT;
+ goto e_shutdown;
+ }
+
+ /* copy certificate chain to userspace */
+ if (cert_blob &&
+ copy_to_user((void __user *)(uintptr_t)input.cert_chain_address,
+ cert_blob, input.cert_chain_len)) {
+ ret = -EFAULT;
+ goto e_shutdown;
+ }
+
+e_shutdown:
+ if (need_shutdown)
+ sev_handle_cmd(SEV_CMD_SHUTDOWN, 0, NULL);
+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 (ioctl != SEV_ISSUE_CMD)
+ return -EINVAL;
+
+ if (copy_from_user(&input, argp, sizeof(struct sev_issue_cmd)))
+ return -EFAULT;
+
+ if (input.cmd > SEV_CMD_MAX)
+ return -EINVAL;
+
+ switch (input.cmd) {
+
+ case SEV_USER_CMD_FACTORY_RESET: {
+ ret = sev_ioctl_factory_reset(&input);
+ break;
+ }
+ case SEV_USER_CMD_PLATFORM_STATUS: {
+ ret = sev_ioctl_platform_status(&input);
+ break;
+ }
+ case SEV_USER_CMD_PEK_GEN: {
+ ret = sev_ioctl_pek_gen(&input);
+ break;
+ }
+ case SEV_USER_CMD_PDH_GEN: {
+ ret = sev_ioctl_pdh_gen(&input);
+ break;
+ }
+ case SEV_USER_CMD_PEK_CSR: {
+ ret = sev_ioctl_pek_csr(&input);
+ break;
+ }
+ case SEV_USER_CMD_PEK_CERT_IMPORT: {
+ ret = sev_ioctl_pek_cert_import(&input);
+ break;
+ }
+ case SEV_USER_CMD_PDH_CERT_EXPORT: {
+ ret = sev_ioctl_pdh_cert_export(&input);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+
+const struct file_operations sev_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = sev_ioctl,
+};
+
+int sev_platform_init(struct sev_data_init *data, int *error)
+{
+ return sev_handle_cmd(SEV_CMD_INIT, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_platform_init);
+
+int sev_platform_shutdown(int *error)
+{
+ return sev_handle_cmd(SEV_CMD_SHUTDOWN, 0, error);
+}
+EXPORT_SYMBOL_GPL(sev_platform_shutdown);
+
+int sev_platform_status(struct sev_data_status *data, int *error)
+{
+ return sev_handle_cmd(SEV_CMD_PLATFORM_STATUS, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_platform_status);
+
+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_handle_cmd(cmd, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
+
+int sev_guest_deactivate(struct sev_data_deactivate *data, int *error)
+{
+ return sev_handle_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_handle_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_handle_cmd(SEV_CMD_DECOMMISSION, data, error);
+}
+EXPORT_SYMBOL_GPL(sev_guest_decommission);
+
+int sev_guest_df_flush(int *error)
+{
+ return sev_handle_cmd(SEV_CMD_DF_FLUSH, 0, error);
+}
+EXPORT_SYMBOL_GPL(sev_guest_df_flush);
+
+static int sev_ops_init(struct psp_device *psp)
+{
+ int ret = 0;
+ struct miscdevice *misc = &psp->sev_misc;
+
+ /*
+ * SEV feature support can be detected on the multiple devices but the
+ * SEV FW commands must be issued on the master. During probe time we
+ * do not know the master hence we create /dev/sev on the first device
+ * probe. sev_handle_cmd() finds the right master device to send the
+ * command.
+ */
+ if (!sev_fops_registered) {
+ misc->minor = MISC_DYNAMIC_MINOR;
+ misc->name = DEVICE_NAME;
+ misc->fops = &sev_fops;
+
+ ret = misc_register(misc);
+ if (!ret) {
+ sev_fops_registered = true;
+ psp->has_sev_fops = true;
+ init_waitqueue_head(&psp->sev_int_queue);
+ }
+ }
+
+ return ret;
+}
+
+static int sev_init(struct psp_device *psp)
+{
+ /* Check if device supports SEV feature */
+ if (!(ioread32(psp->io_regs + PSP_FEATURE_REG) & 1)) {
+ dev_dbg(psp->dev, "device does not support SEV\n");
+ return 1;
+ }
+
+ return sev_ops_init(psp);
+}
+
+static void sev_exit(struct psp_device *psp)
+{
+ if (psp->has_sev_fops)
+ misc_deregister(&psp->sev_misc);
+}
+
int psp_dev_init(struct sp_device *sp)
{
struct device *dev = sp->dev;
@@ -87,14 +821,20 @@ int psp_dev_init(struct sp_device *sp)
sp_set_psp_master(sp);
+ ret = sev_init(psp);
+ if (ret)
+ goto e_irq;
+
/* Enable interrupt */
dev_dbg(dev, "Enabling interrupts ...\n");
- iowrite32(7, psp->io_regs + PSP_P2CMSG_INTEN);
+ iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN);
dev_notice(dev, "psp enabled\n");
return 0;
+e_irq:
+ sp_free_psp_irq(psp->sp, psp);
e_err:
sp->psp_data = NULL;
@@ -107,5 +847,6 @@ void psp_dev_destroy(struct sp_device *sp)
{
struct psp_device *psp = sp->psp_data;
+ sev_exit(psp);
sp_free_psp_irq(sp, psp);
}
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
index d53970ef5960..51d3cd966eed 100644
--- a/drivers/crypto/ccp/psp-dev.h
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -25,9 +25,21 @@
#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_C2PMSG(_num) ((_num) << 2)
+#define PSP_CMDRESP PSP_C2PMSG(32)
+#define PSP_CMDBUFF_ADDR_LO PSP_C2PMSG(56)
+#define PSP_CMDBUFF_ADDR_HI PSP_C2PMSG(57)
+#define PSP_FEATURE_REG PSP_C2PMSG(63)
+
+#define PSP_P2CMSG(_num) (_num << 2)
+#define PSP_CMD_COMPLETE_REG 1
+#define PSP_CMD_COMPLETE PSP_P2CMSG(PSP_CMD_COMPLETE_REG)
+
#define PSP_P2CMSG_INTEN 0x0110
#define PSP_P2CMSG_INTSTS 0x0114
@@ -54,6 +66,11 @@ struct psp_device {
struct sp_device *sp;
void __iomem *io_regs;
+
+ unsigned int sev_int_rcvd;
+ wait_queue_head_t sev_int_queue;
+ bool has_sev_fops;
+ struct miscdevice sev_misc;
};
extern const struct psp_vdata psp_entry;
diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h
index d40709b65b18..70ba2dcdba04 100644
--- a/include/linux/psp-sev.h
+++ b/include/linux/psp-sev.h
@@ -509,4 +509,175 @@ struct __attribute__((__packed__)) sev_data_dbg {
u32 len; /* In */
};
+#if defined(CONFIG_CRYPTO_DEV_SP_PSP)
+
+/**
+ * sev_platform_init - perform SEV INIT command
+ *
+ * @init: sev_data_init structure to be processed
+ * @error: SEV command return code
+ *
+ * Returns:
+ * 0 if the SEV successfully processed the command
+ * -%ENODEV if the SEV device is not available
+ * -%ENOTSUPP if the SEV does not support SEV
+ * -%ETIMEDOUT if the SEV command timed out
+ * -%EIO if the SEV returned a non-zero return code
+ */
+int sev_platform_init(struct sev_data_init *init, int *error);
+
+/**
+ * sev_platform_shutdown - perform SEV SHUTDOWN command
+ *
+ * @error: SEV command return code
+ *
+ * Returns:
+ * 0 if the SEV successfully processed the command
+ * -%ENODEV if the SEV device is not available
+ * -%ENOTSUPP if the SEV does not support SEV
+ * -%ETIMEDOUT if the SEV command timed out
+ * -%EIO if the SEV returned a non-zero return code
+ */
+int sev_platform_shutdown(int *error);
+
+/**
+ * sev_platform_status - perform SEV PLATFORM_STATUS command
+ *
+ * @init: sev_data_status structure to be processed
+ * @error: SEV command return code
+ *
+ * Returns:
+ * 0 if the SEV successfully processed the command
+ * -%ENODEV if the SEV device is not available
+ * -%ENOTSUPP if the SEV does not support SEV
+ * -%ETIMEDOUT if the SEV command timed out
+ * -%EIO if the SEV returned a non-zero return code
+ */
+int sev_platform_status(struct sev_data_status *status, int *error);
+/**
+ * sev_issue_cmd_external_user - issue SEV command by other driver with a file handle.
+ *
+ * The function can be used by other drivers to issue a SEV command on
+ * behalf by userspace. The caller must pass a valid SEV file descriptor
+ * so that we know that caller has access to SEV device.
+ *
+ * @filep - SEV device file pointer
+ * @cmd - command to issue
+ * @data - command buffer
+ * @error: SEV command return code
+ *
+ * Returns:
+ * 0 if the SEV successfully processed the command
+ * -%ENODEV if the SEV device is not available
+ * -%ENOTSUPP if the SEV does not support SEV
+ * -%ETIMEDOUT if the SEV command timed out
+ * -%EIO if the SEV returned a non-zero return code
+ * -%EINVAL if the SEV file descriptor is not valid
+ */
+int sev_issue_cmd_external_user(struct file *filep, unsigned int id,
+ void *data, int *error);
+
+/**
+ * sev_guest_deactivate - perform SEV DEACTIVATE command
+ *
+ * @deactivate: sev_data_deactivate structure to be processed
+ * @sev_ret: sev command return code
+ *
+ * Returns:
+ * 0 if the sev successfully processed the command
+ * -%ENODEV if the sev device is not available
+ * -%ENOTSUPP if the sev does not support SEV
+ * -%ETIMEDOUT if the sev command timed out
+ * -%EIO if the sev returned a non-zero return code
+ */
+int sev_guest_deactivate(struct sev_data_deactivate *data, int *error);
+
+/**
+ * sev_guest_activate - perform SEV ACTIVATE command
+ *
+ * @activate: sev_data_activate structure to be processed
+ * @sev_ret: sev command return code
+ *
+ * Returns:
+ * 0 if the sev successfully processed the command
+ * -%ENODEV if the sev device is not available
+ * -%ENOTSUPP if the sev does not support SEV
+ * -%ETIMEDOUT if the sev command timed out
+ * -%EIO if the sev returned a non-zero return code
+ */
+int sev_guest_activate(struct sev_data_activate *data, int *error);
+
+/**
+ * sev_guest_df_flush - perform SEV DF_FLUSH command
+ *
+ * @sev_ret: sev command return code
+ *
+ * Returns:
+ * 0 if the sev successfully processed the command
+ * -%ENODEV if the sev device is not available
+ * -%ENOTSUPP if the sev does not support SEV
+ * -%ETIMEDOUT if the sev command timed out
+ * -%EIO if the sev returned a non-zero return code
+ */
+int sev_guest_df_flush(int *error);
+
+/**
+ * sev_guest_decommission - perform SEV DECOMMISSION command
+ *
+ * @decommission: sev_data_decommission structure to be processed
+ * @sev_ret: sev command return code
+ *
+ * Returns:
+ * 0 if the sev successfully processed the command
+ * -%ENODEV if the sev device is not available
+ * -%ENOTSUPP if the sev does not support SEV
+ * -%ETIMEDOUT if the sev command timed out
+ * -%EIO if the sev returned a non-zero return code
+ */
+int sev_guest_decommission(struct sev_data_decommission *data, int *error);
+
+#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
+
+static inline int sev_platform_status(struct sev_data_status *status,
+ int *error)
+{
+ return -ENODEV;
+}
+
+static inline int sev_platform_init(struct sev_data_init *init, int *error)
+{
+ return -ENODEV;
+}
+
+static inline int sev_platform_shutdown(int *error) { return -ENODEV; }
+
+
+static inline int sev_issue_cmd_external_user(int fd, unsigned int id,
+ void *data, int *error)
+{
+ return -ENODEV;
+}
+
+static inline int sev_guest_deactivate(struct sev_data_deactivate *data,
+ int *error)
+{
+ return -ENODEV;
+}
+
+static inline int sev_guest_decommission(struct sev_data_decommission *data,
+ int *error)
+{
+ return -ENODEV;
+}
+
+static inline int sev_guest_activate(struct sev_data_activate *data,
+ int *error)
+{
+ return -ENODEV;
+}
+
+static inline int sev_guest_df_flush(int *error) { return -ENODEV; }
+
+#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
+
#endif /* __PSP_SEV_H__ */
diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h
new file mode 100644
index 000000000000..885d9940786a
--- /dev/null
+++ b/include/uapi/linux/psp-sev.h
@@ -0,0 +1,114 @@
+
+/*
+ * Userspace interface for AMD Secure Encrypted Virtualization (SEV)
+ *
+ * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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_SEV_USER_H__
+#define __PSP_SEV_USER_H__
+
+#include <linux/types.h>
+
+/**
+ * SEV platform commands
+ */
+enum {
+ SEV_USER_CMD_FACTORY_RESET = 0,
+ SEV_USER_CMD_PLATFORM_STATUS,
+ SEV_USER_CMD_PEK_GEN,
+ SEV_USER_CMD_PEK_CSR,
+ SEV_USER_CMD_PDH_GEN,
+ SEV_USER_CMD_PDH_CERT_EXPORT,
+ SEV_USER_CMD_PEK_CERT_IMPORT,
+
+ SEV_USER_CMD_MAX,
+};
+
+/**
+ * struct sev_user_data_status - PLATFORM_STATUS command parameters
+ *
+ * @major: major API version
+ * @minor: minor API version
+ * @state: platform state
+ * @owner: self-owned or externally owned
+ * @config: platform config flags
+ * @build: firmware build id for API version
+ * @guest_count: number of active guests
+ */
+struct sev_user_data_status {
+ __u8 api_major; /* Out */
+ __u8 api_minor; /* Out */
+ __u8 state; /* Out */
+ __u8 owner : 1; /* Out */
+ __u8 reserved1 : 7;
+ __u32 config : 1; /* Out */
+ __u32 reserved2 : 23;
+ __u32 build : 8; /* Out */
+ __u32 guest_count; /* Out */
+} __attribute__ ((__packed__));
+
+/**
+ * struct sev_user_data_pek_csr - PEK_CSR command parameters
+ *
+ * @address: PEK certificate chain
+ * @length: length of certificate
+ */
+struct sev_user_data_pek_csr {
+ __u64 address; /* In */
+ __u32 length; /* In/Out */
+};
+
+/**
+ * struct sev_user_data_cert_import - PEK_CERT_IMPORT command parameters
+ *
+ * @pek_address: PEK certificate chain
+ * @pek_len: length of PEK certificate
+ * @oca_address: OCA certificate chain
+ * @oca_len: length of OCA certificate
+ */
+struct sev_user_data_pek_cert_import {
+ __u64 pek_cert_address; /* In */
+ __u32 pek_cert_len; /* In */
+ __u64 oca_cert_address; /* In */
+ __u32 oca_cert_len; /* In */
+};
+
+/**
+ * struct sev_user_data_pdh_cert_export - PDH_CERT_EXPORT command parameters
+ *
+ * @pdh_address: PDH certificate address
+ * @pdh_len: length of PDH certificate
+ * @cert_chain_address: PDH certificate chain
+ * @cert_chain_len: length of PDH certificate chain
+ */
+struct sev_user_data_pdh_cert_export {
+ __u64 pdh_cert_address; /* In */
+ __u32 pdh_cert_len; /* In/Out */
+ __u64 cert_chain_address; /* In */
+ __u32 cert_chain_len; /* In/Out */
+};
+
+/**
+ * struct sev_issue_cmd - SEV ioctl parameters
+ *
+ * @cmd: SEV commands to execute
+ * @opaque: pointer to the command structure
+ * @error: SEV FW return code on failure
+ */
+struct sev_issue_cmd {
+ __u32 cmd; /* In */
+ __u64 data; /* In */
+ __u32 error; /* Out */
+};
+
+#define SEV_IOC_TYPE 'S'
+#define SEV_ISSUE_CMD _IOWR(SEV_IOC_TYPE, 0x0, struct sev_issue_cmd)
+
+#endif /* __PSP_USER_SEV_H */
--
2.9.5
Define Secure Encrypted Virtualization (SEV) key management command id
and structure. The command definition is available in SEV KM [1] spec
0.14 and Documentation/virtual/kvm/amd-memory-encryption.txt
[1] http://support.amd.com/TechDocs/55766_SEV-KM API_Specification.pdf
Cc: Paolo Bonzini <[email protected]>
Cc: "Radim Krčmář" <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Brijesh Singh <[email protected]>
---
include/linux/psp-sev.h | 512 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 512 insertions(+)
create mode 100644 include/linux/psp-sev.h
diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h
new file mode 100644
index 000000000000..d40709b65b18
--- /dev/null
+++ b/include/linux/psp-sev.h
@@ -0,0 +1,512 @@
+/*
+ * AMD Secure Encrypted Virtualization (SEV) driver interface
+ *
+ * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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_SEV_H__
+#define __PSP_SEV_H__
+
+#ifdef CONFIG_X86
+#include <linux/mem_encrypt.h>
+
+#define __psp_pa(x) __sme_pa(x)
+#else
+#define __psp_pa(x) __pa(x)
+#endif
+
+#define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */
+
+/**
+ * SEV platform state
+ */
+enum sev_state {
+ SEV_STATE_UNINIT = 0x0,
+ SEV_STATE_INIT = 0x1,
+ SEV_STATE_WORKING = 0x2,
+
+ SEV_STATE_MAX
+};
+
+/**
+ * SEV platform and guest management commands
+ */
+enum sev_cmd {
+ /* platform commands */
+ SEV_CMD_INIT = 0x001,
+ SEV_CMD_SHUTDOWN = 0x002,
+ SEV_CMD_FACTORY_RESET = 0x003,
+ SEV_CMD_PLATFORM_STATUS = 0x004,
+ SEV_CMD_PEK_GEN = 0x005,
+ SEV_CMD_PEK_CSR = 0x006,
+ SEV_CMD_PEK_CERT_IMPORT = 0x007,
+ SEV_CMD_PDH_CERT_EXPORT = 0x008,
+ SEV_CMD_PDH_GEN = 0x009,
+ SEV_CMD_DF_FLUSH = 0x00A,
+
+ /* Guest commands */
+ SEV_CMD_DECOMMISSION = 0x020,
+ SEV_CMD_ACTIVATE = 0x021,
+ SEV_CMD_DEACTIVATE = 0x022,
+ SEV_CMD_GUEST_STATUS = 0x023,
+
+ /* Guest launch commands */
+ SEV_CMD_LAUNCH_START = 0x030,
+ SEV_CMD_LAUNCH_UPDATE_DATA = 0x031,
+ SEV_CMD_LAUNCH_UPDATE_VMSA = 0x032,
+ SEV_CMD_LAUNCH_MEASURE = 0x033,
+ SEV_CMD_LAUNCH_UPDATE_SECRET = 0x034,
+ SEV_CMD_LAUNCH_FINISH = 0x035,
+
+ /* Guest migration commands (outgoing) */
+ SEV_CMD_SEND_START = 0x040,
+ SEV_CMD_SEND_UPDATE_DATA = 0x041,
+ SEV_CMD_SEND_UPDATE_VMSA = 0x042,
+ SEV_CMD_SEND_FINISH = 0x043,
+
+ /* Guest migration commands (incoming) */
+ SEV_CMD_RECEIVE_START = 0x050,
+ SEV_CMD_RECEIVE_UPDATE_DATA = 0x051,
+ SEV_CMD_RECEIVE_UPDATE_VMSA = 0x052,
+ SEV_CMD_RECEIVE_FINISH = 0x053,
+
+ /* Guest debug commands */
+ SEV_CMD_DBG_DECRYPT = 0x060,
+ SEV_CMD_DBG_ENCRYPT = 0x061,
+
+ SEV_CMD_MAX,
+};
+
+/**
+ * status code returned by the commands
+ */
+enum psp_ret_code {
+ SEV_RET_SUCCESS = 0,
+ SEV_RET_INVALID_PLATFORM_STATE,
+ SEV_RET_INVALID_GUEST_STATE,
+ SEV_RET_INAVLID_CONFIG,
+ SEV_RET_INVALID_len,
+ SEV_RET_ALREADY_OWNED,
+ SEV_RET_INVALID_CERTIFICATE,
+ SEV_RET_POLICY_FAILURE,
+ SEV_RET_INACTIVE,
+ SEV_RET_INVALID_ADDRESS,
+ SEV_RET_BAD_SIGNATURE,
+ SEV_RET_BAD_MEASUREMENT,
+ SEV_RET_ASID_OWNED,
+ SEV_RET_INVALID_ASID,
+ SEV_RET_WBINVD_REQUIRED,
+ SEV_RET_DFFLUSH_REQUIRED,
+ SEV_RET_INVALID_GUEST,
+ SEV_RET_INVALID_COMMAND,
+ SEV_RET_ACTIVE,
+ SEV_RET_HWSEV_RET_PLATFORM,
+ SEV_RET_HWSEV_RET_UNSAFE,
+ SEV_RET_UNSUPPORTED,
+ SEV_RET_MAX,
+};
+
+/**
+ * struct sev_data_init - INIT command parameters
+ *
+ * @flags: processing flags
+ * @tmr_address: system physical address used for SEV-ES
+ * @tmr_len: len of tmr_address
+ */
+struct __attribute__((__packed__)) sev_data_init {
+ u32 flags; /* In */
+ u32 reserved; /* In */
+ u64 tmr_address; /* In */
+ u32 tmr_len; /* In */
+};
+
+/**
+ * struct sev_data_status - PLATFORM_STATUS command parameters
+ *
+ * @major: major API version
+ * @minor: minor API version
+ * @state: platform state
+ * @owner: self-owned or externally owned
+ * @config: platform config flags
+ * @build: firmware build id for API version
+ * @guest_count: number of active guests
+ */
+struct __attribute__((__packed__)) sev_data_status {
+ u8 api_major; /* Out */
+ u8 api_minor; /* Out */
+ u8 state; /* Out */
+ u8 owner : 1; /* Out */
+ u8 reserved1 : 7;
+ u32 config : 1; /* Out */
+ u32 reserved2 : 23;
+ u32 build : 8; /* Out */
+ u32 guest_count; /* Out */
+};
+
+/**
+ * struct sev_data_pek_csr - PEK_CSR command parameters
+ *
+ * @address: PEK certificate chain
+ * @len: len of certificate
+ */
+struct __attribute__((__packed__)) sev_data_pek_csr {
+ u64 address; /* In */
+ u32 len; /* In/Out */
+};
+
+/**
+ * struct sev_data_cert_import - PEK_CERT_IMPORT command parameters
+ *
+ * @pek_address: PEK certificate chain
+ * @pek_len: len of PEK certificate
+ * @oca_address: OCA certificate chain
+ * @oca_len: len of OCA certificate
+ */
+struct __attribute__((__packed__)) sev_data_pek_cert_import {
+ u64 pek_cert_address; /* In */
+ u32 pek_cert_len; /* In */
+ u32 reserved; /* In */
+ u64 oca_cert_address; /* In */
+ u32 oca_cert_len; /* In */
+};
+
+/**
+ * struct sev_data_pdh_cert_export - PDH_CERT_EXPORT command parameters
+ *
+ * @pdh_address: PDH certificate address
+ * @pdh_len: len of PDH certificate
+ * @cert_chain_address: PDH certificate chain
+ * @cert_chain_len: len of PDH certificate chain
+ */
+struct __attribute__((__packed__)) sev_data_pdh_cert_export {
+ u64 pdh_cert_address; /* In */
+ u32 pdh_cert_len; /* In/Out */
+ u32 reserved; /* In */
+ u64 cert_chain_address; /* In */
+ u32 cert_chain_len; /* In/Out */
+};
+
+/**
+ * struct sev_data_decommission - DECOMMISSION command parameters
+ *
+ * @handle: handle of the VM to decommission
+ */
+struct __attribute__((__packed__)) sev_data_decommission {
+ u32 handle; /* In */
+};
+
+/**
+ * struct sev_data_activate - ACTIVATE command parameters
+ *
+ * @handle: handle of the VM to activate
+ * @asid: asid assigned to the VM
+ */
+struct __attribute__((__packed__)) sev_data_activate {
+ u32 handle; /* In */
+ u32 asid; /* In */
+};
+
+/**
+ * struct sev_data_deactivate - DEACTIVATE command parameters
+ *
+ * @handle: handle of the VM to deactivate
+ */
+struct __attribute__((__packed__)) sev_data_deactivate {
+ u32 handle; /* In */
+};
+
+/**
+ * struct sev_data_guest_status - SEV GUEST_STATUS command parameters
+ *
+ * @handle: handle of the VM to retrieve status
+ * @policy: policy information for the VM
+ * @asid: current ASID of the VM
+ * @state: current state of the VM
+ */
+struct __attribute__((__packed__)) sev_data_guest_status {
+ u32 handle; /* In */
+ u32 policy; /* Out */
+ u32 asid; /* Out */
+ u8 state; /* Out */
+};
+
+/**
+ * struct sev_data_launch_start - LAUNCH_START command parameters
+ *
+ * @handle: handle assigned to the VM
+ * @policy: guest launch policy
+ * @dh_cert_address: physical address of DH certificate blob
+ * @dh_cert_len: len of DH certificate blob
+ * @session_address: physical address of session parameters
+ * @session_len: len of session parameters
+ */
+struct __attribute__((__packed__)) sev_data_launch_start {
+ u32 handle; /* In/Out */
+ u32 policy; /* In */
+ u64 dh_cert_address; /* In */
+ u32 dh_cert_len; /* In */
+ u32 reserved; /* In */
+ u64 session_address; /* In */
+ u32 session_len; /* In */
+};
+
+/**
+ * struct sev_data_launch_update_data - LAUNCH_UPDATE_DATA command parameter
+ *
+ * @handle: handle of the VM to update
+ * @len: len of memory to be encrypted
+ * @address: physical address of memory region to encrypt
+ */
+struct __attribute__((__packed__)) sev_data_launch_update_data {
+ u32 handle; /* In */
+ u32 reserved;
+ u64 address; /* In */
+ u32 len; /* In */
+};
+
+/**
+ * struct sev_data_launch_update_vmsa - LAUNCH_UPDATE_VMSA command
+ *
+ * @handle: handle of the VM
+ * @address: physical address of memory region to encrypt
+ * @len: len of memory region to encrypt
+ */
+struct __attribute__((__packed__)) sev_data_launch_update_vmsa {
+ u32 handle; /* In */
+ u32 reserved;
+ u64 address; /* In */
+ u32 len; /* In */
+};
+
+/**
+ * struct sev_data_launch_measure - LAUNCH_MEASURE command parameters
+ *
+ * @handle: handle of the VM to process
+ * @address: physical address containing the measurement blob
+ * @len: len of measurement blob
+ */
+struct __attribute__((__packed__)) sev_data_launch_measure {
+ u32 handle; /* In */
+ u32 reserved;
+ u64 address; /* In */
+ u32 len; /* In/Out */
+};
+
+/**
+ * struct sev_data_launch_secret - LAUNCH_SECRET command parameters
+ *
+ * @handle: handle of the VM to process
+ * @hdr_address: physical address containing the packet header
+ * @hdr_len: len of packet header
+ * @guest_address: system physical address of guest memory region
+ * @guest_len: len of guest_paddr
+ * @trans_address: physical address of transport memory buffer
+ * @trans_len: len of transport memory buffer
+ */
+struct __attribute__((__packed__)) sev_data_launch_secret {
+ u32 handle; /* In */
+ u32 reserved1;
+ u64 hdr_address; /* In */
+ u32 hdr_len; /* In */
+ u32 reserved2;
+ u64 guest_address; /* In */
+ u32 guest_len; /* In */
+ u32 reserved3;
+ u64 trans_address; /* In */
+ u32 trans_len; /* In */
+};
+
+/**
+ * struct sev_data_launch_finish - LAUNCH_FINISH command parameters
+ *
+ * @handle: handle of the VM to process
+ */
+struct __attribute__((__packed__)) sev_data_launch_finish {
+ u32 handle; /* In */
+};
+
+/**
+ * struct sev_data_send_start - SEND_START command parameters
+ *
+ * @handle: handle of the VM to process
+ * @policy: policy information for the VM
+ * @pdh_cert_address: physical address containing PDH certificate
+ * @pdh_cert_len: len of PDH certificate
+ * @plat_certs_address: physical address containing platform certificate
+ * @plat_certs_len: len of platform certificate
+ * @amd_certs_address: physical address containing AMD certificate
+ * @amd_certs_len: len of AMD certificate
+ * @session_address: physical address containing Session data
+ * @session_len: len of session data
+ */
+struct __attribute__((__packed__)) sev_data_send_start {
+ u32 handle; /* In */
+ u32 policy; /* Out */
+ u64 pdh_cert_address; /* In */
+ u32 pdh_cert_len; /* In */
+ u32 reserved1;
+ u64 plat_cert_address; /* In */
+ u32 plat_cert_len; /* In */
+ u32 reserved2;
+ u64 amd_cert_address; /* In */
+ u32 amd_cert_len; /* In */
+ u32 reserved3;
+ u64 session_address; /* In */
+ u32 session_len; /* In/Out */
+};
+
+/**
+ * struct sev_data_send_update - SEND_UPDATE_DATA command
+ *
+ * @handle: handle of the VM to process
+ * @hdr_address: physical address containing packet header
+ * @hdr_len: len of packet header
+ * @guest_address: physical address of guest memory region to send
+ * @guest_len: len of guest memory region to send
+ * @trans_address: physical address of host memory region
+ * @trans_len: len of host memory region
+ */
+struct __attribute__((__packed__)) sev_data_send_update_data {
+ u32 handle; /* In */
+ u32 reserved1;
+ u64 hdr_address; /* In */
+ u32 hdr_len; /* In/Out */
+ u32 reserved2;
+ u64 guest_address; /* In */
+ u32 guest_len; /* In */
+ u32 reserved3;
+ u64 trans_address; /* In */
+ u32 trans_len; /* In */
+};
+
+/**
+ * struct sev_data_send_update - SEND_UPDATE_VMSA command
+ *
+ * @handle: handle of the VM to process
+ * @hdr_address: physical address containing packet header
+ * @hdr_len: len of packet header
+ * @guest_address: physical address of guest memory region to send
+ * @guest_len: len of guest memory region to send
+ * @trans_address: physical address of host memory region
+ * @trans_len: len of host memory region
+ */
+struct __attribute__((__packed__)) sev_data_send_update_vmsa {
+ u32 handle; /* In */
+ u64 hdr_address; /* In */
+ u32 hdr_len; /* In/Out */
+ u32 reserved2;
+ u64 guest_address; /* In */
+ u32 guest_len; /* In */
+ u32 reserved3;
+ u64 trans_address; /* In */
+ u32 trans_len; /* In */
+};
+
+/**
+ * struct sev_data_send_finish - SEND_FINISH command parameters
+ *
+ * @handle: handle of the VM to process
+ */
+struct __attribute__((__packed__)) sev_data_send_finish {
+ u32 handle; /* In */
+};
+
+/**
+ * struct sev_data_receive_start - RECEIVE_START command parameters
+ *
+ * @handle: handle of the VM to perform receive operation
+ * @pdh_cert_address: system physical address containing PDH certificate blob
+ * @pdh_cert_len: len of PDH certificate blob
+ * @session_address: system physical address containing session blob
+ * @session_len: len of session blob
+ */
+struct __attribute__((__packed__)) sev_data_receive_start {
+ u32 handle; /* In/Out */
+ u32 policy; /* In */
+ u64 pdh_cert_address; /* In */
+ u32 pdh_cert_len; /* In */
+ u32 reserved1;
+ u64 session_address; /* In */
+ u32 session_len; /* In */
+};
+
+/**
+ * struct sev_data_receive_update_data - RECEIVE_UPDATE_DATA command parameters
+ *
+ * @handle: handle of the VM to update
+ * @hdr_address: physical address containing packet header blob
+ * @hdr_len: len of packet header
+ * @guest_address: system physical address of guest memory region
+ * @guest_len: len of guest memory region
+ * @trans_address: system physical address of transport buffer
+ * @trans_len: len of transport buffer
+ */
+struct __attribute__((__packed__)) sev_data_receive_update_data {
+ u32 handle; /* In */
+ u32 reserved1;
+ u64 hdr_address; /* In */
+ u32 hdr_len; /* In */
+ u32 reserved2;
+ u64 guest_address; /* In */
+ u32 guest_len; /* In */
+ u32 reserved3;
+ u64 trans_address; /* In */
+ u32 trans_len; /* In */
+};
+
+/**
+ * struct sev_data_receive_update_vmsa - RECEIVE_UPDATE_VMSA command parameters
+ *
+ * @handle: handle of the VM to update
+ * @hdr_address: physical address containing packet header blob
+ * @hdr_len: len of packet header
+ * @guest_address: system physical address of guest memory region
+ * @guest_len: len of guest memory region
+ * @trans_address: system physical address of transport buffer
+ * @trans_len: len of transport buffer
+ */
+struct __attribute__((__packed__)) sev_data_receive_update_vmsa {
+ u32 handle; /* In */
+ u32 reserved1;
+ u64 hdr_address; /* In */
+ u32 hdr_len; /* In */
+ u32 reserved2;
+ u64 guest_address; /* In */
+ u32 guest_len; /* In */
+ u32 reserved3;
+ u64 trans_address; /* In */
+ u32 trans_len; /* In */
+};
+
+/**
+ * struct sev_data_receive_finish - RECEIVE_FINISH command parameters
+ *
+ * @handle: handle of the VM to finish
+ */
+struct __attribute__((__packed__)) sev_data_receive_finish {
+ u32 handle; /* In */
+};
+
+/**
+ * struct sev_data_dbg - DBG_ENCRYPT/DBG_DECRYPT command parameters
+ *
+ * @handle: handle of the VM to perform debug operation
+ * @src_addr: source address of data to operate on
+ * @dst_addr: destination address of data to operate on
+ * @len: len of data to operate on
+ */
+struct __attribute__((__packed__)) sev_data_dbg {
+ u32 handle; /* In */
+ u32 reserved;
+ u64 src_addr; /* In */
+ u64 dst_addr; /* In */
+ u32 len; /* In */
+};
+
+#endif /* __PSP_SEV_H__ */
--
2.9.5
Platform Security Processor (PSP) is part of AMD Secure Processor (AMD-SP),
PSP is a dedicated processor that provides the support for key management
commands in a Secure Encrypted Virtualiztion (SEV) mode, along with
software-based Trusted Executation Environment (TEE) to enable the
third-party trusted applications.
Cc: Paolo Bonzini <[email protected]>
Cc: "Radim Krčmář" <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Brijesh Singh <[email protected]>
---
drivers/crypto/ccp/Kconfig | 11 +++++
drivers/crypto/ccp/Makefile | 1 +
drivers/crypto/ccp/psp-dev.c | 111 +++++++++++++++++++++++++++++++++++++++++++
drivers/crypto/ccp/psp-dev.h | 61 ++++++++++++++++++++++++
drivers/crypto/ccp/sp-dev.c | 32 +++++++++++++
drivers/crypto/ccp/sp-dev.h | 27 ++++++++++-
drivers/crypto/ccp/sp-pci.c | 46 ++++++++++++++++++
7 files changed, 288 insertions(+), 1 deletion(-)
create mode 100644 drivers/crypto/ccp/psp-dev.c
create mode 100644 drivers/crypto/ccp/psp-dev.h
diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
index 6d626606b9c5..1d927e13bf31 100644
--- a/drivers/crypto/ccp/Kconfig
+++ b/drivers/crypto/ccp/Kconfig
@@ -32,3 +32,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
+ help
+ Provide the support for AMD Platform Security Processor (PSP). PSP is
+ a dedicated processor that provides the support for key management
+ commands in in a Secure Encrypted Virtualiztion (SEV) mode, along with
+ software-based Trusted Executation Environment (TEE) to enable the
+ third-party trusted applications.
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index 57f8debfcfb3..008bae7e26ec 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -7,6 +7,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 \
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
new file mode 100644
index 000000000000..e60e53272e71
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -0,0 +1,111 @@
+/*
+ * AMD Platform Security Processor (PSP) interface
+ *
+ * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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"
+
+const struct psp_vdata psp_entry = {
+ .offset = 0x10500,
+};
+
+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;
+}
+
+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);
+
+ dev_dbg(dev, "requesting an IRQ ...\n");
+ /* 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;
+ }
+
+ sp_set_psp_master(sp);
+
+ /* Enable interrupt */
+ dev_dbg(dev, "Enabling interrupts ...\n");
+ iowrite32(7, psp->io_regs + PSP_P2CMSG_INTEN);
+
+ dev_notice(dev, "psp enabled\n");
+
+ 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);
+}
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
new file mode 100644
index 000000000000..d53970ef5960
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -0,0 +1,61 @@
+/*
+ * AMD Platform Security Processor (PSP) interface driver
+ *
+ * Copyright (C) 2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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;
+};
+
+extern const struct psp_vdata psp_entry;
+
+#endif /* __PSP_DEV_H */
diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c
index bef387c8abfd..8487454664d3 100644
--- a/drivers/crypto/ccp/sp-dev.c
+++ b/drivers/crypto/ccp/sp-dev.c
@@ -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,33 @@ 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;
+}
+
+void sp_set_psp_master(struct sp_device *sp)
+{
+ if (sp->set_psp_master_device)
+ sp->set_psp_master_device(sp);
+}
+
static int __init sp_mod_init(void)
{
#ifdef CONFIG_X86
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index 5ab486ade1ad..be09905f06c2 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -42,12 +42,19 @@ struct ccp_vdata {
const unsigned int offset;
const unsigned int rsamax;
};
+
+struct psp_vdata {
+ const unsigned int version;
+ const struct psp_actions *perform;
+ const unsigned int offset;
+};
+
/* Structure to hold SP device data */
struct sp_dev_vdata {
const unsigned int bar;
const struct ccp_vdata *ccp_vdata;
- void *psp_vdata;
+ const struct psp_vdata *psp_vdata;
};
struct sp_device {
@@ -68,6 +75,10 @@ struct sp_device {
/* DMA caching attribute support */
unsigned int axcache;
+ /* get and set master device */
+ struct sp_device*(*get_psp_master_device)(void);
+ void (*set_psp_master_device)(struct sp_device *);
+
bool irq_registered;
bool use_tasklet;
@@ -103,6 +114,8 @@ void sp_free_ccp_irq(struct sp_device *sp, void *data);
int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler,
const char *name, void *data);
void sp_free_psp_irq(struct sp_device *sp, void *data);
+void sp_set_psp_master(struct sp_device *sp);
+struct sp_device *sp_get_psp_master_device(void);
#ifdef CONFIG_CRYPTO_DEV_SP_CCP
@@ -130,4 +143,16 @@ static inline int ccp_dev_resume(struct sp_device *sp)
}
#endif /* CONFIG_CRYPTO_DEV_SP_CCP */
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+
+int psp_dev_init(struct sp_device *sp);
+void psp_dev_destroy(struct sp_device *sp);
+
+#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
+
+static inline int psp_dev_init(struct sp_device *sp) { return 0; }
+static inline void psp_dev_destroy(struct sp_device *sp) { }
+
+#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
+
#endif
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index 9859aa683a28..20a0f3543cf4 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -25,6 +25,7 @@
#include <linux/ccp.h>
#include "ccp-dev.h"
+#include "psp-dev.h"
#define MSIX_VECTORS 2
@@ -32,6 +33,7 @@ struct sp_pci {
int msix_count;
struct msix_entry msix_entry[MSIX_VECTORS];
};
+static struct sp_device *sp_dev_master;
static int sp_get_msix_irqs(struct sp_device *sp)
{
@@ -108,6 +110,45 @@ static void sp_free_irqs(struct sp_device *sp)
sp->psp_irq = 0;
}
+static bool sp_pci_is_master(struct sp_device *sp)
+{
+ struct device *dev_cur, *dev_new;
+ struct pci_dev *pdev_cur, *pdev_new;
+
+ dev_new = sp->dev;
+ dev_cur = sp_dev_master->dev;
+
+ pdev_new = to_pci_dev(dev_new);
+ pdev_cur = to_pci_dev(dev_cur);
+
+ if (pdev_new->bus->number < pdev_cur->bus->number)
+ return true;
+
+ if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn))
+ return true;
+
+ if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn))
+ return true;
+
+ return false;
+}
+
+static void psp_set_master(struct sp_device *sp)
+{
+ if (!sp_dev_master) {
+ sp_dev_master = sp;
+ return;
+ }
+
+ if (sp_pci_is_master(sp))
+ sp_dev_master = sp;
+}
+
+static struct sp_device *psp_get_master(void)
+{
+ return sp_dev_master;
+}
+
static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct sp_device *sp;
@@ -166,6 +207,8 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto e_err;
pci_set_master(pdev);
+ sp->set_psp_master_device = psp_set_master;
+ sp->get_psp_master_device = psp_get_master;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret) {
@@ -237,6 +280,9 @@ static const struct sp_dev_vdata dev_vdata[] = {
#ifdef CONFIG_CRYPTO_DEV_SP_CCP
.ccp_vdata = &ccpv5a,
#endif
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+ .psp_vdata = &psp_entry
+#endif
},
{
.bar = 2,
--
2.9.5
Hi Brijesh,
[auto build test WARNING on kvm/linux-next]
[also build test WARNING on v4.14-rc1 next-20170922]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Brijesh-Singh/x86-Secure-Encrypted-Virtualization-AMD/20170923-033600
base: https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
coccinelle warnings: (new ones prefixed by >>)
>> drivers/crypto/ccp/psp-dev.c:311:5-11: ERROR: allocation function on line 310 returns NULL not ERR_PTR on failure
Please review and possibly fold the followup patch.
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
drivers/crypto/ccp/psp-dev.c:311:5-11: ERROR: allocation function on line 310 returns NULL not ERR_PTR on failure
The various basic memory allocation functions don't return ERR_PTR
Generated by: scripts/coccinelle/null/eno.cocci
Fixes: 7d4ce155f344 ("crypto: ccp: Add Secure Encrypted Virtualization (SEV) command support")
CC: Brijesh Singh <[email protected]>
Signed-off-by: Fengguang Wu <[email protected]>
---
psp-dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -308,7 +308,7 @@ static void *copy_user_blob(u64 __user u
return ERR_PTR(-EINVAL);
data = kmalloc(len, GFP_KERNEL);
- if (IS_ERR(data))
+ if (!data)
return ERR_PTR(-ENOMEM);
if (copy_from_user(data, (void __user *)(uintptr_t)uaddr, len))
On Tue, Sep 19, 2017 at 03:46:03PM -0500, Brijesh Singh wrote:
> Platform Security Processor (PSP) is part of AMD Secure Processor (AMD-SP),
The Platform...
> PSP is a dedicated processor that provides the support for key management
> commands in a Secure Encrypted Virtualiztion (SEV) mode, along with
Virtualization
Is integrating that spellchecker hard? Because what I do, for example,
is press F7 in vim when I've written the commit message. And F7 is
mapped to:
map <F7> :set spell! spelllang=en_us spellfile=~/.vim/spellfile.add<CR><Bar>:echo "spellcheck: " . strpart("offon", 3 * &spell, 3)<CR>
in my .vimrc
And I'm pretty sure you can do a similar thing with other editors.
> software-based Trusted Executation Environment (TEE) to enable the
> third-party trusted applications.
>
> Cc: Paolo Bonzini <[email protected]>
> Cc: "Radim Krčmář" <[email protected]>
> Cc: Borislav Petkov <[email protected]>
> Cc: Herbert Xu <[email protected]>
> Cc: Gary Hook <[email protected]>
> Cc: Tom Lendacky <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Brijesh Singh <[email protected]>
> ---
> drivers/crypto/ccp/Kconfig | 11 +++++
> drivers/crypto/ccp/Makefile | 1 +
> drivers/crypto/ccp/psp-dev.c | 111 +++++++++++++++++++++++++++++++++++++++++++
> drivers/crypto/ccp/psp-dev.h | 61 ++++++++++++++++++++++++
> drivers/crypto/ccp/sp-dev.c | 32 +++++++++++++
> drivers/crypto/ccp/sp-dev.h | 27 ++++++++++-
> drivers/crypto/ccp/sp-pci.c | 46 ++++++++++++++++++
> 7 files changed, 288 insertions(+), 1 deletion(-)
> create mode 100644 drivers/crypto/ccp/psp-dev.c
> create mode 100644 drivers/crypto/ccp/psp-dev.h
>
> diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
> index 6d626606b9c5..1d927e13bf31 100644
> --- a/drivers/crypto/ccp/Kconfig
> +++ b/drivers/crypto/ccp/Kconfig
> @@ -32,3 +32,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
So this last symbol CRYPTO_DEV_CCP_DD is default m and it doesn't depend
on anything. And I'm pretty sure it should depend on CPU_SUP_AMD as this
is AMD-specific hw. You can add that dependency in a prepatch.
And what happened to adding dependencies on CONFIG_KVM_AMD? Or can you
use the PSP without virtualization in any sensible way?
> + help
> + Provide the support for AMD Platform Security Processor (PSP). PSP is
... for the AMD ... The PSP ...
> + a dedicated processor that provides the support for key management
that provides support for
> + commands in in a Secure Encrypted Virtualiztion (SEV) mode, along with
... in Secure Encrypted Virtualization
> + software-based Trusted Executation Environment (TEE) to enable the
> + third-party trusted applications.
> diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
> index 57f8debfcfb3..008bae7e26ec 100644
> --- a/drivers/crypto/ccp/Makefile
> +++ b/drivers/crypto/ccp/Makefile
> @@ -7,6 +7,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 \
> diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
> new file mode 100644
> index 000000000000..e60e53272e71
> --- /dev/null
> +++ b/drivers/crypto/ccp/psp-dev.c
> @@ -0,0 +1,111 @@
> +/*
> + * AMD Platform Security Processor (PSP) interface
> + *
> + * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
> + *
> + * Author: Brijesh Singh <[email protected]>
> + *
> + * 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"
> +
> +const struct psp_vdata psp_entry = {
> + .offset = 0x10500,
> +};
> +
> +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;
> +}
> +
> +irqreturn_t psp_irq_handler(int irq, void *data)
Not static because... ?
> +{
> + 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;
<---- newline here. I already pointed this out last time. Please be more
careful when incorporating feedback. This is not the first time I'm
writing this. :-\
> + 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);
> +
> + dev_dbg(dev, "requesting an IRQ ...\n");
> + /* 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;
> + }
> +
> + sp_set_psp_master(sp);
>From last review:
> So this function is called only once and declared somewhere else. You
> could simply do here:
>
> if (sp->set_psp_master_device)
> sp->set_psp_master_device(sp);
>
> and get rid of one more global function.
and you said:
> Sure I can do that.
> +
> + /* Enable interrupt */
> + dev_dbg(dev, "Enabling interrupts ...\n");
That statement is superfluous...
> + iowrite32(7, psp->io_regs + PSP_P2CMSG_INTEN);
> +
> + dev_notice(dev, "psp enabled\n");
... as this will issue anyway and there are no conditional code paths
in-between.
> +
> + 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);
> +}
So I'm going to stop right here. Please go over
https://lkml.kernel.org/r/[email protected]
make sure you've addressed *every* piece of feedback and then send me a
v4.1 for review.
--
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
The Platform Security Processor (PSP) is part of AMD Secure Processor
(AMD-SP), PSP is a dedicated processor that provides the support for
key management commands in a Secure Encrypted Virtualization (SEV) mode,
along with software-based Trusted Execution Environment (TEE) to enable
the third-party trusted applications.
Cc: Paolo Bonzini <[email protected]>
Cc: "Radim Krčmář" <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Brijesh Singh <[email protected]>
---
Hi Boris,
I have been going through feedbacks and issues reported by kbuild robot and
have been making the fixes at:
repo: https://github.com/codomania/kvm.git
branch: sev-v4-p2+fixes
After I am finished with all the fixes then will submit v5 part2.
In meantime, if you don't mind then can you look at updated patches
on sev-v4-p2+fixes branch or you can just wait for me to submit v5.
thank you very much.
-Brijesh
drivers/crypto/ccp/Kconfig | 11 +++++
drivers/crypto/ccp/Makefile | 1 +
drivers/crypto/ccp/psp-dev.c | 113 +++++++++++++++++++++++++++++++++++++++++++
drivers/crypto/ccp/psp-dev.h | 61 +++++++++++++++++++++++
drivers/crypto/ccp/sp-dev.c | 26 ++++++++++
drivers/crypto/ccp/sp-dev.h | 26 +++++++++-
drivers/crypto/ccp/sp-pci.c | 46 ++++++++++++++++++
7 files changed, 283 insertions(+), 1 deletion(-)
create mode 100644 drivers/crypto/ccp/psp-dev.c
create mode 100644 drivers/crypto/ccp/psp-dev.h
diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
index 6d626606b9c5..627f3e61dcac 100644
--- a/drivers/crypto/ccp/Kconfig
+++ b/drivers/crypto/ccp/Kconfig
@@ -32,3 +32,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
+ help
+ Provide the support for AMD Platform Security Processor (PSP). PSP is
+ a dedicated processor that provides the support for key management
+ commands in a Secure Encrypted Virtualiztion (SEV) mode, along with
+ software-based Trusted Execution Environment (TEE) to enable the
+ third-party trusted applications.
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index 57f8debfcfb3..008bae7e26ec 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -7,6 +7,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 \
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
new file mode 100644
index 000000000000..b201c524c28f
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -0,0 +1,113 @@
+/*
+ * AMD Platform Security Processor (PSP) interface
+ *
+ * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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"
+
+const struct psp_vdata psp_entry = {
+ .offset = 0x10500,
+};
+
+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);
+
+ dev_dbg(dev, "requesting an IRQ ...\n");
+ /* 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 */
+ dev_dbg(dev, "Enabling interrupts ...\n");
+ iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN);
+
+ dev_notice(dev, "psp enabled\n");
+
+ 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);
+}
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
new file mode 100644
index 000000000000..d53970ef5960
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -0,0 +1,61 @@
+/*
+ * AMD Platform Security Processor (PSP) interface driver
+ *
+ * Copyright (C) 2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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;
+};
+
+extern const struct psp_vdata psp_entry;
+
+#endif /* __PSP_DEV_H */
diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c
index bef387c8abfd..cf101c039c8f 100644
--- a/drivers/crypto/ccp/sp-dev.c
+++ b/drivers/crypto/ccp/sp-dev.c
@@ -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
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index 5ab486ade1ad..761dba176168 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -42,12 +42,19 @@ struct ccp_vdata {
const unsigned int offset;
const unsigned int rsamax;
};
+
+struct psp_vdata {
+ const unsigned int version;
+ const struct psp_actions *perform;
+ const unsigned int offset;
+};
+
/* Structure to hold SP device data */
struct sp_dev_vdata {
const unsigned int bar;
const struct ccp_vdata *ccp_vdata;
- void *psp_vdata;
+ const struct psp_vdata *psp_vdata;
};
struct sp_device {
@@ -68,6 +75,10 @@ struct sp_device {
/* DMA caching attribute support */
unsigned int axcache;
+ /* get and set master device */
+ struct sp_device*(*get_psp_master_device)(void);
+ void (*set_psp_master_device)(struct sp_device *);
+
bool irq_registered;
bool use_tasklet;
@@ -103,6 +114,7 @@ void sp_free_ccp_irq(struct sp_device *sp, void *data);
int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler,
const char *name, void *data);
void sp_free_psp_irq(struct sp_device *sp, void *data);
+struct sp_device *sp_get_psp_master_device(void);
#ifdef CONFIG_CRYPTO_DEV_SP_CCP
@@ -130,4 +142,16 @@ static inline int ccp_dev_resume(struct sp_device *sp)
}
#endif /* CONFIG_CRYPTO_DEV_SP_CCP */
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+
+int psp_dev_init(struct sp_device *sp);
+void psp_dev_destroy(struct sp_device *sp);
+
+#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
+
+static inline int psp_dev_init(struct sp_device *sp) { return 0; }
+static inline void psp_dev_destroy(struct sp_device *sp) { }
+
+#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
+
#endif
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index 9859aa683a28..20a0f3543cf4 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -25,6 +25,7 @@
#include <linux/ccp.h>
#include "ccp-dev.h"
+#include "psp-dev.h"
#define MSIX_VECTORS 2
@@ -32,6 +33,7 @@ struct sp_pci {
int msix_count;
struct msix_entry msix_entry[MSIX_VECTORS];
};
+static struct sp_device *sp_dev_master;
static int sp_get_msix_irqs(struct sp_device *sp)
{
@@ -108,6 +110,45 @@ static void sp_free_irqs(struct sp_device *sp)
sp->psp_irq = 0;
}
+static bool sp_pci_is_master(struct sp_device *sp)
+{
+ struct device *dev_cur, *dev_new;
+ struct pci_dev *pdev_cur, *pdev_new;
+
+ dev_new = sp->dev;
+ dev_cur = sp_dev_master->dev;
+
+ pdev_new = to_pci_dev(dev_new);
+ pdev_cur = to_pci_dev(dev_cur);
+
+ if (pdev_new->bus->number < pdev_cur->bus->number)
+ return true;
+
+ if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn))
+ return true;
+
+ if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn))
+ return true;
+
+ return false;
+}
+
+static void psp_set_master(struct sp_device *sp)
+{
+ if (!sp_dev_master) {
+ sp_dev_master = sp;
+ return;
+ }
+
+ if (sp_pci_is_master(sp))
+ sp_dev_master = sp;
+}
+
+static struct sp_device *psp_get_master(void)
+{
+ return sp_dev_master;
+}
+
static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct sp_device *sp;
@@ -166,6 +207,8 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto e_err;
pci_set_master(pdev);
+ sp->set_psp_master_device = psp_set_master;
+ sp->get_psp_master_device = psp_get_master;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret) {
@@ -237,6 +280,9 @@ static const struct sp_dev_vdata dev_vdata[] = {
#ifdef CONFIG_CRYPTO_DEV_SP_CCP
.ccp_vdata = &ccpv5a,
#endif
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+ .psp_vdata = &psp_entry
+#endif
},
{
.bar = 2,
--
2.9.5
Hi,
just a small Kconfig correction. Feel free to add it to your patchset.
Thx.
---
From: Borislav Petkov <[email protected]>
This is AMD-specific hardware so present it in Kconfig only when AMD
CPU support is enabled.
Signed-off-by: Borislav Petkov <[email protected]>
Cc: Brijesh Singh <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
---
drivers/crypto/ccp/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
index 627f3e61dcac..f58a6521270b 100644
--- a/drivers/crypto/ccp/Kconfig
+++ b/drivers/crypto/ccp/Kconfig
@@ -1,5 +1,6 @@
config CRYPTO_DEV_CCP_DD
tristate "Secure Processor device driver"
+ depends on CPU_SUP_AMD
default m
help
Provides AMD Secure Processor device driver.
--
2.13.0
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
On 9/30/17 3:30 AM, Borislav Petkov wrote:
...
> From: Borislav Petkov <[email protected]>
>
> This is AMD-specific hardware so present it in Kconfig only when AMD
> CPU support is enabled.
>
> Signed-off-by: Borislav Petkov <[email protected]>
> Cc: Brijesh Singh <[email protected]>
> Cc: Tom Lendacky <[email protected]>
> Cc: Gary Hook <[email protected]>
> Cc: Herbert Xu <[email protected]>
> Cc: "David S. Miller" <[email protected]>
> Cc: [email protected]
> ---
> drivers/crypto/ccp/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
> index 627f3e61dcac..f58a6521270b 100644
> --- a/drivers/crypto/ccp/Kconfig
> +++ b/drivers/crypto/ccp/Kconfig
> @@ -1,5 +1,6 @@
> config CRYPTO_DEV_CCP_DD
> tristate "Secure Processor device driver"
> + depends on CPU_SUP_AMD
Please note that ccp.ko is built on both x86 and aarch64 (AMD Seattle)
architectures. I have not looked into details but I thought CPU_SUP_AMD
is x64 specific config. I will look into it and verify that we don't
break AMD Seattle platform builds.
> default m
> help
> Provides AMD Secure Processor device driver.
On Sat, Sep 30, 2017 at 09:06:26AM -0500, Brijesh Singh wrote:
> > diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
> > index 627f3e61dcac..f58a6521270b 100644
> > --- a/drivers/crypto/ccp/Kconfig
> > +++ b/drivers/crypto/ccp/Kconfig
> > @@ -1,5 +1,6 @@
> > config CRYPTO_DEV_CCP_DD
> > tristate "Secure Processor device driver"
> > + depends on CPU_SUP_AMD
>
> Please note that ccp.ko is built on both x86 and aarch64 (AMD Seattle)
> architectures. I have not looked into details but I thought CPU_SUP_AMD
> is x64 specific config. I will look into it and verify that we don't
> break AMD Seattle platform builds.
Ah, then I guess that line needs to be:
depends on CPU_SUP_AMD || ARM64
--
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
On 9/29/17 10:16 AM, Borislav Petkov wrote:
...
> +
>> +config CRYPTO_DEV_SP_PSP
>> + bool "Platform Security Processor (PSP) device"
>> + default y
>> + depends on CRYPTO_DEV_CCP_DD
> So this last symbol CRYPTO_DEV_CCP_DD is default m and it doesn't depend
> on anything. And I'm pretty sure it should depend on CPU_SUP_AMD as this
> is AMD-specific hw. You can add that dependency in a prepatch.
CRYPTO_DEV_CCP_DD is supported on aarch64 and x86. Whereas the PSP
interface I am adding is available on x86 only hence its safe to add add
depend on CPU_SUP_AMD for CRYPTO_DEV_SP_PSP.
> And what happened to adding dependencies on CONFIG_KVM_AMD? Or can you
> use the PSP without virtualization in any sensible way?
Yes its very much possible. The SEV FW provides two sets of commands 1)
platform certificate management and 2) guest management
The platform certificate management commands is used outside the
CONFIG_KVM_AMD.
-Brijesh
On Sat, Sep 30, 2017 at 10:55:25AM -0500, Brijesh Singh wrote:
> CRYPTO_DEV_CCP_DD is supported on aarch64 and x86. Whereas the PSP
> interface I am adding is available on x86 only hence its safe to add add
> depend on CPU_SUP_AMD for CRYPTO_DEV_SP_PSP.
I think just from having CRYPTO_DEV_CCP_DD depend on CPU_SUP_AMD ||
ARM64, CRYPTO_DEV_SP_PSP gets almost the same dependency transitively.
But sure, let's make the PSP build only on x86. It should depend on
X86_64, to be precise.
> Yes its very much possible. The SEV FW provides two sets of commands 1)
> platform certificate management and 2) guest management
>
> The platform certificate management commands is used outside the
> CONFIG_KVM_AMD.
Ok, please state that in the commit message so that it is written down
somewhere.
Thx.
--
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
On 9/30/17 11:11 AM, Borislav Petkov wrote:
> I think just from having CRYPTO_DEV_CCP_DD depend on CPU_SUP_AMD ||
> ARM64, CRYPTO_DEV_SP_PSP gets almost the same dependency transitively.
> But sure, let's make the PSP build only on x86. It should depend on
> X86_64, to be precise.
I think theoretically a 32-bit host OS can invoke a PSP commands but
currently PSP interface is exposing only the SEV FW command. And SEV
feature is available when we are in 64-bit mode hence for now its okay
to have depends on X86_64. I will add CRYPTO_DEV_CCP_DD depend on
CPU_SUP_AMD || ARM64 and CRYPTO_DEV_SP_PSP depend on X86_64 and send you
v4.2. thanks
The Platform Security Processor (PSP) is part of AMD Secure Processor
(AMD-SP), PSP is a dedicated processor that provides the support for
key management commands in a Secure Encrypted Virtualization (SEV) mode,
along with software-based Trusted Execution Environment (TEE) to enable
the third-party trusted applications.
Note that the key management functionality provided by the SEV firmware
can be used outside the kvm-amd driver hence we don't do depends on
CONFIG_KVM_AMD.
Cc: Paolo Bonzini <[email protected]>
Cc: "Radim Krčmář" <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Brijesh Singh <[email protected]>
---
Changes since v4.1:
* Add CPU_SUP_AMD depends
* Add a note in commit message that PSP can be used outside KVM
* Fix the Kconfig help based on Boris feedback
* Remove some superfluous debug statement
drivers/crypto/ccp/Kconfig | 12 +++++
drivers/crypto/ccp/Makefile | 1 +
drivers/crypto/ccp/psp-dev.c | 109 +++++++++++++++++++++++++++++++++++++++++++
drivers/crypto/ccp/psp-dev.h | 61 ++++++++++++++++++++++++
drivers/crypto/ccp/sp-dev.c | 26 +++++++++++
drivers/crypto/ccp/sp-dev.h | 26 ++++++++++-
drivers/crypto/ccp/sp-pci.c | 46 ++++++++++++++++++
7 files changed, 280 insertions(+), 1 deletion(-)
create mode 100644 drivers/crypto/ccp/psp-dev.c
create mode 100644 drivers/crypto/ccp/psp-dev.h
diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
index 6d626606b9c5..91177a5f1d32 100644
--- a/drivers/crypto/ccp/Kconfig
+++ b/drivers/crypto/ccp/Kconfig
@@ -1,6 +1,7 @@
config CRYPTO_DEV_CCP_DD
tristate "Secure Processor device driver"
default m
+ depends on CPU_SUP_AMD || ARM64
help
Provides AMD Secure Processor device driver.
If you choose 'M' here, this module will be called ccp.
@@ -32,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 the 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 the third-party trusted applications.
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index 57f8debfcfb3..008bae7e26ec 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -7,6 +7,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 \
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
new file mode 100644
index 000000000000..7480d4316239
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -0,0 +1,109 @@
+/*
+ * AMD Platform Security Processor (PSP) interface
+ *
+ * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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"
+
+const struct psp_vdata psp_entry = {
+ .offset = 0x10500,
+};
+
+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);
+}
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
new file mode 100644
index 000000000000..d53970ef5960
--- /dev/null
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -0,0 +1,61 @@
+/*
+ * AMD Platform Security Processor (PSP) interface driver
+ *
+ * Copyright (C) 2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <[email protected]>
+ *
+ * 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;
+};
+
+extern const struct psp_vdata psp_entry;
+
+#endif /* __PSP_DEV_H */
diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c
index bef387c8abfd..cf101c039c8f 100644
--- a/drivers/crypto/ccp/sp-dev.c
+++ b/drivers/crypto/ccp/sp-dev.c
@@ -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
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index 5ab486ade1ad..761dba176168 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -42,12 +42,19 @@ struct ccp_vdata {
const unsigned int offset;
const unsigned int rsamax;
};
+
+struct psp_vdata {
+ const unsigned int version;
+ const struct psp_actions *perform;
+ const unsigned int offset;
+};
+
/* Structure to hold SP device data */
struct sp_dev_vdata {
const unsigned int bar;
const struct ccp_vdata *ccp_vdata;
- void *psp_vdata;
+ const struct psp_vdata *psp_vdata;
};
struct sp_device {
@@ -68,6 +75,10 @@ struct sp_device {
/* DMA caching attribute support */
unsigned int axcache;
+ /* get and set master device */
+ struct sp_device*(*get_psp_master_device)(void);
+ void (*set_psp_master_device)(struct sp_device *);
+
bool irq_registered;
bool use_tasklet;
@@ -103,6 +114,7 @@ void sp_free_ccp_irq(struct sp_device *sp, void *data);
int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler,
const char *name, void *data);
void sp_free_psp_irq(struct sp_device *sp, void *data);
+struct sp_device *sp_get_psp_master_device(void);
#ifdef CONFIG_CRYPTO_DEV_SP_CCP
@@ -130,4 +142,16 @@ static inline int ccp_dev_resume(struct sp_device *sp)
}
#endif /* CONFIG_CRYPTO_DEV_SP_CCP */
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+
+int psp_dev_init(struct sp_device *sp);
+void psp_dev_destroy(struct sp_device *sp);
+
+#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
+
+static inline int psp_dev_init(struct sp_device *sp) { return 0; }
+static inline void psp_dev_destroy(struct sp_device *sp) { }
+
+#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
+
#endif
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index 9859aa683a28..20a0f3543cf4 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -25,6 +25,7 @@
#include <linux/ccp.h>
#include "ccp-dev.h"
+#include "psp-dev.h"
#define MSIX_VECTORS 2
@@ -32,6 +33,7 @@ struct sp_pci {
int msix_count;
struct msix_entry msix_entry[MSIX_VECTORS];
};
+static struct sp_device *sp_dev_master;
static int sp_get_msix_irqs(struct sp_device *sp)
{
@@ -108,6 +110,45 @@ static void sp_free_irqs(struct sp_device *sp)
sp->psp_irq = 0;
}
+static bool sp_pci_is_master(struct sp_device *sp)
+{
+ struct device *dev_cur, *dev_new;
+ struct pci_dev *pdev_cur, *pdev_new;
+
+ dev_new = sp->dev;
+ dev_cur = sp_dev_master->dev;
+
+ pdev_new = to_pci_dev(dev_new);
+ pdev_cur = to_pci_dev(dev_cur);
+
+ if (pdev_new->bus->number < pdev_cur->bus->number)
+ return true;
+
+ if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn))
+ return true;
+
+ if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn))
+ return true;
+
+ return false;
+}
+
+static void psp_set_master(struct sp_device *sp)
+{
+ if (!sp_dev_master) {
+ sp_dev_master = sp;
+ return;
+ }
+
+ if (sp_pci_is_master(sp))
+ sp_dev_master = sp;
+}
+
+static struct sp_device *psp_get_master(void)
+{
+ return sp_dev_master;
+}
+
static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct sp_device *sp;
@@ -166,6 +207,8 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto e_err;
pci_set_master(pdev);
+ sp->set_psp_master_device = psp_set_master;
+ sp->get_psp_master_device = psp_get_master;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret) {
@@ -237,6 +280,9 @@ static const struct sp_dev_vdata dev_vdata[] = {
#ifdef CONFIG_CRYPTO_DEV_SP_CCP
.ccp_vdata = &ccpv5a,
#endif
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+ .psp_vdata = &psp_entry
+#endif
},
{
.bar = 2,
--
2.9.5
On Sun, Oct 01, 2017 at 03:05:11PM -0500, Brijesh Singh wrote:
> I think theoretically a 32-bit host OS can invoke a PSP commands but
> currently PSP interface is exposing only the SEV FW command. And SEV
Let's cross that bridge when we get to it.
> feature is available when we are in 64-bit mode hence for now its okay
> to have depends on X86_64. I will add CRYPTO_DEV_CCP_DD depend on
> CPU_SUP_AMD || ARM64 and CRYPTO_DEV_SP_PSP depend on X86_64 and send you
> v4.2.
No, please add my patch below to your set for the CRYPTO_DEV_CCP_DD
dependency as it is a separate thing. Your patch should concentrate only
on adding the PSP and its dependencies.
Thx.
---
From: Borislav Petkov <[email protected]>
Date: Sat, 30 Sep 2017 10:06:27 +0200
Subject: [PATCH] crypto: ccp: Build the AMD secure processor driver only with
AMD CPU support
This is AMD-specific hardware so present it in Kconfig only when AMD
CPU support is enabled or on ARM64 where it is also used.
Signed-off-by: Borislav Petkov <[email protected]>
Cc: Brijesh Singh <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
---
drivers/crypto/ccp/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
index 627f3e61dcac..f19f57162225 100644
--- a/drivers/crypto/ccp/Kconfig
+++ b/drivers/crypto/ccp/Kconfig
@@ -1,5 +1,6 @@
config CRYPTO_DEV_CCP_DD
tristate "Secure Processor device driver"
+ depends on CPU_SUP_AMD || ARM64
default m
help
Provides AMD Secure Processor device driver.
--
2.13.0
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
On 10/03/2017 11:17 AM, Borislav Petkov wrote:
...
>
> No, please add my patch below to your set for the CRYPTO_DEV_CCP_DD
> dependency as it is a separate thing. Your patch should concentrate only
> on adding the PSP and its dependencies.
>
Sure, I will include your patch in my series. thanks
> ---
> From: Borislav Petkov <[email protected]>
> Date: Sat, 30 Sep 2017 10:06:27 +0200
> Subject: [PATCH] crypto: ccp: Build the AMD secure processor driver only with
> AMD CPU support
>
> This is AMD-specific hardware so present it in Kconfig only when AMD
> CPU support is enabled or on ARM64 where it is also used.
>
> Signed-off-by: Borislav Petkov <[email protected]>
> Cc: Brijesh Singh <[email protected]>
> Cc: Tom Lendacky <[email protected]>
> Cc: Gary Hook <[email protected]>
> Cc: Herbert Xu <[email protected]>
> Cc: "David S. Miller" <[email protected]>
> Cc: [email protected]
> ---
> drivers/crypto/ccp/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
> index 627f3e61dcac..f19f57162225 100644
> --- a/drivers/crypto/ccp/Kconfig
> +++ b/drivers/crypto/ccp/Kconfig
> @@ -1,5 +1,6 @@
> config CRYPTO_DEV_CCP_DD
> tristate "Secure Processor device driver"
> + depends on CPU_SUP_AMD || ARM64
> default m
> help
> Provides AMD Secure Processor device driver.
>
+-- On Mon, 2 Oct 2017, Brijesh Singh wrote --+
| +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;
| ...
| +e_err:
| + sp->psp_data = NULL;
Needs to kfree(sp->psp_data) before setting to NULL.
--
- P J P
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
On Wed, Oct 04, 2017 at 12:06:42PM +0530, P J P wrote:
> Needs to kfree(sp->psp_data) before setting to NULL.
Not if it is allocated with devm_kzalloc().
--
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--