diff options
Diffstat (limited to 'drivers/crypto/ccp')
-rw-r--r-- | drivers/crypto/ccp/Makefile | 3 | ||||
-rw-r--r-- | drivers/crypto/ccp/dbc.c | 250 | ||||
-rw-r--r-- | drivers/crypto/ccp/dbc.h | 56 | ||||
-rw-r--r-- | drivers/crypto/ccp/psp-dev.c | 19 | ||||
-rw-r--r-- | drivers/crypto/ccp/psp-dev.h | 1 | ||||
-rw-r--r-- | drivers/crypto/ccp/sp-dev.h | 7 | ||||
-rw-r--r-- | drivers/crypto/ccp/sp-pci.c | 96 |
7 files changed, 415 insertions, 17 deletions
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index f6196495e862..aa0ba2d17e1e 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile @@ -11,7 +11,8 @@ ccp-$(CONFIG_PCI) += sp-pci.o ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \ sev-dev.o \ tee-dev.o \ - platform-access.o + platform-access.o \ + dbc.o obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o ccp-crypto-objs := ccp-crypto-main.o \ diff --git a/drivers/crypto/ccp/dbc.c b/drivers/crypto/ccp/dbc.c new file mode 100644 index 000000000000..839ea14b9a85 --- /dev/null +++ b/drivers/crypto/ccp/dbc.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AMD Secure Processor Dynamic Boost Control interface + * + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Author: Mario Limonciello <mario.limonciello@amd.com> + */ + +#include "dbc.h" + +struct error_map { + u32 psp; + int ret; +}; + +#define DBC_ERROR_ACCESS_DENIED 0x0001 +#define DBC_ERROR_EXCESS_DATA 0x0004 +#define DBC_ERROR_BAD_PARAMETERS 0x0006 +#define DBC_ERROR_BAD_STATE 0x0007 +#define DBC_ERROR_NOT_IMPLEMENTED 0x0009 +#define DBC_ERROR_BUSY 0x000D +#define DBC_ERROR_MESSAGE_FAILURE 0x0307 +#define DBC_ERROR_OVERFLOW 0x300F +#define DBC_ERROR_SIGNATURE_INVALID 0x3072 + +static struct error_map error_codes[] = { + {DBC_ERROR_ACCESS_DENIED, -EACCES}, + {DBC_ERROR_EXCESS_DATA, -E2BIG}, + {DBC_ERROR_BAD_PARAMETERS, -EINVAL}, + {DBC_ERROR_BAD_STATE, -EAGAIN}, + {DBC_ERROR_MESSAGE_FAILURE, -ENOENT}, + {DBC_ERROR_NOT_IMPLEMENTED, -ENOENT}, + {DBC_ERROR_BUSY, -EBUSY}, + {DBC_ERROR_OVERFLOW, -ENFILE}, + {DBC_ERROR_SIGNATURE_INVALID, -EPERM}, + {0x0, 0x0}, +}; + +static int send_dbc_cmd(struct psp_dbc_device *dbc_dev, + enum psp_platform_access_msg msg) +{ + int ret; + + dbc_dev->mbox->req.header.status = 0; + ret = psp_send_platform_access_msg(msg, (struct psp_request *)dbc_dev->mbox); + if (ret == -EIO) { + int i; + + dev_dbg(dbc_dev->dev, + "msg 0x%x failed with PSP error: 0x%x\n", + msg, dbc_dev->mbox->req.header.status); + + for (i = 0; error_codes[i].psp; i++) { + if (dbc_dev->mbox->req.header.status == error_codes[i].psp) + return error_codes[i].ret; + } + } + + return ret; +} + +static int send_dbc_nonce(struct psp_dbc_device *dbc_dev) +{ + int ret; + + dbc_dev->mbox->req.header.payload_size = sizeof(dbc_dev->mbox->dbc_nonce); + ret = send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_GET_NONCE); + if (ret == -EAGAIN) { + dev_dbg(dbc_dev->dev, "retrying get nonce\n"); + ret = send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_GET_NONCE); + } + + return ret; +} + +static int send_dbc_parameter(struct psp_dbc_device *dbc_dev) +{ + dbc_dev->mbox->req.header.payload_size = sizeof(dbc_dev->mbox->dbc_param); + + switch (dbc_dev->mbox->dbc_param.user.msg_index) { + case PARAM_SET_FMAX_CAP: + case PARAM_SET_PWR_CAP: + case PARAM_SET_GFX_MODE: + return send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_SET_PARAMETER); + case PARAM_GET_FMAX_CAP: + case PARAM_GET_PWR_CAP: + case PARAM_GET_CURR_TEMP: + case PARAM_GET_FMAX_MAX: + case PARAM_GET_FMAX_MIN: + case PARAM_GET_SOC_PWR_MAX: + case PARAM_GET_SOC_PWR_MIN: + case PARAM_GET_SOC_PWR_CUR: + case PARAM_GET_GFX_MODE: + return send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_GET_PARAMETER); + } + + return -EINVAL; +} + +void dbc_dev_destroy(struct psp_device *psp) +{ + struct psp_dbc_device *dbc_dev = psp->dbc_data; + + if (!dbc_dev) + return; + + misc_deregister(&dbc_dev->char_dev); + mutex_destroy(&dbc_dev->ioctl_mutex); + psp->dbc_data = NULL; +} + +static long dbc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct psp_device *psp_master = psp_get_master_device(); + void __user *argp = (void __user *)arg; + struct psp_dbc_device *dbc_dev; + int ret; + + if (!psp_master || !psp_master->dbc_data) + return -ENODEV; + dbc_dev = psp_master->dbc_data; + + mutex_lock(&dbc_dev->ioctl_mutex); + + switch (cmd) { + case DBCIOCNONCE: + if (copy_from_user(&dbc_dev->mbox->dbc_nonce.user, argp, + sizeof(struct dbc_user_nonce))) { + ret = -EFAULT; + goto unlock; + } + + ret = send_dbc_nonce(dbc_dev); + if (ret) + goto unlock; + + if (copy_to_user(argp, &dbc_dev->mbox->dbc_nonce.user, + sizeof(struct dbc_user_nonce))) { + ret = -EFAULT; + goto unlock; + } + break; + case DBCIOCUID: + dbc_dev->mbox->req.header.payload_size = sizeof(dbc_dev->mbox->dbc_set_uid); + if (copy_from_user(&dbc_dev->mbox->dbc_set_uid.user, argp, + sizeof(struct dbc_user_setuid))) { + ret = -EFAULT; + goto unlock; + } + + ret = send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_SET_UID); + if (ret) + goto unlock; + + if (copy_to_user(argp, &dbc_dev->mbox->dbc_set_uid.user, + sizeof(struct dbc_user_setuid))) { + ret = -EFAULT; + goto unlock; + } + break; + case DBCIOCPARAM: + if (copy_from_user(&dbc_dev->mbox->dbc_param.user, argp, + sizeof(struct dbc_user_param))) { + ret = -EFAULT; + goto unlock; + } + + ret = send_dbc_parameter(dbc_dev); + if (ret) + goto unlock; + + if (copy_to_user(argp, &dbc_dev->mbox->dbc_param.user, + sizeof(struct dbc_user_param))) { + ret = -EFAULT; + goto unlock; + } + break; + default: + ret = -EINVAL; + + } +unlock: + mutex_unlock(&dbc_dev->ioctl_mutex); + + return ret; +} + +static const struct file_operations dbc_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dbc_ioctl, +}; + +int dbc_dev_init(struct psp_device *psp) +{ + struct device *dev = psp->dev; + struct psp_dbc_device *dbc_dev; + int ret; + + if (!PSP_FEATURE(psp, DBC)) + return 0; + + dbc_dev = devm_kzalloc(dev, sizeof(*dbc_dev), GFP_KERNEL); + if (!dbc_dev) + return -ENOMEM; + + BUILD_BUG_ON(sizeof(union dbc_buffer) > PAGE_SIZE); + dbc_dev->mbox = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0); + if (!dbc_dev->mbox) { + ret = -ENOMEM; + goto cleanup_dev; + } + + psp->dbc_data = dbc_dev; + dbc_dev->dev = dev; + + ret = send_dbc_nonce(dbc_dev); + if (ret == -EACCES) { + dev_dbg(dbc_dev->dev, + "dynamic boost control was previously authenticated\n"); + ret = 0; + } + dev_dbg(dbc_dev->dev, "dynamic boost control is %savailable\n", + ret ? "un" : ""); + if (ret) { + ret = 0; + goto cleanup_mbox; + } + + dbc_dev->char_dev.minor = MISC_DYNAMIC_MINOR; + dbc_dev->char_dev.name = "dbc"; + dbc_dev->char_dev.fops = &dbc_fops; + dbc_dev->char_dev.mode = 0600; + ret = misc_register(&dbc_dev->char_dev); + if (ret) + goto cleanup_mbox; + + mutex_init(&dbc_dev->ioctl_mutex); + + return 0; + +cleanup_mbox: + devm_free_pages(dev, (unsigned long)dbc_dev->mbox); + +cleanup_dev: + psp->dbc_data = NULL; + devm_kfree(dev, dbc_dev); + + return ret; +} diff --git a/drivers/crypto/ccp/dbc.h b/drivers/crypto/ccp/dbc.h new file mode 100644 index 000000000000..e963099ca38e --- /dev/null +++ b/drivers/crypto/ccp/dbc.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * AMD Platform Security Processor (PSP) Dynamic Boost Control support + * + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Author: Mario Limonciello <mario.limonciello@amd.com> + */ + +#ifndef __DBC_H__ +#define __DBC_H__ + +#include <uapi/linux/psp-dbc.h> + +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <linux/psp-platform-access.h> + +#include "psp-dev.h" + +struct psp_dbc_device { + struct device *dev; + + union dbc_buffer *mbox; + + struct mutex ioctl_mutex; + + struct miscdevice char_dev; +}; + +struct dbc_nonce { + struct psp_req_buffer_hdr header; + struct dbc_user_nonce user; +} __packed; + +struct dbc_set_uid { + struct psp_req_buffer_hdr header; + struct dbc_user_setuid user; +} __packed; + +struct dbc_param { + struct psp_req_buffer_hdr header; + struct dbc_user_param user; +} __packed; + +union dbc_buffer { + struct psp_request req; + struct dbc_nonce dbc_nonce; + struct dbc_set_uid dbc_set_uid; + struct dbc_param dbc_param; +}; + +void dbc_dev_destroy(struct psp_device *psp); +int dbc_dev_init(struct psp_device *psp); + +#endif /* __DBC_H */ diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index e3d6955d3265..d42d7bc62352 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -15,6 +15,7 @@ #include "sev-dev.h" #include "tee-dev.h" #include "platform-access.h" +#include "dbc.h" struct psp_device *psp_master; @@ -112,6 +113,12 @@ static void psp_init_platform_access(struct psp_device *psp) dev_warn(psp->dev, "platform access init failed: %d\n", ret); return; } + + /* dbc must come after platform access as it tests the feature */ + ret = dbc_dev_init(psp); + if (ret) + dev_warn(psp->dev, "failed to init dynamic boost control: %d\n", + ret); } static int psp_init(struct psp_device *psp) @@ -173,13 +180,14 @@ int psp_dev_init(struct sp_device *sp) goto e_err; } + /* master device must be set for platform access */ + if (psp->sp->set_psp_master_device) + psp->sp->set_psp_master_device(psp->sp); + ret = psp_init(psp); if (ret) goto e_irq; - if (sp->set_psp_master_device) - sp->set_psp_master_device(sp); - /* Enable interrupt */ iowrite32(-1, psp->io_regs + psp->vdata->inten_reg); @@ -188,6 +196,9 @@ int psp_dev_init(struct sp_device *sp) return 0; e_irq: + if (sp->clear_psp_master_device) + sp->clear_psp_master_device(sp); + sp_free_psp_irq(psp->sp, psp); e_err: sp->psp_data = NULL; @@ -213,6 +224,8 @@ void psp_dev_destroy(struct sp_device *sp) tee_dev_destroy(psp); + dbc_dev_destroy(psp); + platform_access_dev_destroy(psp); sp_free_psp_irq(sp, psp); diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h index 505e4bdeaca8..8a4de69399c5 100644 --- a/drivers/crypto/ccp/psp-dev.h +++ b/drivers/crypto/ccp/psp-dev.h @@ -40,6 +40,7 @@ struct psp_device { void *sev_data; void *tee_data; void *platform_access_data; + void *dbc_data; unsigned int capability; }; diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 1253a0217985..2329ad524b49 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -28,6 +28,10 @@ #define CACHE_NONE 0x00 #define CACHE_WB_NO_ALLOC 0xb7 +#define PLATFORM_FEATURE_DBC 0x1 + +#define PSP_FEATURE(psp, feat) (psp->vdata && psp->vdata->platform_features & PLATFORM_FEATURE_##feat) + /* Structure to hold CCP device data */ struct ccp_device; struct ccp_vdata { @@ -51,6 +55,7 @@ struct tee_vdata { const unsigned int cmdbuff_addr_hi_reg; const unsigned int ring_wptr_reg; const unsigned int ring_rptr_reg; + const unsigned int info_reg; }; struct platform_access_vdata { @@ -69,6 +74,8 @@ struct psp_vdata { const unsigned int feature_reg; const unsigned int inten_reg; const unsigned int intsts_reg; + const unsigned int bootloader_info_reg; + const unsigned int platform_features; }; /* Structure to hold SP device data */ diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index b603ad9b8341..b6ab56abeb68 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -8,6 +8,7 @@ * Author: Gary R Hook <gary.hook@amd.com> */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> @@ -24,6 +25,12 @@ #include "ccp-dev.h" #include "psp-dev.h" +/* used for version string AA.BB.CC.DD */ +#define AA GENMASK(31, 24) +#define BB GENMASK(23, 16) +#define CC GENMASK(15, 8) +#define DD GENMASK(7, 0) + #define MSIX_VECTORS 2 struct sp_pci { @@ -32,7 +39,7 @@ struct sp_pci { }; static struct sp_device *sp_dev_master; -#define attribute_show(name, def) \ +#define security_attribute_show(name, def) \ static ssize_t name##_show(struct device *d, struct device_attribute *attr, \ char *buf) \ { \ @@ -42,24 +49,24 @@ static ssize_t name##_show(struct device *d, struct device_attribute *attr, \ return sysfs_emit(buf, "%d\n", (psp->capability & bit) > 0); \ } -attribute_show(fused_part, FUSED_PART) +security_attribute_show(fused_part, FUSED_PART) static DEVICE_ATTR_RO(fused_part); -attribute_show(debug_lock_on, DEBUG_LOCK_ON) +security_attribute_show(debug_lock_on, DEBUG_LOCK_ON) static DEVICE_ATTR_RO(debug_lock_on); -attribute_show(tsme_status, TSME_STATUS) +security_attribute_show(tsme_status, TSME_STATUS) static DEVICE_ATTR_RO(tsme_status); -attribute_show(anti_rollback_status, ANTI_ROLLBACK_STATUS) +security_attribute_show(anti_rollback_status, ANTI_ROLLBACK_STATUS) static DEVICE_ATTR_RO(anti_rollback_status); -attribute_show(rpmc_production_enabled, RPMC_PRODUCTION_ENABLED) +security_attribute_show(rpmc_production_enabled, RPMC_PRODUCTION_ENABLED) static DEVICE_ATTR_RO(rpmc_production_enabled); -attribute_show(rpmc_spirom_available, RPMC_SPIROM_AVAILABLE) +security_attribute_show(rpmc_spirom_available, RPMC_SPIROM_AVAILABLE) static DEVICE_ATTR_RO(rpmc_spirom_available); -attribute_show(hsp_tpm_available, HSP_TPM_AVAILABLE) +security_attribute_show(hsp_tpm_available, HSP_TPM_AVAILABLE) static DEVICE_ATTR_RO(hsp_tpm_available); -attribute_show(rom_armor_enforced, ROM_ARMOR_ENFORCED) +security_attribute_show(rom_armor_enforced, ROM_ARMOR_ENFORCED) static DEVICE_ATTR_RO(rom_armor_enforced); -static struct attribute *psp_attrs[] = { +static struct attribute *psp_security_attrs[] = { &dev_attr_fused_part.attr, &dev_attr_debug_lock_on.attr, &dev_attr_tsme_status.attr, @@ -83,13 +90,70 @@ static umode_t psp_security_is_visible(struct kobject *kobj, struct attribute *a return 0; } -static struct attribute_group psp_attr_group = { - .attrs = psp_attrs, +static struct attribute_group psp_security_attr_group = { + .attrs = psp_security_attrs, .is_visible = psp_security_is_visible, }; +#define version_attribute_show(name, _offset) \ +static ssize_t name##_show(struct device *d, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct sp_device *sp = dev_get_drvdata(d); \ + struct psp_device *psp = sp->psp_data; \ + unsigned int val = ioread32(psp->io_regs + _offset); \ + return sysfs_emit(buf, "%02lx.%02lx.%02lx.%02lx\n", \ + FIELD_GET(AA, val), \ + FIELD_GET(BB, val), \ + FIELD_GET(CC, val), \ + FIELD_GET(DD, val)); \ +} + +version_attribute_show(bootloader_version, psp->vdata->bootloader_info_reg) +static DEVICE_ATTR_RO(bootloader_version); +version_attribute_show(tee_version, psp->vdata->tee->info_reg) +static DEVICE_ATTR_RO(tee_version); + +static struct attribute *psp_firmware_attrs[] = { + &dev_attr_bootloader_version.attr, + &dev_attr_tee_version.attr, + NULL, +}; + +static umode_t psp_firmware_is_visible(struct kobject *kobj, struct attribute *attr, int idx) +{ + struct device *dev = kobj_to_dev(kobj); + struct sp_device *sp = dev_get_drvdata(dev); + struct psp_device *psp = sp->psp_data; + unsigned int val = 0xffffffff; + + if (!psp) + return 0; + + if (attr == &dev_attr_bootloader_version.attr && + psp->vdata->bootloader_info_reg) + val = ioread32(psp->io_regs + psp->vdata->bootloader_info_reg); + + if (attr == &dev_attr_tee_version.attr && + psp->capability & PSP_CAPABILITY_TEE && + psp->vdata->tee->info_reg) + val = ioread32(psp->io_regs + psp->vdata->tee->info_reg); + + /* If platform disallows accessing this register it will be all f's */ + if (val != 0xffffffff) + return 0444; + + return 0; +} + +static struct attribute_group psp_firmware_attr_group = { + .attrs = psp_firmware_attrs, + .is_visible = psp_firmware_is_visible, +}; + static const struct attribute_group *psp_groups[] = { - &psp_attr_group, + &psp_security_attr_group, + &psp_firmware_attr_group, NULL, }; @@ -359,6 +423,7 @@ static const struct tee_vdata teev1 = { .cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */ .ring_wptr_reg = 0x10550, /* C2PMSG_20 */ .ring_rptr_reg = 0x10554, /* C2PMSG_21 */ + .info_reg = 0x109e8, /* C2PMSG_58 */ }; static const struct tee_vdata teev2 = { @@ -384,6 +449,7 @@ static const struct platform_access_vdata pa_v2 = { static const struct psp_vdata pspv1 = { .sev = &sevv1, + .bootloader_info_reg = 0x105ec, /* C2PMSG_59 */ .feature_reg = 0x105fc, /* C2PMSG_63 */ .inten_reg = 0x10610, /* P2CMSG_INTEN */ .intsts_reg = 0x10614, /* P2CMSG_INTSTS */ @@ -391,6 +457,7 @@ static const struct psp_vdata pspv1 = { static const struct psp_vdata pspv2 = { .sev = &sevv2, + .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */ .feature_reg = 0x109fc, /* C2PMSG_63 */ .inten_reg = 0x10690, /* P2CMSG_INTEN */ .intsts_reg = 0x10694, /* P2CMSG_INTSTS */ @@ -399,14 +466,17 @@ static const struct psp_vdata pspv2 = { static const struct psp_vdata pspv3 = { .tee = &teev1, .platform_access = &pa_v1, + .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */ .feature_reg = 0x109fc, /* C2PMSG_63 */ .inten_reg = 0x10690, /* P2CMSG_INTEN */ .intsts_reg = 0x10694, /* P2CMSG_INTSTS */ + .platform_features = PLATFORM_FEATURE_DBC, }; static const struct psp_vdata pspv4 = { .sev = &sevv2, .tee = &teev1, + .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */ .feature_reg = 0x109fc, /* C2PMSG_63 */ .inten_reg = 0x10690, /* P2CMSG_INTEN */ .intsts_reg = 0x10694, /* P2CMSG_INTSTS */ |