diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-10 16:16:35 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-10 16:16:35 -0500 |
| commit | 15303ba5d1cd9b28d03a980456c0978c0ea3b208 (patch) | |
| tree | b9200d5b7474661cf36468038529a5269ee83238 /drivers | |
| parent | 9a61df9e5f7471fe5be3e02bd0bed726b2761a54 (diff) | |
| parent | 1ab03c072feb579c9fd116de25be2b211e6bff6a (diff) | |
Merge tag 'kvm-4.16-1' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull KVM updates from Radim Krčmář:
"ARM:
- icache invalidation optimizations, improving VM startup time
- support for forwarded level-triggered interrupts, improving
performance for timers and passthrough platform devices
- a small fix for power-management notifiers, and some cosmetic
changes
PPC:
- add MMIO emulation for vector loads and stores
- allow HPT guests to run on a radix host on POWER9 v2.2 CPUs without
requiring the complex thread synchronization of older CPU versions
- improve the handling of escalation interrupts with the XIVE
interrupt controller
- support decrement register migration
- various cleanups and bugfixes.
s390:
- Cornelia Huck passed maintainership to Janosch Frank
- exitless interrupts for emulated devices
- cleanup of cpuflag handling
- kvm_stat counter improvements
- VSIE improvements
- mm cleanup
x86:
- hypervisor part of SEV
- UMIP, RDPID, and MSR_SMI_COUNT emulation
- paravirtualized TLB shootdown using the new KVM_VCPU_PREEMPTED bit
- allow guests to see TOPOEXT, GFNI, VAES, VPCLMULQDQ, and more
AVX512 features
- show vcpu id in its anonymous inode name
- many fixes and cleanups
- per-VCPU MSR bitmaps (already merged through x86/pti branch)
- stable KVM clock when nesting on Hyper-V (merged through
x86/hyperv)"
* tag 'kvm-4.16-1' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (197 commits)
KVM: PPC: Book3S: Add MMIO emulation for VMX instructions
KVM: PPC: Book3S HV: Branch inside feature section
KVM: PPC: Book3S HV: Make HPT resizing work on POWER9
KVM: PPC: Book3S HV: Fix handling of secondary HPTEG in HPT resizing code
KVM: PPC: Book3S PR: Fix broken select due to misspelling
KVM: x86: don't forget vcpu_put() in kvm_arch_vcpu_ioctl_set_sregs()
KVM: PPC: Book3S PR: Fix svcpu copying with preemption enabled
KVM: PPC: Book3S HV: Drop locks before reading guest memory
kvm: x86: remove efer_reload entry in kvm_vcpu_stat
KVM: x86: AMD Processor Topology Information
x86/kvm/vmx: do not use vm-exit instruction length for fast MMIO when running nested
kvm: embed vcpu id to dentry of vcpu anon inode
kvm: Map PFN-type memory regions as writable (if possible)
x86/kvm: Make it compile on 32bit and with HYPYERVISOR_GUEST=n
KVM: arm/arm64: Fixup userspace irqchip static key optimization
KVM: arm/arm64: Fix userspace_irqchip_in_use counting
KVM: arm/arm64: Fix incorrect timer_is_pending logic
MAINTAINERS: update KVM/s390 maintainers
MAINTAINERS: add Halil as additional vfio-ccw maintainer
MAINTAINERS: add David as a reviewer for KVM/s390
...
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/crypto/ccp/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/crypto/ccp/Makefile | 1 | ||||
| -rw-r--r-- | drivers/crypto/ccp/psp-dev.c | 805 | ||||
| -rw-r--r-- | drivers/crypto/ccp/psp-dev.h | 83 | ||||
| -rw-r--r-- | drivers/crypto/ccp/sp-dev.c | 35 | ||||
| -rw-r--r-- | drivers/crypto/ccp/sp-dev.h | 28 | ||||
| -rw-r--r-- | drivers/crypto/ccp/sp-pci.c | 52 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_early.c | 3 |
8 files changed, 1017 insertions, 2 deletions
diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index 6d626606b9c5..b9dfae47aefd 100644 --- a/drivers/crypto/ccp/Kconfig +++ b/drivers/crypto/ccp/Kconfig | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | config CRYPTO_DEV_CCP_DD | 1 | config CRYPTO_DEV_CCP_DD |
| 2 | tristate "Secure Processor device driver" | 2 | tristate "Secure Processor device driver" |
| 3 | depends on CPU_SUP_AMD || ARM64 | ||
| 3 | default m | 4 | default m |
| 4 | help | 5 | help |
| 5 | Provides AMD Secure Processor device driver. | 6 | Provides AMD Secure Processor device driver. |
| @@ -32,3 +33,14 @@ config CRYPTO_DEV_CCP_CRYPTO | |||
| 32 | Support for using the cryptographic API with the AMD Cryptographic | 33 | Support for using the cryptographic API with the AMD Cryptographic |
| 33 | Coprocessor. This module supports offload of SHA and AES algorithms. | 34 | Coprocessor. This module supports offload of SHA and AES algorithms. |
| 34 | If you choose 'M' here, this module will be called ccp_crypto. | 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. | ||
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index c4ce726b931e..51d1c0cf66c7 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile | |||
| @@ -8,6 +8,7 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \ | |||
| 8 | ccp-dmaengine.o \ | 8 | ccp-dmaengine.o \ |
| 9 | ccp-debugfs.o | 9 | ccp-debugfs.o |
| 10 | ccp-$(CONFIG_PCI) += sp-pci.o | 10 | ccp-$(CONFIG_PCI) += sp-pci.o |
| 11 | ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o | ||
| 11 | 12 | ||
| 12 | obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o | 13 | obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o |
| 13 | ccp-crypto-objs := ccp-crypto-main.o \ | 14 | 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..fcfa5b1eae61 --- /dev/null +++ b/drivers/crypto/ccp/psp-dev.c | |||
| @@ -0,0 +1,805 @@ | |||
| 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 | #define DEVICE_NAME "sev" | ||
| 30 | |||
| 31 | static DEFINE_MUTEX(sev_cmd_mutex); | ||
| 32 | static struct sev_misc_dev *misc_dev; | ||
| 33 | static struct psp_device *psp_master; | ||
| 34 | |||
| 35 | static struct psp_device *psp_alloc_struct(struct sp_device *sp) | ||
| 36 | { | ||
| 37 | struct device *dev = sp->dev; | ||
| 38 | struct psp_device *psp; | ||
| 39 | |||
| 40 | psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL); | ||
| 41 | if (!psp) | ||
| 42 | return NULL; | ||
| 43 | |||
| 44 | psp->dev = dev; | ||
| 45 | psp->sp = sp; | ||
| 46 | |||
| 47 | snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord); | ||
| 48 | |||
| 49 | return psp; | ||
| 50 | } | ||
| 51 | |||
| 52 | static irqreturn_t psp_irq_handler(int irq, void *data) | ||
| 53 | { | ||
| 54 | struct psp_device *psp = data; | ||
| 55 | unsigned int status; | ||
| 56 | int reg; | ||
| 57 | |||
| 58 | /* Read the interrupt status: */ | ||
| 59 | status = ioread32(psp->io_regs + PSP_P2CMSG_INTSTS); | ||
| 60 | |||
| 61 | /* Check if it is command completion: */ | ||
| 62 | if (!(status & BIT(PSP_CMD_COMPLETE_REG))) | ||
| 63 | goto done; | ||
| 64 | |||
| 65 | /* Check if it is SEV command completion: */ | ||
| 66 | reg = ioread32(psp->io_regs + PSP_CMDRESP); | ||
| 67 | if (reg & PSP_CMDRESP_RESP) { | ||
| 68 | psp->sev_int_rcvd = 1; | ||
| 69 | wake_up(&psp->sev_int_queue); | ||
| 70 | } | ||
| 71 | |||
| 72 | done: | ||
| 73 | /* Clear the interrupt status by writing the same value we read. */ | ||
| 74 | iowrite32(status, psp->io_regs + PSP_P2CMSG_INTSTS); | ||
| 75 | |||
| 76 | return IRQ_HANDLED; | ||
| 77 | } | ||
| 78 | |||
| 79 | static void sev_wait_cmd_ioc(struct psp_device *psp, unsigned int *reg) | ||
| 80 | { | ||
| 81 | psp->sev_int_rcvd = 0; | ||
| 82 | |||
| 83 | wait_event(psp->sev_int_queue, psp->sev_int_rcvd); | ||
| 84 | *reg = ioread32(psp->io_regs + PSP_CMDRESP); | ||
| 85 | } | ||
| 86 | |||
| 87 | static int sev_cmd_buffer_len(int cmd) | ||
| 88 | { | ||
| 89 | switch (cmd) { | ||
| 90 | case SEV_CMD_INIT: return sizeof(struct sev_data_init); | ||
| 91 | case SEV_CMD_PLATFORM_STATUS: return sizeof(struct sev_user_data_status); | ||
| 92 | case SEV_CMD_PEK_CSR: return sizeof(struct sev_data_pek_csr); | ||
| 93 | case SEV_CMD_PEK_CERT_IMPORT: return sizeof(struct sev_data_pek_cert_import); | ||
| 94 | case SEV_CMD_PDH_CERT_EXPORT: return sizeof(struct sev_data_pdh_cert_export); | ||
| 95 | case SEV_CMD_LAUNCH_START: return sizeof(struct sev_data_launch_start); | ||
| 96 | case SEV_CMD_LAUNCH_UPDATE_DATA: return sizeof(struct sev_data_launch_update_data); | ||
| 97 | case SEV_CMD_LAUNCH_UPDATE_VMSA: return sizeof(struct sev_data_launch_update_vmsa); | ||
| 98 | case SEV_CMD_LAUNCH_FINISH: return sizeof(struct sev_data_launch_finish); | ||
| 99 | case SEV_CMD_LAUNCH_MEASURE: return sizeof(struct sev_data_launch_measure); | ||
| 100 | case SEV_CMD_ACTIVATE: return sizeof(struct sev_data_activate); | ||
| 101 | case SEV_CMD_DEACTIVATE: return sizeof(struct sev_data_deactivate); | ||
| 102 | case SEV_CMD_DECOMMISSION: return sizeof(struct sev_data_decommission); | ||
| 103 | case SEV_CMD_GUEST_STATUS: return sizeof(struct sev_data_guest_status); | ||
| 104 | case SEV_CMD_DBG_DECRYPT: return sizeof(struct sev_data_dbg); | ||
| 105 | case SEV_CMD_DBG_ENCRYPT: return sizeof(struct sev_data_dbg); | ||
| 106 | case SEV_CMD_SEND_START: return sizeof(struct sev_data_send_start); | ||
| 107 | case SEV_CMD_SEND_UPDATE_DATA: return sizeof(struct sev_data_send_update_data); | ||
| 108 | case SEV_CMD_SEND_UPDATE_VMSA: return sizeof(struct sev_data_send_update_vmsa); | ||
| 109 | case SEV_CMD_SEND_FINISH: return sizeof(struct sev_data_send_finish); | ||
| 110 | case SEV_CMD_RECEIVE_START: return sizeof(struct sev_data_receive_start); | ||
| 111 | case SEV_CMD_RECEIVE_FINISH: return sizeof(struct sev_data_receive_finish); | ||
| 112 | case SEV_CMD_RECEIVE_UPDATE_DATA: return sizeof(struct sev_data_receive_update_data); | ||
| 113 | case SEV_CMD_RECEIVE_UPDATE_VMSA: return sizeof(struct sev_data_receive_update_vmsa); | ||
| 114 | case SEV_CMD_LAUNCH_UPDATE_SECRET: return sizeof(struct sev_data_launch_secret); | ||
| 115 | default: return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) | ||
| 122 | { | ||
| 123 | struct psp_device *psp = psp_master; | ||
| 124 | unsigned int phys_lsb, phys_msb; | ||
| 125 | unsigned int reg, ret = 0; | ||
| 126 | |||
| 127 | if (!psp) | ||
| 128 | return -ENODEV; | ||
| 129 | |||
| 130 | /* Get the physical address of the command buffer */ | ||
| 131 | phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0; | ||
| 132 | phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0; | ||
| 133 | |||
| 134 | dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x\n", | ||
| 135 | cmd, phys_msb, phys_lsb); | ||
| 136 | |||
| 137 | print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data, | ||
| 138 | sev_cmd_buffer_len(cmd), false); | ||
| 139 | |||
| 140 | iowrite32(phys_lsb, psp->io_regs + PSP_CMDBUFF_ADDR_LO); | ||
| 141 | iowrite32(phys_msb, psp->io_regs + PSP_CMDBUFF_ADDR_HI); | ||
| 142 | |||
| 143 | reg = cmd; | ||
| 144 | reg <<= PSP_CMDRESP_CMD_SHIFT; | ||
| 145 | reg |= PSP_CMDRESP_IOC; | ||
| 146 | iowrite32(reg, psp->io_regs + PSP_CMDRESP); | ||
| 147 | |||
| 148 | /* wait for command completion */ | ||
| 149 | sev_wait_cmd_ioc(psp, ®); | ||
| 150 | |||
| 151 | if (psp_ret) | ||
| 152 | *psp_ret = reg & PSP_CMDRESP_ERR_MASK; | ||
| 153 | |||
| 154 | if (reg & PSP_CMDRESP_ERR_MASK) { | ||
| 155 | dev_dbg(psp->dev, "sev command %#x failed (%#010x)\n", | ||
| 156 | cmd, reg & PSP_CMDRESP_ERR_MASK); | ||
| 157 | ret = -EIO; | ||
| 158 | } | ||
| 159 | |||
| 160 | print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data, | ||
| 161 | sev_cmd_buffer_len(cmd), false); | ||
| 162 | |||
| 163 | return ret; | ||
| 164 | } | ||
| 165 | |||
| 166 | static int sev_do_cmd(int cmd, void *data, int *psp_ret) | ||
| 167 | { | ||
| 168 | int rc; | ||
| 169 | |||
| 170 | mutex_lock(&sev_cmd_mutex); | ||
| 171 | rc = __sev_do_cmd_locked(cmd, data, psp_ret); | ||
| 172 | mutex_unlock(&sev_cmd_mutex); | ||
| 173 | |||
| 174 | return rc; | ||
| 175 | } | ||
| 176 | |||
| 177 | static int __sev_platform_init_locked(int *error) | ||
| 178 | { | ||
| 179 | struct psp_device *psp = psp_master; | ||
| 180 | int rc = 0; | ||
| 181 | |||
| 182 | if (!psp) | ||
| 183 | return -ENODEV; | ||
| 184 | |||
| 185 | if (psp->sev_state == SEV_STATE_INIT) | ||
| 186 | return 0; | ||
| 187 | |||
| 188 | rc = __sev_do_cmd_locked(SEV_CMD_INIT, &psp->init_cmd_buf, error); | ||
| 189 | if (rc) | ||
| 190 | return rc; | ||
| 191 | |||
| 192 | psp->sev_state = SEV_STATE_INIT; | ||
| 193 | dev_dbg(psp->dev, "SEV firmware initialized\n"); | ||
| 194 | |||
| 195 | return rc; | ||
| 196 | } | ||
| 197 | |||
| 198 | int sev_platform_init(int *error) | ||
| 199 | { | ||
| 200 | int rc; | ||
| 201 | |||
| 202 | mutex_lock(&sev_cmd_mutex); | ||
| 203 | rc = __sev_platform_init_locked(error); | ||
| 204 | mutex_unlock(&sev_cmd_mutex); | ||
| 205 | |||
| 206 | return rc; | ||
| 207 | } | ||
| 208 | EXPORT_SYMBOL_GPL(sev_platform_init); | ||
| 209 | |||
| 210 | static int __sev_platform_shutdown_locked(int *error) | ||
| 211 | { | ||
| 212 | int ret; | ||
| 213 | |||
| 214 | ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, 0, error); | ||
| 215 | if (ret) | ||
| 216 | return ret; | ||
| 217 | |||
| 218 | psp_master->sev_state = SEV_STATE_UNINIT; | ||
| 219 | dev_dbg(psp_master->dev, "SEV firmware shutdown\n"); | ||
| 220 | |||
| 221 | return ret; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int sev_platform_shutdown(int *error) | ||
| 225 | { | ||
| 226 | int rc; | ||
| 227 | |||
| 228 | mutex_lock(&sev_cmd_mutex); | ||
| 229 | rc = __sev_platform_shutdown_locked(NULL); | ||
| 230 | mutex_unlock(&sev_cmd_mutex); | ||
| 231 | |||
| 232 | return rc; | ||
| 233 | } | ||
| 234 | |||
| 235 | static int sev_get_platform_state(int *state, int *error) | ||
| 236 | { | ||
| 237 | int rc; | ||
| 238 | |||
| 239 | rc = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, | ||
| 240 | &psp_master->status_cmd_buf, error); | ||
| 241 | if (rc) | ||
| 242 | return rc; | ||
| 243 | |||
| 244 | *state = psp_master->status_cmd_buf.state; | ||
| 245 | return rc; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int sev_ioctl_do_reset(struct sev_issue_cmd *argp) | ||
| 249 | { | ||
| 250 | int state, rc; | ||
| 251 | |||
| 252 | /* | ||
| 253 | * The SEV spec requires that FACTORY_RESET must be issued in | ||
| 254 | * UNINIT state. Before we go further lets check if any guest is | ||
| 255 | * active. | ||
| 256 | * | ||
| 257 | * If FW is in WORKING state then deny the request otherwise issue | ||
| 258 | * SHUTDOWN command do INIT -> UNINIT before issuing the FACTORY_RESET. | ||
| 259 | * | ||
| 260 | */ | ||
| 261 | rc = sev_get_platform_state(&state, &argp->error); | ||
| 262 | if (rc) | ||
| 263 | return rc; | ||
| 264 | |||
| 265 | if (state == SEV_STATE_WORKING) | ||
| 266 | return -EBUSY; | ||
| 267 | |||
| 268 | if (state == SEV_STATE_INIT) { | ||
| 269 | rc = __sev_platform_shutdown_locked(&argp->error); | ||
| 270 | if (rc) | ||
| 271 | return rc; | ||
| 272 | } | ||
| 273 | |||
| 274 | return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, 0, &argp->error); | ||
| 275 | } | ||
| 276 | |||
| 277 | static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) | ||
| 278 | { | ||
| 279 | struct sev_user_data_status *data = &psp_master->status_cmd_buf; | ||
| 280 | int ret; | ||
| 281 | |||
| 282 | ret = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, data, &argp->error); | ||
| 283 | if (ret) | ||
| 284 | return ret; | ||
| 285 | |||
| 286 | if (copy_to_user((void __user *)argp->data, data, sizeof(*data))) | ||
| 287 | ret = -EFAULT; | ||
| 288 | |||
| 289 | return ret; | ||
| 290 | } | ||
| 291 | |||
| 292 | static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp) | ||
| 293 | { | ||
| 294 | int rc; | ||
| 295 | |||
| 296 | if (psp_master->sev_state == SEV_STATE_UNINIT) { | ||
| 297 | rc = __sev_platform_init_locked(&argp->error); | ||
| 298 | if (rc) | ||
| 299 | return rc; | ||
| 300 | } | ||
| 301 | |||
| 302 | return __sev_do_cmd_locked(cmd, 0, &argp->error); | ||
| 303 | } | ||
| 304 | |||
| 305 | static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp) | ||
| 306 | { | ||
| 307 | struct sev_user_data_pek_csr input; | ||
| 308 | struct sev_data_pek_csr *data; | ||
| 309 | void *blob = NULL; | ||
| 310 | int ret; | ||
| 311 | |||
| 312 | if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) | ||
| 313 | return -EFAULT; | ||
| 314 | |||
| 315 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
| 316 | if (!data) | ||
| 317 | return -ENOMEM; | ||
| 318 | |||
| 319 | /* userspace wants to query CSR length */ | ||
| 320 | if (!input.address || !input.length) | ||
| 321 | goto cmd; | ||
| 322 | |||
| 323 | /* allocate a physically contiguous buffer to store the CSR blob */ | ||
| 324 | if (!access_ok(VERIFY_WRITE, input.address, input.length) || | ||
| 325 | input.length > SEV_FW_BLOB_MAX_SIZE) { | ||
| 326 | ret = -EFAULT; | ||
| 327 | goto e_free; | ||
| 328 | } | ||
| 329 | |||
| 330 | blob = kmalloc(input.length, GFP_KERNEL); | ||
| 331 | if (!blob) { | ||
| 332 | ret = -ENOMEM; | ||
| 333 | goto e_free; | ||
| 334 | } | ||
| 335 | |||
| 336 | data->address = __psp_pa(blob); | ||
| 337 | data->len = input.length; | ||
| 338 | |||
| 339 | cmd: | ||
| 340 | if (psp_master->sev_state == SEV_STATE_UNINIT) { | ||
| 341 | ret = __sev_platform_init_locked(&argp->error); | ||
| 342 | if (ret) | ||
| 343 | goto e_free_blob; | ||
| 344 | } | ||
| 345 | |||
| 346 | ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, data, &argp->error); | ||
| 347 | |||
| 348 | /* If we query the CSR length, FW responded with expected data. */ | ||
| 349 | input.length = data->len; | ||
| 350 | |||
| 351 | if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { | ||
| 352 | ret = -EFAULT; | ||
| 353 | goto e_free_blob; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (blob) { | ||
| 357 | if (copy_to_user((void __user *)input.address, blob, input.length)) | ||
| 358 | ret = -EFAULT; | ||
| 359 | } | ||
| 360 | |||
| 361 | e_free_blob: | ||
| 362 | kfree(blob); | ||
| 363 | e_free: | ||
| 364 | kfree(data); | ||
| 365 | return ret; | ||
| 366 | } | ||
| 367 | |||
| 368 | void *psp_copy_user_blob(u64 __user uaddr, u32 len) | ||
| 369 | { | ||
| 370 | void *data; | ||
| 371 | |||
| 372 | if (!uaddr || !len) | ||
| 373 | return ERR_PTR(-EINVAL); | ||
| 374 | |||
| 375 | /* verify that blob length does not exceed our limit */ | ||
| 376 | if (len > SEV_FW_BLOB_MAX_SIZE) | ||
| 377 | return ERR_PTR(-EINVAL); | ||
| 378 | |||
| 379 | data = kmalloc(len, GFP_KERNEL); | ||
| 380 | if (!data) | ||
| 381 | return ERR_PTR(-ENOMEM); | ||
| 382 | |||
| 383 | if (copy_from_user(data, (void __user *)(uintptr_t)uaddr, len)) | ||
| 384 | goto e_free; | ||
| 385 | |||
| 386 | return data; | ||
| 387 | |||
| 388 | e_free: | ||
| 389 | kfree(data); | ||
| 390 | return ERR_PTR(-EFAULT); | ||
| 391 | } | ||
| 392 | EXPORT_SYMBOL_GPL(psp_copy_user_blob); | ||
| 393 | |||
| 394 | static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp) | ||
| 395 | { | ||
| 396 | struct sev_user_data_pek_cert_import input; | ||
| 397 | struct sev_data_pek_cert_import *data; | ||
| 398 | void *pek_blob, *oca_blob; | ||
| 399 | int ret; | ||
| 400 | |||
| 401 | if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) | ||
| 402 | return -EFAULT; | ||
| 403 | |||
| 404 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
| 405 | if (!data) | ||
| 406 | return -ENOMEM; | ||
| 407 | |||
| 408 | /* copy PEK certificate blobs from userspace */ | ||
| 409 | pek_blob = psp_copy_user_blob(input.pek_cert_address, input.pek_cert_len); | ||
| 410 | if (IS_ERR(pek_blob)) { | ||
| 411 | ret = PTR_ERR(pek_blob); | ||
| 412 | goto e_free; | ||
| 413 | } | ||
| 414 | |||
| 415 | data->pek_cert_address = __psp_pa(pek_blob); | ||
| 416 | data->pek_cert_len = input.pek_cert_len; | ||
| 417 | |||
| 418 | /* copy PEK certificate blobs from userspace */ | ||
| 419 | oca_blob = psp_copy_user_blob(input.oca_cert_address, input.oca_cert_len); | ||
| 420 | if (IS_ERR(oca_blob)) { | ||
| 421 | ret = PTR_ERR(oca_blob); | ||
| 422 | goto e_free_pek; | ||
| 423 | } | ||
| 424 | |||
| 425 | data->oca_cert_address = __psp_pa(oca_blob); | ||
| 426 | data->oca_cert_len = input.oca_cert_len; | ||
| 427 | |||
| 428 | /* If platform is not in INIT state then transition it to INIT */ | ||
| 429 | if (psp_master->sev_state != SEV_STATE_INIT) { | ||
| 430 | ret = __sev_platform_init_locked(&argp->error); | ||
| 431 | if (ret) | ||
| 432 | goto e_free_oca; | ||
| 433 | } | ||
| 434 | |||
| 435 | ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, data, &argp->error); | ||
| 436 | |||
| 437 | e_free_oca: | ||
| 438 | kfree(oca_blob); | ||
| 439 | e_free_pek: | ||
| 440 | kfree(pek_blob); | ||
| 441 | e_free: | ||
| 442 | kfree(data); | ||
| 443 | return ret; | ||
| 444 | } | ||
| 445 | |||
| 446 | static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp) | ||
| 447 | { | ||
| 448 | struct sev_user_data_pdh_cert_export input; | ||
| 449 | void *pdh_blob = NULL, *cert_blob = NULL; | ||
| 450 | struct sev_data_pdh_cert_export *data; | ||
| 451 | int ret; | ||
| 452 | |||
| 453 | if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) | ||
| 454 | return -EFAULT; | ||
| 455 | |||
| 456 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
| 457 | if (!data) | ||
| 458 | return -ENOMEM; | ||
| 459 | |||
| 460 | /* Userspace wants to query the certificate length. */ | ||
| 461 | if (!input.pdh_cert_address || | ||
| 462 | !input.pdh_cert_len || | ||
| 463 | !input.cert_chain_address) | ||
| 464 | goto cmd; | ||
| 465 | |||
| 466 | /* Allocate a physically contiguous buffer to store the PDH blob. */ | ||
| 467 | if ((input.pdh_cert_len > SEV_FW_BLOB_MAX_SIZE) || | ||
| 468 | !access_ok(VERIFY_WRITE, input.pdh_cert_address, input.pdh_cert_len)) { | ||
| 469 | ret = -EFAULT; | ||
| 470 | goto e_free; | ||
| 471 | } | ||
| 472 | |||
| 473 | /* Allocate a physically contiguous buffer to store the cert chain blob. */ | ||
| 474 | if ((input.cert_chain_len > SEV_FW_BLOB_MAX_SIZE) || | ||
| 475 | !access_ok(VERIFY_WRITE, input.cert_chain_address, input.cert_chain_len)) { | ||
| 476 | ret = -EFAULT; | ||
| 477 | goto e_free; | ||
| 478 | } | ||
| 479 | |||
| 480 | pdh_blob = kmalloc(input.pdh_cert_len, GFP_KERNEL); | ||
| 481 | if (!pdh_blob) { | ||
| 482 | ret = -ENOMEM; | ||
| 483 | goto e_free; | ||
| 484 | } | ||
| 485 | |||
| 486 | data->pdh_cert_address = __psp_pa(pdh_blob); | ||
| 487 | data->pdh_cert_len = input.pdh_cert_len; | ||
| 488 | |||
| 489 | cert_blob = kmalloc(input.cert_chain_len, GFP_KERNEL); | ||
| 490 | if (!cert_blob) { | ||
| 491 | ret = -ENOMEM; | ||
| 492 | goto e_free_pdh; | ||
| 493 | } | ||
| 494 | |||
| 495 | data->cert_chain_address = __psp_pa(cert_blob); | ||
| 496 | data->cert_chain_len = input.cert_chain_len; | ||
| 497 | |||
| 498 | cmd: | ||
| 499 | /* If platform is not in INIT state then transition it to INIT. */ | ||
| 500 | if (psp_master->sev_state != SEV_STATE_INIT) { | ||
| 501 | ret = __sev_platform_init_locked(&argp->error); | ||
| 502 | if (ret) | ||
| 503 | goto e_free_cert; | ||
| 504 | } | ||
| 505 | |||
| 506 | ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, data, &argp->error); | ||
| 507 | |||
| 508 | /* If we query the length, FW responded with expected data. */ | ||
| 509 | input.cert_chain_len = data->cert_chain_len; | ||
| 510 | input.pdh_cert_len = data->pdh_cert_len; | ||
| 511 | |||
| 512 | if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { | ||
| 513 | ret = -EFAULT; | ||
| 514 | goto e_free_cert; | ||
| 515 | } | ||
| 516 | |||
| 517 | if (pdh_blob) { | ||
| 518 | if (copy_to_user((void __user *)input.pdh_cert_address, | ||
| 519 | pdh_blob, input.pdh_cert_len)) { | ||
| 520 | ret = -EFAULT; | ||
| 521 | goto e_free_cert; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | if (cert_blob) { | ||
| 526 | if (copy_to_user((void __user *)input.cert_chain_address, | ||
| 527 | cert_blob, input.cert_chain_len)) | ||
| 528 | ret = -EFAULT; | ||
| 529 | } | ||
| 530 | |||
| 531 | e_free_cert: | ||
| 532 | kfree(cert_blob); | ||
| 533 | e_free_pdh: | ||
| 534 | kfree(pdh_blob); | ||
| 535 | e_free: | ||
| 536 | kfree(data); | ||
| 537 | return ret; | ||
| 538 | } | ||
| 539 | |||
| 540 | static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) | ||
| 541 | { | ||
| 542 | void __user *argp = (void __user *)arg; | ||
| 543 | struct sev_issue_cmd input; | ||
| 544 | int ret = -EFAULT; | ||
| 545 | |||
| 546 | if (!psp_master) | ||
| 547 | return -ENODEV; | ||
| 548 | |||
| 549 | if (ioctl != SEV_ISSUE_CMD) | ||
| 550 | return -EINVAL; | ||
| 551 | |||
| 552 | if (copy_from_user(&input, argp, sizeof(struct sev_issue_cmd))) | ||
| 553 | return -EFAULT; | ||
| 554 | |||
| 555 | if (input.cmd > SEV_MAX) | ||
| 556 | return -EINVAL; | ||
| 557 | |||
| 558 | mutex_lock(&sev_cmd_mutex); | ||
| 559 | |||
| 560 | switch (input.cmd) { | ||
| 561 | |||
| 562 | case SEV_FACTORY_RESET: | ||
| 563 | ret = sev_ioctl_do_reset(&input); | ||
| 564 | break; | ||
| 565 | case SEV_PLATFORM_STATUS: | ||
| 566 | ret = sev_ioctl_do_platform_status(&input); | ||
| 567 | break; | ||
| 568 | case SEV_PEK_GEN: | ||
| 569 | ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PEK_GEN, &input); | ||
| 570 | break; | ||
| 571 | case SEV_PDH_GEN: | ||
| 572 | ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input); | ||
| 573 | break; | ||
| 574 | case SEV_PEK_CSR: | ||
| 575 | ret = sev_ioctl_do_pek_csr(&input); | ||
| 576 | break; | ||
| 577 | case SEV_PEK_CERT_IMPORT: | ||
| 578 | ret = sev_ioctl_do_pek_import(&input); | ||
| 579 | break; | ||
| 580 | case SEV_PDH_CERT_EXPORT: | ||
| 581 | ret = sev_ioctl_do_pdh_export(&input); | ||
| 582 | break; | ||
| 583 | default: | ||
| 584 | ret = -EINVAL; | ||
| 585 | goto out; | ||
| 586 | } | ||
| 587 | |||
| 588 | if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd))) | ||
| 589 | ret = -EFAULT; | ||
| 590 | out: | ||
| 591 | mutex_unlock(&sev_cmd_mutex); | ||
| 592 | |||
| 593 | return ret; | ||
| 594 | } | ||
| 595 | |||
| 596 | static const struct file_operations sev_fops = { | ||
| 597 | .owner = THIS_MODULE, | ||
| 598 | .unlocked_ioctl = sev_ioctl, | ||
| 599 | }; | ||
| 600 | |||
| 601 | int sev_platform_status(struct sev_user_data_status *data, int *error) | ||
| 602 | { | ||
| 603 | return sev_do_cmd(SEV_CMD_PLATFORM_STATUS, data, error); | ||
| 604 | } | ||
| 605 | EXPORT_SYMBOL_GPL(sev_platform_status); | ||
| 606 | |||
| 607 | int sev_guest_deactivate(struct sev_data_deactivate *data, int *error) | ||
| 608 | { | ||
| 609 | return sev_do_cmd(SEV_CMD_DEACTIVATE, data, error); | ||
| 610 | } | ||
| 611 | EXPORT_SYMBOL_GPL(sev_guest_deactivate); | ||
| 612 | |||
| 613 | int sev_guest_activate(struct sev_data_activate *data, int *error) | ||
| 614 | { | ||
| 615 | return sev_do_cmd(SEV_CMD_ACTIVATE, data, error); | ||
| 616 | } | ||
| 617 | EXPORT_SYMBOL_GPL(sev_guest_activate); | ||
| 618 | |||
| 619 | int sev_guest_decommission(struct sev_data_decommission *data, int *error) | ||
| 620 | { | ||
| 621 | return sev_do_cmd(SEV_CMD_DECOMMISSION, data, error); | ||
| 622 | } | ||
| 623 | EXPORT_SYMBOL_GPL(sev_guest_decommission); | ||
| 624 | |||
| 625 | int sev_guest_df_flush(int *error) | ||
| 626 | { | ||
| 627 | return sev_do_cmd(SEV_CMD_DF_FLUSH, 0, error); | ||
| 628 | } | ||
| 629 | EXPORT_SYMBOL_GPL(sev_guest_df_flush); | ||
| 630 | |||
| 631 | static void sev_exit(struct kref *ref) | ||
| 632 | { | ||
| 633 | struct sev_misc_dev *misc_dev = container_of(ref, struct sev_misc_dev, refcount); | ||
| 634 | |||
| 635 | misc_deregister(&misc_dev->misc); | ||
| 636 | } | ||
| 637 | |||
| 638 | static int sev_misc_init(struct psp_device *psp) | ||
| 639 | { | ||
| 640 | struct device *dev = psp->dev; | ||
| 641 | int ret; | ||
| 642 | |||
| 643 | /* | ||
| 644 | * SEV feature support can be detected on multiple devices but the SEV | ||
| 645 | * FW commands must be issued on the master. During probe, we do not | ||
| 646 | * know the master hence we create /dev/sev on the first device probe. | ||
| 647 | * sev_do_cmd() finds the right master device to which to issue the | ||
| 648 | * command to the firmware. | ||
| 649 | */ | ||
| 650 | if (!misc_dev) { | ||
| 651 | struct miscdevice *misc; | ||
| 652 | |||
| 653 | misc_dev = devm_kzalloc(dev, sizeof(*misc_dev), GFP_KERNEL); | ||
| 654 | if (!misc_dev) | ||
| 655 | return -ENOMEM; | ||
| 656 | |||
| 657 | misc = &misc_dev->misc; | ||
| 658 | misc->minor = MISC_DYNAMIC_MINOR; | ||
| 659 | misc->name = DEVICE_NAME; | ||
| 660 | misc->fops = &sev_fops; | ||
| 661 | |||
| 662 | ret = misc_register(misc); | ||
| 663 | if (ret) | ||
| 664 | return ret; | ||
| 665 | |||
| 666 | kref_init(&misc_dev->refcount); | ||
| 667 | } else { | ||
| 668 | kref_get(&misc_dev->refcount); | ||
| 669 | } | ||
| 670 | |||
| 671 | init_waitqueue_head(&psp->sev_int_queue); | ||
| 672 | psp->sev_misc = misc_dev; | ||
| 673 | dev_dbg(dev, "registered SEV device\n"); | ||
| 674 | |||
| 675 | return 0; | ||
| 676 | } | ||
| 677 | |||
| 678 | static int sev_init(struct psp_device *psp) | ||
| 679 | { | ||
| 680 | /* Check if device supports SEV feature */ | ||
| 681 | if (!(ioread32(psp->io_regs + PSP_FEATURE_REG) & 1)) { | ||
| 682 | dev_dbg(psp->dev, "device does not support SEV\n"); | ||
| 683 | return 1; | ||
| 684 | } | ||
| 685 | |||
| 686 | return sev_misc_init(psp); | ||
| 687 | } | ||
| 688 | |||
| 689 | int psp_dev_init(struct sp_device *sp) | ||
| 690 | { | ||
| 691 | struct device *dev = sp->dev; | ||
| 692 | struct psp_device *psp; | ||
| 693 | int ret; | ||
| 694 | |||
| 695 | ret = -ENOMEM; | ||
| 696 | psp = psp_alloc_struct(sp); | ||
| 697 | if (!psp) | ||
| 698 | goto e_err; | ||
| 699 | |||
| 700 | sp->psp_data = psp; | ||
| 701 | |||
| 702 | psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata; | ||
| 703 | if (!psp->vdata) { | ||
| 704 | ret = -ENODEV; | ||
| 705 | dev_err(dev, "missing driver data\n"); | ||
| 706 | goto e_err; | ||
| 707 | } | ||
| 708 | |||
| 709 | psp->io_regs = sp->io_map + psp->vdata->offset; | ||
| 710 | |||
| 711 | /* Disable and clear interrupts until ready */ | ||
| 712 | iowrite32(0, psp->io_regs + PSP_P2CMSG_INTEN); | ||
| 713 | iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTSTS); | ||
| 714 | |||
| 715 | /* Request an irq */ | ||
| 716 | ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp); | ||
| 717 | if (ret) { | ||
| 718 | dev_err(dev, "psp: unable to allocate an IRQ\n"); | ||
| 719 | goto e_err; | ||
| 720 | } | ||
| 721 | |||
| 722 | ret = sev_init(psp); | ||
| 723 | if (ret) | ||
| 724 | goto e_irq; | ||
| 725 | |||
| 726 | if (sp->set_psp_master_device) | ||
| 727 | sp->set_psp_master_device(sp); | ||
| 728 | |||
| 729 | /* Enable interrupt */ | ||
| 730 | iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN); | ||
| 731 | |||
| 732 | return 0; | ||
| 733 | |||
| 734 | e_irq: | ||
| 735 | sp_free_psp_irq(psp->sp, psp); | ||
| 736 | e_err: | ||
| 737 | sp->psp_data = NULL; | ||
| 738 | |||
| 739 | dev_notice(dev, "psp initialization failed\n"); | ||
| 740 | |||
| 741 | return ret; | ||
| 742 | } | ||
| 743 | |||
| 744 | void psp_dev_destroy(struct sp_device *sp) | ||
| 745 | { | ||
| 746 | struct psp_device *psp = sp->psp_data; | ||
| 747 | |||
| 748 | if (psp->sev_misc) | ||
| 749 | kref_put(&misc_dev->refcount, sev_exit); | ||
| 750 | |||
| 751 | sp_free_psp_irq(sp, psp); | ||
| 752 | } | ||
| 753 | |||
| 754 | int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd, | ||
| 755 | void *data, int *error) | ||
| 756 | { | ||
| 757 | if (!filep || filep->f_op != &sev_fops) | ||
| 758 | return -EBADF; | ||
| 759 | |||
| 760 | return sev_do_cmd(cmd, data, error); | ||
| 761 | } | ||
| 762 | EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user); | ||
| 763 | |||
| 764 | void psp_pci_init(void) | ||
| 765 | { | ||
| 766 | struct sev_user_data_status *status; | ||
| 767 | struct sp_device *sp; | ||
| 768 | int error, rc; | ||
| 769 | |||
| 770 | sp = sp_get_psp_master_device(); | ||
| 771 | if (!sp) | ||
| 772 | return; | ||
| 773 | |||
| 774 | psp_master = sp->psp_data; | ||
| 775 | |||
| 776 | /* Initialize the platform */ | ||
| 777 | rc = sev_platform_init(&error); | ||
| 778 | if (rc) { | ||
| 779 | dev_err(sp->dev, "SEV: failed to INIT error %#x\n", error); | ||
| 780 | goto err; | ||
| 781 | } | ||
| 782 | |||
| 783 | /* Display SEV firmware version */ | ||
| 784 | status = &psp_master->status_cmd_buf; | ||
| 785 | rc = sev_platform_status(status, &error); | ||
| 786 | if (rc) { | ||
| 787 | dev_err(sp->dev, "SEV: failed to get status error %#x\n", error); | ||
| 788 | goto err; | ||
| 789 | } | ||
| 790 | |||
| 791 | dev_info(sp->dev, "SEV API:%d.%d build:%d\n", status->api_major, | ||
| 792 | status->api_minor, status->build); | ||
| 793 | return; | ||
| 794 | |||
| 795 | err: | ||
| 796 | psp_master = NULL; | ||
| 797 | } | ||
| 798 | |||
| 799 | void psp_pci_exit(void) | ||
| 800 | { | ||
| 801 | if (!psp_master) | ||
| 802 | return; | ||
| 803 | |||
| 804 | sev_platform_shutdown(NULL); | ||
| 805 | } | ||
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h new file mode 100644 index 000000000000..c81f0b11287a --- /dev/null +++ b/drivers/crypto/ccp/psp-dev.h | |||
| @@ -0,0 +1,83 @@ | |||
| 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 | #include <linux/psp-sev.h> | ||
| 29 | #include <linux/miscdevice.h> | ||
| 30 | |||
| 31 | #include "sp-dev.h" | ||
| 32 | |||
| 33 | #define PSP_C2PMSG(_num) ((_num) << 2) | ||
| 34 | #define PSP_CMDRESP PSP_C2PMSG(32) | ||
| 35 | #define PSP_CMDBUFF_ADDR_LO PSP_C2PMSG(56) | ||
| 36 | #define PSP_CMDBUFF_ADDR_HI PSP_C2PMSG(57) | ||
| 37 | #define PSP_FEATURE_REG PSP_C2PMSG(63) | ||
| 38 | |||
| 39 | #define PSP_P2CMSG(_num) ((_num) << 2) | ||
| 40 | #define PSP_CMD_COMPLETE_REG 1 | ||
| 41 | #define PSP_CMD_COMPLETE PSP_P2CMSG(PSP_CMD_COMPLETE_REG) | ||
| 42 | |||
| 43 | #define PSP_P2CMSG_INTEN 0x0110 | ||
| 44 | #define PSP_P2CMSG_INTSTS 0x0114 | ||
| 45 | |||
| 46 | #define PSP_C2PMSG_ATTR_0 0x0118 | ||
| 47 | #define PSP_C2PMSG_ATTR_1 0x011c | ||
| 48 | #define PSP_C2PMSG_ATTR_2 0x0120 | ||
| 49 | #define PSP_C2PMSG_ATTR_3 0x0124 | ||
| 50 | #define PSP_P2CMSG_ATTR_0 0x0128 | ||
| 51 | |||
| 52 | #define PSP_CMDRESP_CMD_SHIFT 16 | ||
| 53 | #define PSP_CMDRESP_IOC BIT(0) | ||
| 54 | #define PSP_CMDRESP_RESP BIT(31) | ||
| 55 | #define PSP_CMDRESP_ERR_MASK 0xffff | ||
| 56 | |||
| 57 | #define MAX_PSP_NAME_LEN 16 | ||
| 58 | |||
| 59 | struct sev_misc_dev { | ||
| 60 | struct kref refcount; | ||
| 61 | struct miscdevice misc; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct psp_device { | ||
| 65 | struct list_head entry; | ||
| 66 | |||
| 67 | struct psp_vdata *vdata; | ||
| 68 | char name[MAX_PSP_NAME_LEN]; | ||
| 69 | |||
| 70 | struct device *dev; | ||
| 71 | struct sp_device *sp; | ||
| 72 | |||
| 73 | void __iomem *io_regs; | ||
| 74 | |||
| 75 | int sev_state; | ||
| 76 | unsigned int sev_int_rcvd; | ||
| 77 | wait_queue_head_t sev_int_queue; | ||
| 78 | struct sev_misc_dev *sev_misc; | ||
| 79 | struct sev_user_data_status status_cmd_buf; | ||
| 80 | struct sev_data_init init_cmd_buf; | ||
| 81 | }; | ||
| 82 | |||
| 83 | #endif /* __PSP_DEV_H */ | ||
diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c index bef387c8abfd..eb0da6572720 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) | |||
| 198 | if (sp->dev_vdata->ccp_vdata) | 198 | if (sp->dev_vdata->ccp_vdata) |
| 199 | ccp_dev_init(sp); | 199 | ccp_dev_init(sp); |
| 200 | 200 | ||
| 201 | if (sp->dev_vdata->psp_vdata) | ||
| 202 | psp_dev_init(sp); | ||
| 201 | return 0; | 203 | return 0; |
| 202 | } | 204 | } |
| 203 | 205 | ||
| @@ -206,6 +208,9 @@ void sp_destroy(struct sp_device *sp) | |||
| 206 | if (sp->dev_vdata->ccp_vdata) | 208 | if (sp->dev_vdata->ccp_vdata) |
| 207 | ccp_dev_destroy(sp); | 209 | ccp_dev_destroy(sp); |
| 208 | 210 | ||
| 211 | if (sp->dev_vdata->psp_vdata) | ||
| 212 | psp_dev_destroy(sp); | ||
| 213 | |||
| 209 | sp_del_device(sp); | 214 | sp_del_device(sp); |
| 210 | } | 215 | } |
| 211 | 216 | ||
| @@ -237,6 +242,27 @@ int sp_resume(struct sp_device *sp) | |||
| 237 | } | 242 | } |
| 238 | #endif | 243 | #endif |
| 239 | 244 | ||
| 245 | struct sp_device *sp_get_psp_master_device(void) | ||
| 246 | { | ||
| 247 | struct sp_device *i, *ret = NULL; | ||
| 248 | unsigned long flags; | ||
| 249 | |||
| 250 | write_lock_irqsave(&sp_unit_lock, flags); | ||
| 251 | if (list_empty(&sp_units)) | ||
| 252 | goto unlock; | ||
| 253 | |||
| 254 | list_for_each_entry(i, &sp_units, entry) { | ||
| 255 | if (i->psp_data) | ||
| 256 | break; | ||
| 257 | } | ||
| 258 | |||
| 259 | if (i->get_psp_master_device) | ||
| 260 | ret = i->get_psp_master_device(); | ||
| 261 | unlock: | ||
| 262 | write_unlock_irqrestore(&sp_unit_lock, flags); | ||
| 263 | return ret; | ||
| 264 | } | ||
| 265 | |||
| 240 | static int __init sp_mod_init(void) | 266 | static int __init sp_mod_init(void) |
| 241 | { | 267 | { |
| 242 | #ifdef CONFIG_X86 | 268 | #ifdef CONFIG_X86 |
| @@ -246,6 +272,10 @@ static int __init sp_mod_init(void) | |||
| 246 | if (ret) | 272 | if (ret) |
| 247 | return ret; | 273 | return ret; |
| 248 | 274 | ||
| 275 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | ||
| 276 | psp_pci_init(); | ||
| 277 | #endif | ||
| 278 | |||
| 249 | return 0; | 279 | return 0; |
| 250 | #endif | 280 | #endif |
| 251 | 281 | ||
| @@ -265,6 +295,11 @@ static int __init sp_mod_init(void) | |||
| 265 | static void __exit sp_mod_exit(void) | 295 | static void __exit sp_mod_exit(void) |
| 266 | { | 296 | { |
| 267 | #ifdef CONFIG_X86 | 297 | #ifdef CONFIG_X86 |
| 298 | |||
| 299 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | ||
| 300 | psp_pci_exit(); | ||
| 301 | #endif | ||
| 302 | |||
| 268 | sp_pci_exit(); | 303 | sp_pci_exit(); |
| 269 | #endif | 304 | #endif |
| 270 | 305 | ||
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 5ab486ade1ad..acb197b66ced 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h | |||
| @@ -42,12 +42,17 @@ struct ccp_vdata { | |||
| 42 | const unsigned int offset; | 42 | const unsigned int offset; |
| 43 | const unsigned int rsamax; | 43 | const unsigned int rsamax; |
| 44 | }; | 44 | }; |
| 45 | |||
| 46 | struct psp_vdata { | ||
| 47 | const unsigned int offset; | ||
| 48 | }; | ||
| 49 | |||
| 45 | /* Structure to hold SP device data */ | 50 | /* Structure to hold SP device data */ |
| 46 | struct sp_dev_vdata { | 51 | struct sp_dev_vdata { |
| 47 | const unsigned int bar; | 52 | const unsigned int bar; |
| 48 | 53 | ||
| 49 | const struct ccp_vdata *ccp_vdata; | 54 | const struct ccp_vdata *ccp_vdata; |
| 50 | void *psp_vdata; | 55 | const struct psp_vdata *psp_vdata; |
| 51 | }; | 56 | }; |
| 52 | 57 | ||
| 53 | struct sp_device { | 58 | struct sp_device { |
| @@ -68,6 +73,10 @@ struct sp_device { | |||
| 68 | /* DMA caching attribute support */ | 73 | /* DMA caching attribute support */ |
| 69 | unsigned int axcache; | 74 | unsigned int axcache; |
| 70 | 75 | ||
| 76 | /* get and set master device */ | ||
| 77 | struct sp_device*(*get_psp_master_device)(void); | ||
| 78 | void (*set_psp_master_device)(struct sp_device *); | ||
| 79 | |||
| 71 | bool irq_registered; | 80 | bool irq_registered; |
| 72 | bool use_tasklet; | 81 | bool use_tasklet; |
| 73 | 82 | ||
| @@ -103,6 +112,7 @@ void sp_free_ccp_irq(struct sp_device *sp, void *data); | |||
| 103 | int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler, | 112 | int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler, |
| 104 | const char *name, void *data); | 113 | const char *name, void *data); |
| 105 | void sp_free_psp_irq(struct sp_device *sp, void *data); | 114 | void sp_free_psp_irq(struct sp_device *sp, void *data); |
| 115 | struct sp_device *sp_get_psp_master_device(void); | ||
| 106 | 116 | ||
| 107 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP | 117 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP |
| 108 | 118 | ||
| @@ -130,4 +140,20 @@ static inline int ccp_dev_resume(struct sp_device *sp) | |||
| 130 | } | 140 | } |
| 131 | #endif /* CONFIG_CRYPTO_DEV_SP_CCP */ | 141 | #endif /* CONFIG_CRYPTO_DEV_SP_CCP */ |
| 132 | 142 | ||
| 143 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | ||
| 144 | |||
| 145 | int psp_dev_init(struct sp_device *sp); | ||
| 146 | void psp_pci_init(void); | ||
| 147 | void psp_dev_destroy(struct sp_device *sp); | ||
| 148 | void psp_pci_exit(void); | ||
| 149 | |||
| 150 | #else /* !CONFIG_CRYPTO_DEV_SP_PSP */ | ||
| 151 | |||
| 152 | static inline int psp_dev_init(struct sp_device *sp) { return 0; } | ||
| 153 | static inline void psp_pci_init(void) { } | ||
| 154 | static inline void psp_dev_destroy(struct sp_device *sp) { } | ||
| 155 | static inline void psp_pci_exit(void) { } | ||
| 156 | |||
| 157 | #endif /* CONFIG_CRYPTO_DEV_SP_PSP */ | ||
| 158 | |||
| 133 | #endif | 159 | #endif |
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 9859aa683a28..f5f43c50698a 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/ccp.h> | 25 | #include <linux/ccp.h> |
| 26 | 26 | ||
| 27 | #include "ccp-dev.h" | 27 | #include "ccp-dev.h" |
| 28 | #include "psp-dev.h" | ||
| 28 | 29 | ||
| 29 | #define MSIX_VECTORS 2 | 30 | #define MSIX_VECTORS 2 |
| 30 | 31 | ||
| @@ -32,6 +33,7 @@ struct sp_pci { | |||
| 32 | int msix_count; | 33 | int msix_count; |
| 33 | struct msix_entry msix_entry[MSIX_VECTORS]; | 34 | struct msix_entry msix_entry[MSIX_VECTORS]; |
| 34 | }; | 35 | }; |
| 36 | static struct sp_device *sp_dev_master; | ||
| 35 | 37 | ||
| 36 | static int sp_get_msix_irqs(struct sp_device *sp) | 38 | static int sp_get_msix_irqs(struct sp_device *sp) |
| 37 | { | 39 | { |
| @@ -108,6 +110,45 @@ static void sp_free_irqs(struct sp_device *sp) | |||
| 108 | sp->psp_irq = 0; | 110 | sp->psp_irq = 0; |
| 109 | } | 111 | } |
| 110 | 112 | ||
| 113 | static bool sp_pci_is_master(struct sp_device *sp) | ||
| 114 | { | ||
| 115 | struct device *dev_cur, *dev_new; | ||
| 116 | struct pci_dev *pdev_cur, *pdev_new; | ||
| 117 | |||
| 118 | dev_new = sp->dev; | ||
| 119 | dev_cur = sp_dev_master->dev; | ||
| 120 | |||
| 121 | pdev_new = to_pci_dev(dev_new); | ||
| 122 | pdev_cur = to_pci_dev(dev_cur); | ||
| 123 | |||
| 124 | if (pdev_new->bus->number < pdev_cur->bus->number) | ||
| 125 | return true; | ||
| 126 | |||
| 127 | if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn)) | ||
| 128 | return true; | ||
| 129 | |||
| 130 | if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn)) | ||
| 131 | return true; | ||
| 132 | |||
| 133 | return false; | ||
| 134 | } | ||
| 135 | |||
| 136 | static void psp_set_master(struct sp_device *sp) | ||
| 137 | { | ||
| 138 | if (!sp_dev_master) { | ||
| 139 | sp_dev_master = sp; | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | |||
| 143 | if (sp_pci_is_master(sp)) | ||
| 144 | sp_dev_master = sp; | ||
| 145 | } | ||
| 146 | |||
| 147 | static struct sp_device *psp_get_master(void) | ||
| 148 | { | ||
| 149 | return sp_dev_master; | ||
| 150 | } | ||
| 151 | |||
| 111 | static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 152 | static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| 112 | { | 153 | { |
| 113 | struct sp_device *sp; | 154 | struct sp_device *sp; |
| @@ -166,6 +207,8 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 166 | goto e_err; | 207 | goto e_err; |
| 167 | 208 | ||
| 168 | pci_set_master(pdev); | 209 | pci_set_master(pdev); |
| 210 | sp->set_psp_master_device = psp_set_master; | ||
| 211 | sp->get_psp_master_device = psp_get_master; | ||
| 169 | 212 | ||
| 170 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); | 213 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); |
| 171 | if (ret) { | 214 | if (ret) { |
| @@ -225,6 +268,12 @@ static int sp_pci_resume(struct pci_dev *pdev) | |||
| 225 | } | 268 | } |
| 226 | #endif | 269 | #endif |
| 227 | 270 | ||
| 271 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | ||
| 272 | static const struct psp_vdata psp_entry = { | ||
| 273 | .offset = 0x10500, | ||
| 274 | }; | ||
| 275 | #endif | ||
| 276 | |||
| 228 | static const struct sp_dev_vdata dev_vdata[] = { | 277 | static const struct sp_dev_vdata dev_vdata[] = { |
| 229 | { | 278 | { |
| 230 | .bar = 2, | 279 | .bar = 2, |
| @@ -237,6 +286,9 @@ static const struct sp_dev_vdata dev_vdata[] = { | |||
| 237 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP | 286 | #ifdef CONFIG_CRYPTO_DEV_SP_CCP |
| 238 | .ccp_vdata = &ccpv5a, | 287 | .ccp_vdata = &ccpv5a, |
| 239 | #endif | 288 | #endif |
| 289 | #ifdef CONFIG_CRYPTO_DEV_SP_PSP | ||
| 290 | .psp_vdata = &psp_entry | ||
| 291 | #endif | ||
| 240 | }, | 292 | }, |
| 241 | { | 293 | { |
| 242 | .bar = 2, | 294 | .bar = 2, |
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index d06bc5674e5f..6b1891539c84 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c | |||
| @@ -49,7 +49,7 @@ struct read_info_sccb { | |||
| 49 | u8 _pad_112[116 - 112]; /* 112-115 */ | 49 | u8 _pad_112[116 - 112]; /* 112-115 */ |
| 50 | u8 fac116; /* 116 */ | 50 | u8 fac116; /* 116 */ |
| 51 | u8 fac117; /* 117 */ | 51 | u8 fac117; /* 117 */ |
| 52 | u8 _pad_118; /* 118 */ | 52 | u8 fac118; /* 118 */ |
| 53 | u8 fac119; /* 119 */ | 53 | u8 fac119; /* 119 */ |
| 54 | u16 hcpua; /* 120-121 */ | 54 | u16 hcpua; /* 120-121 */ |
| 55 | u8 _pad_122[124 - 122]; /* 122-123 */ | 55 | u8 _pad_122[124 - 122]; /* 122-123 */ |
| @@ -100,6 +100,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) | |||
| 100 | sclp.has_esca = !!(sccb->fac116 & 0x08); | 100 | sclp.has_esca = !!(sccb->fac116 & 0x08); |
| 101 | sclp.has_pfmfi = !!(sccb->fac117 & 0x40); | 101 | sclp.has_pfmfi = !!(sccb->fac117 & 0x40); |
| 102 | sclp.has_ibs = !!(sccb->fac117 & 0x20); | 102 | sclp.has_ibs = !!(sccb->fac117 & 0x20); |
| 103 | sclp.has_gisaf = !!(sccb->fac118 & 0x08); | ||
| 103 | sclp.has_hvs = !!(sccb->fac119 & 0x80); | 104 | sclp.has_hvs = !!(sccb->fac119 & 0x80); |
| 104 | sclp.has_kss = !!(sccb->fac98 & 0x01); | 105 | sclp.has_kss = !!(sccb->fac98 & 0x01); |
| 105 | if (sccb->fac85 & 0x02) | 106 | if (sccb->fac85 & 0x02) |
