The Security Violation module requires below System Controller Security controller API to interact with SNVS block via SCFW - imx_sc_seco_build_info - imx_sc_seco_secvio_enable - imx_sc_seco_secvio_config - imx_sc_seco_secvio_dgo_config Signed-off-by: Franck LENORMAND <franck.lenormand@xxxxxxx> Reviewed-by: Iuliana Prodan <iuliana.prodan@xxxxxxx> Reviewed-by: Horia Geanta<horia.geanta@xxxxxxx> Signed-off-by: Dong Aisheng <aisheng.dong@xxxxxxx> Signed-off-by: Vabhav Sharma <vabhav.sharma@xxxxxxx> --- drivers/firmware/imx/Makefile | 2 +- drivers/firmware/imx/imx-scu.c | 4 +- drivers/firmware/imx/seco.c | 216 ++++++++++++++++++++++++++++++++++ include/linux/firmware/imx/ipc.h | 1 + include/linux/firmware/imx/sci.h | 4 + include/linux/firmware/imx/svc/seco.h | 69 +++++++++++ 6 files changed, 294 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 8f9f04a513a8..b53d2dee8ff3 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_IMX_DSP) += imx-dsp.o -obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o +obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o seco.o diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 1dd4362ef9a3..c96dc73689a8 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -242,9 +242,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp) * APIs are defined as void function in SCU firmware, so they * should be treated as return success always. */ - if ((saved_svc == IMX_SC_RPC_SVC_MISC) && + if (((saved_svc == IMX_SC_RPC_SVC_MISC) && (saved_func == IMX_SC_MISC_FUNC_UNIQUE_ID || saved_func == IMX_SC_MISC_FUNC_GET_BUTTON_STATUS)) + || (saved_svc == IMX_SC_RPC_SVC_SECO && + saved_func == IMX_SC_SECO_FUNC_BUILD_INFO)) ret = 0; } diff --git a/drivers/firmware/imx/seco.c b/drivers/firmware/imx/seco.c new file mode 100644 index 000000000000..2d6bf301ac87 --- /dev/null +++ b/drivers/firmware/imx/seco.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020, 2024 NXP + * + * File containing client-side RPC functions for the SECO service. These + * function are ported to clients that communicate to the SC. + */ + +#include <linux/firmware/imx/sci.h> + +struct imx_sc_msg_seco_get_build_id { + struct imx_sc_rpc_msg hdr; + u32 version; + u32 commit; +} __packed __aligned(4); + +int imx_sc_seco_build_info(struct imx_sc_ipc *ipc, uint32_t *version, + uint32_t *commit) +{ + struct imx_sc_msg_seco_get_build_id msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_SECO; + hdr->func = IMX_SC_SECO_FUNC_BUILD_INFO; + hdr->size = 1; + + ret = imx_scu_call_rpc(ipc, &msg, true); + if (ret) + return ret; + + if (version) + *version = msg.version; + if (commit) + *commit = msg.commit; + + return 0; +} +EXPORT_SYMBOL(imx_sc_seco_build_info); + +int imx_sc_seco_secvio_enable(struct imx_sc_ipc *ipc) +{ + struct imx_sc_rpc_msg msg; + struct imx_sc_rpc_msg *hdr = &msg; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_SECO; + hdr->func = IMX_SC_SECO_FUNC_SECVIO_ENABLE; + hdr->size = 1; + + return imx_scu_call_rpc(ipc, &msg, true); +} +EXPORT_SYMBOL(imx_sc_seco_secvio_enable); + +struct imx_sc_msg_req_seco_config { + struct imx_sc_rpc_msg hdr; + u32 data0; + u32 data1; + u32 data2; + u32 data3; + u32 data4; + u8 id; + u8 access; + u8 size; +} __packed __aligned(4); + +struct imx_sc_msg_resp_seco_config { + struct imx_sc_rpc_msg hdr; + u32 data0; + u32 data1; + u32 data2; + u32 data3; + u32 data4; +} __packed __aligned(4); + +int imx_sc_seco_secvio_config(struct imx_sc_ipc *ipc, u8 id, u8 access, + u32 *data0, u32 *data1, u32 *data2, u32 *data3, + u32 *data4, u8 size) +{ + struct imx_sc_msg_req_seco_config msg; + struct imx_sc_msg_resp_seco_config *resp; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_SECO; + hdr->func = IMX_SC_SECO_FUNC_SECVIO_CONFIG; + hdr->size = 7; + + /* Check the pointers on data are valid and set it if doing a write */ + switch (size) { + case 5: + if (data4) { + if (access) + msg.data4 = *data4; + } else { + return -EINVAL; + } + fallthrough; + case 4: + if (data3) { + if (access) + msg.data3 = *data3; + } else { + return -EINVAL; + } + fallthrough; + case 3: + if (data2) { + if (access) + msg.data2 = *data2; + } else { + return -EINVAL; + } + fallthrough; + case 2: + if (data1) { + if (access) + msg.data1 = *data1; + } else { + return -EINVAL; + } + fallthrough; + case 1: + if (data0) { + if (access) + msg.data0 = *data0; + } else { + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + msg.id = id; + msg.access = access; + msg.size = size; + + ret = imx_scu_call_rpc(ipc, &msg, true); + if (ret) + return ret; + + resp = (struct imx_sc_msg_resp_seco_config *)&msg; + + /* Pointers already checked so we just copy the data if reading */ + if (!access) + switch (size) { + case 5: + *data4 = resp->data4; + fallthrough; + case 4: + *data3 = resp->data3; + fallthrough; + case 3: + *data2 = resp->data2; + fallthrough; + case 2: + *data1 = resp->data1; + fallthrough; + case 1: + *data0 = resp->data0; + } + + return 0; +} +EXPORT_SYMBOL(imx_sc_seco_secvio_config); + +struct imx_sc_msg_req_seco_dgo_config { + struct imx_sc_rpc_msg hdr; + u32 data; + u8 id; + u8 access; +} __packed __aligned(4); + +struct imx_sc_msg_resp_seco_dgo_config { + struct imx_sc_rpc_msg hdr; + u32 data; +} __packed __aligned(4); + +int imx_sc_seco_secvio_dgo_config(struct imx_sc_ipc *ipc, u8 id, u8 access, + u32 *data) +{ + struct imx_sc_msg_req_seco_dgo_config msg; + struct imx_sc_msg_resp_seco_dgo_config *resp; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_SECO; + hdr->func = IMX_SC_SECO_FUNC_SECVIO_DGO_CONFIG; + hdr->size = 3; + + if (access) { + if (data) + msg.data = *data; + else + return -EINVAL; + } + + msg.access = access; + msg.id = id; + + ret = imx_scu_call_rpc(ipc, &msg, true); + if (ret) + return ret; + + resp = (struct imx_sc_msg_resp_seco_dgo_config *)&msg; + + if (!access && data) + *data = resp->data; + + return 0; +} +EXPORT_SYMBOL(imx_sc_seco_secvio_dgo_config); diff --git a/include/linux/firmware/imx/ipc.h b/include/linux/firmware/imx/ipc.h index 0b4643571625..df38ab8e7e2e 100644 --- a/include/linux/firmware/imx/ipc.h +++ b/include/linux/firmware/imx/ipc.h @@ -25,6 +25,7 @@ enum imx_sc_rpc_svc { IMX_SC_RPC_SVC_PAD = 6, IMX_SC_RPC_SVC_MISC = 7, IMX_SC_RPC_SVC_IRQ = 8, + IMX_SC_RPC_SVC_SECO = 9, }; struct imx_sc_rpc_msg { diff --git a/include/linux/firmware/imx/sci.h b/include/linux/firmware/imx/sci.h index df17196df5ff..947e49d8bebc 100644 --- a/include/linux/firmware/imx/sci.h +++ b/include/linux/firmware/imx/sci.h @@ -15,6 +15,10 @@ #include <linux/firmware/imx/svc/misc.h> #include <linux/firmware/imx/svc/pm.h> #include <linux/firmware/imx/svc/rm.h> +#include <linux/firmware/imx/svc/seco.h> + +#define IMX_SC_IRQ_SECVIO BIT(6) /* Security violation */ +#define IMX_SC_IRQ_GROUP_WAKE 3 /* Wakeup interrupts */ #if IS_ENABLED(CONFIG_IMX_SCU) int imx_scu_enable_general_irq_channel(struct device *dev); diff --git a/include/linux/firmware/imx/svc/seco.h b/include/linux/firmware/imx/svc/seco.h new file mode 100644 index 000000000000..508444c02d39 --- /dev/null +++ b/include/linux/firmware/imx/svc/seco.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020, 2024 NXP + * + * Header file containing the public API for the System Controller (SC) + * Security Controller (SECO) function. + * + * SECO_SVC (SVC) Security Controller Service + * + * Module for the Security Controller (SECO) service. + */ + +#ifndef _SC_SECO_API_H +#define _SC_SECO_API_H + +#include <linux/errno.h> +#include <linux/firmware/imx/sci.h> + +/* + * This type is used to indicate RPCs/RM/SECO function calls. + */ +enum imx_sc_seco_func { + IMX_SC_SECO_FUNC_UNKNOWN = 0, + IMX_SC_SECO_FUNC_BUILD_INFO = 16, + IMX_SC_SECO_FUNC_SECVIO_ENABLE = 25, + IMX_SC_SECO_FUNC_SECVIO_CONFIG = 26, + IMX_SC_SECO_FUNC_SECVIO_DGO_CONFIG = 27, +}; + +#if IS_ENABLED(CONFIG_IMX_SCU) +int imx_sc_seco_build_info(struct imx_sc_ipc *ipc, uint32_t *version, + uint32_t *commit); +int imx_sc_seco_secvio_enable(struct imx_sc_ipc *ipc); +int imx_sc_seco_secvio_config(struct imx_sc_ipc *ipc, u8 id, u8 access, + u32 *data0, u32 *data1, u32 *data2, u32 *data3, + u32 *data4, u8 size); +int imx_sc_seco_secvio_dgo_config(struct imx_sc_ipc *ipc, u8 id, u8 access, + u32 *data); +#else /* IS_ENABLED(CONFIG_IMX_SCU) */ +static inline +int imx_sc_seco_build_info(struct imx_sc_ipc *ipc, uint32_t *version, + uint32_t *commit) +{ + return -EOPNOTSUPP; +} + +static inline +int imx_sc_seco_secvio_enable(struct imx_sc_ipc *ipc) +{ + return -EOPNOTSUPP; +} + +static inline +int imx_sc_seco_secvio_config(struct imx_sc_ipc *ipc, u8 id, u8 access, + u32 *data0, u32 *data1, u32 *data2, u32 *data3, + u32 *data4, u8 size) +{ + return -EOPNOTSUPP; +} + +static inline +int imx_sc_seco_secvio_dgo_config(struct imx_sc_ipc *ipc, u8 id, u8 access, + u32 *data) +{ + return -EOPNOTSUPP; +} +#endif /* IS_ENABLED(CONFIG_IMX_SCU) */ + +#endif /* _SC_SECO_API_H */ -- 2.25.1