From c04cf9e14f109ebcc425c1efd2c01294c52a4d62 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 23 Jun 2023 08:49:55 -0500 Subject: crypto: ccp - Add support for fetching a nonce for dynamic boost control Dynamic Boost Control is a feature offered on AMD client platforms that allows software to request and set power or frequency limits. Only software that has authenticated with the PSP can retrieve or set these limits. Create a character device and ioctl for fetching the nonce. This ioctl supports optionally passing authentication information which will influence how many calls the nonce is valid for. Acked-by: Tom Lendacky Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu --- include/uapi/linux/psp-dbc.h | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 include/uapi/linux/psp-dbc.h (limited to 'include/uapi/linux') diff --git a/include/uapi/linux/psp-dbc.h b/include/uapi/linux/psp-dbc.h new file mode 100644 index 000000000000..d032f78934e2 --- /dev/null +++ b/include/uapi/linux/psp-dbc.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Userspace interface for AMD Dynamic Boost Control (DBC) + * + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Author: Mario Limonciello + */ + +#ifndef __PSP_DBC_USER_H__ +#define __PSP_DBC_USER_H__ + +#include + +/** + * DOC: AMD Dynamic Boost Control (DBC) interface + */ + +#define DBC_NONCE_SIZE 16 +#define DBC_SIG_SIZE 32 + +/** + * struct dbc_user_nonce - Nonce exchange structure (input/output). + * @auth_needed: Whether the PSP should authenticate this request (input). + * 0: no authentication, PSP will return single use nonce. + * 1: authentication: PSP will return multi-use nonce. + * @nonce: 8 byte value used for future authentication (output). + * @signature: Optional 32 byte signature created by software using a + * previous nonce (input). + */ +struct dbc_user_nonce { + __u32 auth_needed; + __u8 nonce[DBC_NONCE_SIZE]; + __u8 signature[DBC_SIG_SIZE]; +} __packed; + +/** + * Dynamic Boost Control (DBC) IOC + * + * possible return codes for all DBC IOCTLs: + * 0: success + * -EINVAL: invalid input + * -E2BIG: excess data passed + * -EFAULT: failed to copy to/from userspace + * -EBUSY: mailbox in recovery or in use + * -ENODEV: driver not bound with PSP device + * -EACCES: request isn't authorized + * -EINVAL: invalid parameter + * -ETIMEDOUT: request timed out + * -EAGAIN: invalid request for state machine + * -ENOENT: not implemented + * -ENFILE: overflow + * -EPERM: invalid signature + * -EIO: unknown error + */ +#define DBC_IOC_TYPE 'D' + +/** + * DBCIOCNONCE - Fetch a nonce from the PSP for authenticating commands. + * If a nonce is fetched without authentication it can only + * be utilized for one command. + * If a nonce is fetched with authentication it can be used + * for multiple requests. + */ +#define DBCIOCNONCE _IOWR(DBC_IOC_TYPE, 0x1, struct dbc_user_nonce) + +#endif /* __PSP_DBC_USER_H__ */ -- cgit v1.2.3 From d9408716d2126439fbc46f6c40e72792069b8411 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 23 Jun 2023 08:49:56 -0500 Subject: crypto: ccp - Add support for setting user ID for dynamic boost control As part of the authentication flow for Dynamic Boost Control, the calling software will need to send a uid used in all of its future communications. Add support for another IOCTL call to let userspace software set this up. Acked-by: Tom Lendacky Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu --- drivers/crypto/ccp/dbc.c | 18 ++++++++++++++++++ drivers/crypto/ccp/dbc.h | 6 ++++++ include/linux/psp-platform-access.h | 1 + include/uapi/linux/psp-dbc.h | 20 ++++++++++++++++++++ 4 files changed, 45 insertions(+) (limited to 'include/uapi/linux') diff --git a/drivers/crypto/ccp/dbc.c b/drivers/crypto/ccp/dbc.c index f65e93a81e53..c6f5fb3658ca 100644 --- a/drivers/crypto/ccp/dbc.c +++ b/drivers/crypto/ccp/dbc.c @@ -117,6 +117,24 @@ static long dbc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 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; default: ret = -EINVAL; diff --git a/drivers/crypto/ccp/dbc.h b/drivers/crypto/ccp/dbc.h index 1c3a0a078d15..156435100076 100644 --- a/drivers/crypto/ccp/dbc.h +++ b/drivers/crypto/ccp/dbc.h @@ -33,9 +33,15 @@ struct dbc_nonce { struct dbc_user_nonce user; } __packed; +struct dbc_set_uid { + struct psp_req_buffer_hdr header; + struct dbc_user_setuid user; +} __packed; + union dbc_buffer { struct psp_request req; struct dbc_nonce dbc_nonce; + struct dbc_set_uid dbc_set_uid; }; void dbc_dev_destroy(struct psp_device *psp); diff --git a/include/linux/psp-platform-access.h b/include/linux/psp-platform-access.h index 53b4a1df5180..18b9e0f0cb03 100644 --- a/include/linux/psp-platform-access.h +++ b/include/linux/psp-platform-access.h @@ -9,6 +9,7 @@ enum psp_platform_access_msg { PSP_CMD_NONE = 0x0, PSP_I2C_REQ_BUS_CMD = 0x64, PSP_DYNAMIC_BOOST_GET_NONCE, + PSP_DYNAMIC_BOOST_SET_UID, }; struct psp_req_buffer_hdr { diff --git a/include/uapi/linux/psp-dbc.h b/include/uapi/linux/psp-dbc.h index d032f78934e2..7443c78ede19 100644 --- a/include/uapi/linux/psp-dbc.h +++ b/include/uapi/linux/psp-dbc.h @@ -18,6 +18,7 @@ #define DBC_NONCE_SIZE 16 #define DBC_SIG_SIZE 32 +#define DBC_UID_SIZE 16 /** * struct dbc_user_nonce - Nonce exchange structure (input/output). @@ -34,6 +35,16 @@ struct dbc_user_nonce { __u8 signature[DBC_SIG_SIZE]; } __packed; +/** + * struct dbc_user_setuid - UID exchange structure (input). + * @uid: 16 byte value representing software identity + * @signature: 32 byte signature created by software using a previous nonce + */ +struct dbc_user_setuid { + __u8 uid[DBC_UID_SIZE]; + __u8 signature[DBC_SIG_SIZE]; +} __packed; + /** * Dynamic Boost Control (DBC) IOC * @@ -64,4 +75,13 @@ struct dbc_user_nonce { */ #define DBCIOCNONCE _IOWR(DBC_IOC_TYPE, 0x1, struct dbc_user_nonce) +/** + * DBCIOCUID - Set the user ID (UID) of a calling process. + * The user ID is 8 bytes long. It must be programmed using a + * 32 byte signature built using the nonce fetched from + * DBCIOCNONCE. + * The UID can only be set once until the system is rebooted. + */ +#define DBCIOCUID _IOW(DBC_IOC_TYPE, 0x2, struct dbc_user_setuid) + #endif /* __PSP_DBC_USER_H__ */ -- cgit v1.2.3 From e2cfe05e9277b5a7abbbc186fec1ad37348dd956 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 23 Jun 2023 08:49:57 -0500 Subject: crypto: ccp - Add support for getting and setting DBC parameters After software has authenticated a dynamic boost control request, it can fetch and set supported parameters using a selection of messages. Add support for these messages and export the ability to do this to userspace. Acked-by: Tom Lendacky Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu --- drivers/crypto/ccp/dbc.c | 41 +++++++++++++++++++++++++ drivers/crypto/ccp/dbc.h | 6 ++++ include/linux/psp-platform-access.h | 2 ++ include/uapi/linux/psp-dbc.h | 60 +++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) (limited to 'include/uapi/linux') diff --git a/drivers/crypto/ccp/dbc.c b/drivers/crypto/ccp/dbc.c index c6f5fb3658ca..839ea14b9a85 100644 --- a/drivers/crypto/ccp/dbc.c +++ b/drivers/crypto/ccp/dbc.c @@ -74,6 +74,30 @@ static int send_dbc_nonce(struct psp_dbc_device *dbc_dev) 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; @@ -135,6 +159,23 @@ static long dbc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 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; diff --git a/drivers/crypto/ccp/dbc.h b/drivers/crypto/ccp/dbc.h index 156435100076..e963099ca38e 100644 --- a/drivers/crypto/ccp/dbc.h +++ b/drivers/crypto/ccp/dbc.h @@ -38,10 +38,16 @@ struct dbc_set_uid { 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); diff --git a/include/linux/psp-platform-access.h b/include/linux/psp-platform-access.h index 18b9e0f0cb03..c1dc87fc536b 100644 --- a/include/linux/psp-platform-access.h +++ b/include/linux/psp-platform-access.h @@ -10,6 +10,8 @@ enum psp_platform_access_msg { PSP_I2C_REQ_BUS_CMD = 0x64, PSP_DYNAMIC_BOOST_GET_NONCE, PSP_DYNAMIC_BOOST_SET_UID, + PSP_DYNAMIC_BOOST_GET_PARAMETER, + PSP_DYNAMIC_BOOST_SET_PARAMETER, }; struct psp_req_buffer_hdr { diff --git a/include/uapi/linux/psp-dbc.h b/include/uapi/linux/psp-dbc.h index 7443c78ede19..b3845a9ff5fd 100644 --- a/include/uapi/linux/psp-dbc.h +++ b/include/uapi/linux/psp-dbc.h @@ -45,6 +45,23 @@ struct dbc_user_setuid { __u8 signature[DBC_SIG_SIZE]; } __packed; +/** + * struct dbc_user_param - Parameter exchange structure (input/output). + * @msg_index: Message indicating what parameter to set or get (input) + * @param: 4 byte parameter, units are message specific. (input/output) + * @signature: 32 byte signature. + * - When sending a message this is to be created by software + * using a previous nonce (input) + * - For interpreting results, this signature is updated by the + * PSP to allow software to validate the authenticity of the + * results. + */ +struct dbc_user_param { + __u32 msg_index; + __u32 param; + __u8 signature[DBC_SIG_SIZE]; +} __packed; + /** * Dynamic Boost Control (DBC) IOC * @@ -84,4 +101,47 @@ struct dbc_user_setuid { */ #define DBCIOCUID _IOW(DBC_IOC_TYPE, 0x2, struct dbc_user_setuid) +/** + * DBCIOCPARAM - Set or get a parameter from the PSP. + * This request will only work after DBCIOCUID has successfully + * set the UID of the calling process. + * Whether the parameter is set or get is controlled by the + * message ID in the request. + * This command must be sent using a 32 byte signature built + * using the nonce fetched from DBCIOCNONCE. + * When the command succeeds, the 32 byte signature will be + * updated by the PSP for software to authenticate the results. + */ +#define DBCIOCPARAM _IOWR(DBC_IOC_TYPE, 0x3, struct dbc_user_param) + +/** + * enum dbc_cmd_msg - Messages utilized by DBCIOCPARAM + * @PARAM_GET_FMAX_CAP: Get frequency cap (MHz) + * @PARAM_SET_FMAX_CAP: Set frequency cap (MHz) + * @PARAM_GET_PWR_CAP: Get socket power cap (mW) + * @PARAM_SET_PWR_CAP: Set socket power cap (mW) + * @PARAM_GET_GFX_MODE: Get graphics mode (0/1) + * @PARAM_SET_GFX_MODE: Set graphics mode (0/1) + * @PARAM_GET_CURR_TEMP: Get current temperature (degrees C) + * @PARAM_GET_FMAX_MAX: Get maximum allowed value for frequency (MHz) + * @PARAM_GET_FMAX_MIN: Get minimum allowed value for frequency (MHz) + * @PARAM_GET_SOC_PWR_MAX: Get maximum allowed value for SoC power (mw) + * @PARAM_GET_SOC_PWR_MIN: Get minimum allowed value for SoC power (mw) + * @PARAM_GET_SOC_PWR_CUR: Get current value for SoC Power (mW) + */ +enum dbc_cmd_msg { + PARAM_GET_FMAX_CAP = 0x3, + PARAM_SET_FMAX_CAP = 0x4, + PARAM_GET_PWR_CAP = 0x5, + PARAM_SET_PWR_CAP = 0x6, + PARAM_GET_GFX_MODE = 0x7, + PARAM_SET_GFX_MODE = 0x8, + PARAM_GET_CURR_TEMP = 0x9, + PARAM_GET_FMAX_MAX = 0xA, + PARAM_GET_FMAX_MIN = 0xB, + PARAM_GET_SOC_PWR_MAX = 0xC, + PARAM_GET_SOC_PWR_MIN = 0xD, + PARAM_GET_SOC_PWR_CUR = 0xE, +}; + #endif /* __PSP_DBC_USER_H__ */ -- cgit v1.2.3