Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

The Platform Security Processor (PSP) is part of the AMD Secure
Processor (AMD-SP) functionality. The PSP is a dedicated processor
that provides support for key management commands in Secure Encrypted
Virtualization (SEV) mode, along with software-based Trusted Execution
Environment (TEE) to enable third-party trusted applications.

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

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Gary Hook <gary.hook@amd.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: linux-crypto@vger.kernel.org
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Improvements-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Borislav Petkov <bp@suse.de>

+277 -1
+11
drivers/crypto/ccp/Kconfig
··· 33 33 Support for using the cryptographic API with the AMD Cryptographic 34 34 Coprocessor. This module supports offload of SHA and AES algorithms. 35 35 If you choose 'M' here, this module will be called ccp_crypto. 36 + 37 + config CRYPTO_DEV_SP_PSP 38 + bool "Platform Security Processor (PSP) device" 39 + default y 40 + depends on CRYPTO_DEV_CCP_DD && X86_64 41 + help 42 + Provide support for the AMD Platform Security Processor (PSP). 43 + The PSP is a dedicated processor that provides support for key 44 + management commands in Secure Encrypted Virtualization (SEV) mode, 45 + along with software-based Trusted Execution Environment (TEE) to 46 + enable third-party trusted applications.
+1
drivers/crypto/ccp/Makefile
··· 8 8 ccp-dmaengine.o \ 9 9 ccp-debugfs.o 10 10 ccp-$(CONFIG_PCI) += sp-pci.o 11 + ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o 11 12 12 13 obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o 13 14 ccp-crypto-objs := ccp-crypto-main.o \
+105
drivers/crypto/ccp/psp-dev.c
··· 1 + /* 2 + * AMD Platform Security Processor (PSP) interface 3 + * 4 + * Copyright (C) 2016-2017 Advanced Micro Devices, Inc. 5 + * 6 + * Author: Brijesh Singh <brijesh.singh@amd.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/module.h> 14 + #include <linux/kernel.h> 15 + #include <linux/kthread.h> 16 + #include <linux/sched.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/spinlock.h> 19 + #include <linux/spinlock_types.h> 20 + #include <linux/types.h> 21 + #include <linux/mutex.h> 22 + #include <linux/delay.h> 23 + #include <linux/hw_random.h> 24 + #include <linux/ccp.h> 25 + 26 + #include "sp-dev.h" 27 + #include "psp-dev.h" 28 + 29 + static struct psp_device *psp_alloc_struct(struct sp_device *sp) 30 + { 31 + struct device *dev = sp->dev; 32 + struct psp_device *psp; 33 + 34 + psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL); 35 + if (!psp) 36 + return NULL; 37 + 38 + psp->dev = dev; 39 + psp->sp = sp; 40 + 41 + snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord); 42 + 43 + return psp; 44 + } 45 + 46 + static irqreturn_t psp_irq_handler(int irq, void *data) 47 + { 48 + return IRQ_HANDLED; 49 + } 50 + 51 + int psp_dev_init(struct sp_device *sp) 52 + { 53 + struct device *dev = sp->dev; 54 + struct psp_device *psp; 55 + int ret; 56 + 57 + ret = -ENOMEM; 58 + psp = psp_alloc_struct(sp); 59 + if (!psp) 60 + goto e_err; 61 + 62 + sp->psp_data = psp; 63 + 64 + psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata; 65 + if (!psp->vdata) { 66 + ret = -ENODEV; 67 + dev_err(dev, "missing driver data\n"); 68 + goto e_err; 69 + } 70 + 71 + psp->io_regs = sp->io_map + psp->vdata->offset; 72 + 73 + /* Disable and clear interrupts until ready */ 74 + iowrite32(0, psp->io_regs + PSP_P2CMSG_INTEN); 75 + iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTSTS); 76 + 77 + /* Request an irq */ 78 + ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp); 79 + if (ret) { 80 + dev_err(dev, "psp: unable to allocate an IRQ\n"); 81 + goto e_err; 82 + } 83 + 84 + if (sp->set_psp_master_device) 85 + sp->set_psp_master_device(sp); 86 + 87 + /* Enable interrupt */ 88 + iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN); 89 + 90 + return 0; 91 + 92 + e_err: 93 + sp->psp_data = NULL; 94 + 95 + dev_notice(dev, "psp initialization failed\n"); 96 + 97 + return ret; 98 + } 99 + 100 + void psp_dev_destroy(struct sp_device *sp) 101 + { 102 + struct psp_device *psp = sp->psp_data; 103 + 104 + sp_free_psp_irq(sp, psp); 105 + }
+59
drivers/crypto/ccp/psp-dev.h
··· 1 + /* 2 + * AMD Platform Security Processor (PSP) interface driver 3 + * 4 + * Copyright (C) 2017 Advanced Micro Devices, Inc. 5 + * 6 + * Author: Brijesh Singh <brijesh.singh@amd.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #ifndef __PSP_DEV_H__ 14 + #define __PSP_DEV_H__ 15 + 16 + #include <linux/device.h> 17 + #include <linux/pci.h> 18 + #include <linux/spinlock.h> 19 + #include <linux/mutex.h> 20 + #include <linux/list.h> 21 + #include <linux/wait.h> 22 + #include <linux/dmapool.h> 23 + #include <linux/hw_random.h> 24 + #include <linux/bitops.h> 25 + #include <linux/interrupt.h> 26 + #include <linux/irqreturn.h> 27 + #include <linux/dmaengine.h> 28 + 29 + #include "sp-dev.h" 30 + 31 + #define PSP_P2CMSG_INTEN 0x0110 32 + #define PSP_P2CMSG_INTSTS 0x0114 33 + 34 + #define PSP_C2PMSG_ATTR_0 0x0118 35 + #define PSP_C2PMSG_ATTR_1 0x011c 36 + #define PSP_C2PMSG_ATTR_2 0x0120 37 + #define PSP_C2PMSG_ATTR_3 0x0124 38 + #define PSP_P2CMSG_ATTR_0 0x0128 39 + 40 + #define PSP_CMDRESP_CMD_SHIFT 16 41 + #define PSP_CMDRESP_IOC BIT(0) 42 + #define PSP_CMDRESP_RESP BIT(31) 43 + #define PSP_CMDRESP_ERR_MASK 0xffff 44 + 45 + #define MAX_PSP_NAME_LEN 16 46 + 47 + struct psp_device { 48 + struct list_head entry; 49 + 50 + struct psp_vdata *vdata; 51 + char name[MAX_PSP_NAME_LEN]; 52 + 53 + struct device *dev; 54 + struct sp_device *sp; 55 + 56 + void __iomem *io_regs; 57 + }; 58 + 59 + #endif /* __PSP_DEV_H */
+26
drivers/crypto/ccp/sp-dev.c
··· 198 198 if (sp->dev_vdata->ccp_vdata) 199 199 ccp_dev_init(sp); 200 200 201 + if (sp->dev_vdata->psp_vdata) 202 + psp_dev_init(sp); 201 203 return 0; 202 204 } 203 205 ··· 207 205 { 208 206 if (sp->dev_vdata->ccp_vdata) 209 207 ccp_dev_destroy(sp); 208 + 209 + if (sp->dev_vdata->psp_vdata) 210 + psp_dev_destroy(sp); 210 211 211 212 sp_del_device(sp); 212 213 } ··· 241 236 return 0; 242 237 } 243 238 #endif 239 + 240 + struct sp_device *sp_get_psp_master_device(void) 241 + { 242 + struct sp_device *i, *ret = NULL; 243 + unsigned long flags; 244 + 245 + write_lock_irqsave(&sp_unit_lock, flags); 246 + if (list_empty(&sp_units)) 247 + goto unlock; 248 + 249 + list_for_each_entry(i, &sp_units, entry) { 250 + if (i->psp_data) 251 + break; 252 + } 253 + 254 + if (i->get_psp_master_device) 255 + ret = i->get_psp_master_device(); 256 + unlock: 257 + write_unlock_irqrestore(&sp_unit_lock, flags); 258 + return ret; 259 + } 244 260 245 261 static int __init sp_mod_init(void) 246 262 {
+23 -1
drivers/crypto/ccp/sp-dev.h
··· 42 42 const unsigned int offset; 43 43 const unsigned int rsamax; 44 44 }; 45 + 46 + struct psp_vdata { 47 + const unsigned int offset; 48 + }; 49 + 45 50 /* Structure to hold SP device data */ 46 51 struct sp_dev_vdata { 47 52 const unsigned int bar; 48 53 49 54 const struct ccp_vdata *ccp_vdata; 50 - void *psp_vdata; 55 + const struct psp_vdata *psp_vdata; 51 56 }; 52 57 53 58 struct sp_device { ··· 72 67 73 68 /* DMA caching attribute support */ 74 69 unsigned int axcache; 70 + 71 + /* get and set master device */ 72 + struct sp_device*(*get_psp_master_device)(void); 73 + void (*set_psp_master_device)(struct sp_device *); 75 74 76 75 bool irq_registered; 77 76 bool use_tasklet; ··· 112 103 int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler, 113 104 const char *name, void *data); 114 105 void sp_free_psp_irq(struct sp_device *sp, void *data); 106 + struct sp_device *sp_get_psp_master_device(void); 115 107 116 108 #ifdef CONFIG_CRYPTO_DEV_SP_CCP 117 109 ··· 139 129 return 0; 140 130 } 141 131 #endif /* CONFIG_CRYPTO_DEV_SP_CCP */ 132 + 133 + #ifdef CONFIG_CRYPTO_DEV_SP_PSP 134 + 135 + int psp_dev_init(struct sp_device *sp); 136 + void psp_dev_destroy(struct sp_device *sp); 137 + 138 + #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ 139 + 140 + static inline int psp_dev_init(struct sp_device *sp) { return 0; } 141 + static inline void psp_dev_destroy(struct sp_device *sp) { } 142 + 143 + #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ 142 144 143 145 #endif
+52
drivers/crypto/ccp/sp-pci.c
··· 25 25 #include <linux/ccp.h> 26 26 27 27 #include "ccp-dev.h" 28 + #include "psp-dev.h" 28 29 29 30 #define MSIX_VECTORS 2 30 31 ··· 33 32 int msix_count; 34 33 struct msix_entry msix_entry[MSIX_VECTORS]; 35 34 }; 35 + static struct sp_device *sp_dev_master; 36 36 37 37 static int sp_get_msix_irqs(struct sp_device *sp) 38 38 { ··· 110 108 sp->psp_irq = 0; 111 109 } 112 110 111 + static bool sp_pci_is_master(struct sp_device *sp) 112 + { 113 + struct device *dev_cur, *dev_new; 114 + struct pci_dev *pdev_cur, *pdev_new; 115 + 116 + dev_new = sp->dev; 117 + dev_cur = sp_dev_master->dev; 118 + 119 + pdev_new = to_pci_dev(dev_new); 120 + pdev_cur = to_pci_dev(dev_cur); 121 + 122 + if (pdev_new->bus->number < pdev_cur->bus->number) 123 + return true; 124 + 125 + if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn)) 126 + return true; 127 + 128 + if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn)) 129 + return true; 130 + 131 + return false; 132 + } 133 + 134 + static void psp_set_master(struct sp_device *sp) 135 + { 136 + if (!sp_dev_master) { 137 + sp_dev_master = sp; 138 + return; 139 + } 140 + 141 + if (sp_pci_is_master(sp)) 142 + sp_dev_master = sp; 143 + } 144 + 145 + static struct sp_device *psp_get_master(void) 146 + { 147 + return sp_dev_master; 148 + } 149 + 113 150 static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 114 151 { 115 152 struct sp_device *sp; ··· 207 166 goto e_err; 208 167 209 168 pci_set_master(pdev); 169 + sp->set_psp_master_device = psp_set_master; 170 + sp->get_psp_master_device = psp_get_master; 210 171 211 172 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); 212 173 if (ret) { ··· 268 225 } 269 226 #endif 270 227 228 + #ifdef CONFIG_CRYPTO_DEV_SP_PSP 229 + static const struct psp_vdata psp_entry = { 230 + .offset = 0x10500, 231 + }; 232 + #endif 233 + 271 234 static const struct sp_dev_vdata dev_vdata[] = { 272 235 { 273 236 .bar = 2, ··· 285 236 .bar = 2, 286 237 #ifdef CONFIG_CRYPTO_DEV_SP_CCP 287 238 .ccp_vdata = &ccpv5a, 239 + #endif 240 + #ifdef CONFIG_CRYPTO_DEV_SP_PSP 241 + .psp_vdata = &psp_entry 288 242 #endif 289 243 }, 290 244 {