diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig index 8abf6dd90837..bd000a20ea08 100644 --- a/drivers/firmware/imx/Kconfig +++ b/drivers/firmware/imx/Kconfig @@ -49,6 +49,7 @@ config IMX_SEC_ENCLAVE help It is possible to use APIs exposed by the iMX Secure Enclave HW IP called: - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93, i.MX95), + - SECO (for i.MX8DXL, i.MXQM, i.MXQXP), like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging Unit. This driver exposes these interfaces via a set of file descriptors allowing to configure shared memory, send and receive messages. diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 2460617878fb..05d705d894ab 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o seco obj-${CONFIG_IMX_SCMI_MISC_CONTROL} += sm-misc.o obj-$(CONFIG_IMX_SCMI_BBM_CONTROL) += sm-bbm.o obj-$(CONFIG_IMX_ISPMU) += isp-mu.o -sec_enclave-objs = se_ctrl.o ele_common.o ele_base_msg.o ele_fw_api.o v2x_base_msg.o v2x_common.o +obj-${CONFIG_IMX_SCMI_MISC_DRV} += sm-misc.o +sec_enclave-objs = se_ctrl.o ele_common.o ele_base_msg.o ele_fw_api.o v2x_base_msg.o v2x_common.o seco_init.o obj-${CONFIG_IMX_SEC_ENCLAVE} += sec_enclave.o sec_enclave-${CONFIG_IMX_ELE_TRNG} += ele_trng.o diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c index 33a784ab9f22..cc7efbe4d715 100644 --- a/drivers/firmware/imx/se_ctrl.c +++ b/drivers/firmware/imx/se_ctrl.c @@ -31,12 +31,15 @@ #include "ele_fw_api.h" #include "ele_trng.h" #include "se_ctrl.h" +#include "seco_init.h" #include "v2x_base_msg.h" #include "v2x_common.h" #define MAX_SOC_INFO_DATA_SZ 256 #define MBOX_TX_NAME "tx" #define MBOX_RX_NAME "rx" +#define MBOX_TXDB_NAME "txdb" +#define MBOX_RXDB_NAME "rxdb" #define SE_RCV_MSG_DEFAULT_TIMEOUT 5000 #define SE_RCV_MSG_LONG_TIMEOUT 5000000 @@ -167,11 +170,9 @@ static struct se_if_node_info_list imx95_info = { .soc_id = SOC_ID_OF_IMX95, .soc_register = false, .se_fetch_soc_info = ele_fetch_soc_info, - .load_hsm_fw = { + .se_fw_img_nm = { .prim_fw_nm_in_rfs = NULL, .seco_fw_nm_in_rfs = NULL, - .is_fw_loaded = true, - .handle_susp_resm = false, }, .info = { { @@ -249,10 +250,150 @@ static struct se_if_node_info_list imx95_info = { }, }; +static struct se_if_node_info_list imx8dxl_info = { + .num_mu = 7, + .soc_id = SOC_ID_OF_IMX8DXL, + .soc_register = false, + .se_fetch_soc_info = seco_fetch_soc_info, + .se_fw_img_nm = { + .prim_fw_nm_in_rfs = NULL, + .seco_fw_nm_in_rfs = NULL, + }, + .info = { + { + .se_if_id = 0, + .mu_buff_size = 0, + .if_defs = { + .se_if_type = SE_TYPE_ID_SHE, + .se_instance_id = 0, + .cmd_tag = 0x17, + .rsp_tag = 0xe1, + .success_tag = SECO_SUCCESS_IND, + .base_api_ver = MESSAGING_VERSION_6, + .fw_api_ver = MESSAGING_VERSION_7, + }, + .reserved_dma_ranges = false, + .start_rng = NULL, + .init_trng = NULL, + .se_if_early_init = imx_scu_init_fw, + .se_if_late_init = NULL, + }, + { + .se_if_id = 1, + .mu_buff_size = 0, + .if_defs = { + .se_if_type = SE_TYPE_ID_HSM, + .se_instance_id = 0, + .cmd_tag = 0x17, + .rsp_tag = 0xe1, + .success_tag = SECO_SUCCESS_IND, + .base_api_ver = MESSAGING_VERSION_6, + .fw_api_ver = MESSAGING_VERSION_7, + }, + .reserved_dma_ranges = false, + .start_rng = NULL, + .init_trng = NULL, + .se_if_early_init = imx_scu_init_fw, + .se_if_late_init = NULL, + }, + { + .se_if_id = 2, + .mu_buff_size = 0, + .if_defs = { + .se_if_type = SE_TYPE_ID_V2X_SV, + .se_instance_id = 0, + .cmd_tag = 0x18, + .rsp_tag = 0xe2, + .success_tag = SECO_SUCCESS_IND, + .base_api_ver = MESSAGING_VERSION_2, + .fw_api_ver = MESSAGING_VERSION_7, + }, + .reserved_dma_ranges = false, + .start_rng = NULL, + .init_trng = NULL, + .se_if_early_init = imx_scu_init_fw, + .se_if_late_init = NULL, + }, + { + .se_if_id = 3, + .mu_buff_size = 0, + .if_defs = { + .se_if_type = SE_TYPE_ID_V2X_SV, + .se_instance_id = 1, + .cmd_tag = 0x19, + .rsp_tag = 0xe3, + .success_tag = SECO_SUCCESS_IND, + .base_api_ver = MESSAGING_VERSION_2, + .fw_api_ver = MESSAGING_VERSION_7, + }, + .reserved_dma_ranges = false, + .start_rng = NULL, + .init_trng = NULL, + .se_if_early_init = imx_scu_init_fw, + .se_if_late_init = NULL, + }, + { + .se_if_id = 4, + .mu_buff_size = 16, + .if_defs = { + .se_if_type = SE_TYPE_ID_V2X_SHE, + .se_instance_id = 0, + .cmd_tag = 0x1a, + .rsp_tag = 0xe4, + .success_tag = SECO_SUCCESS_IND, + .base_api_ver = MESSAGING_VERSION_2, + .fw_api_ver = MESSAGING_VERSION_7, + }, + .reserved_dma_ranges = false, + .start_rng = NULL, + .init_trng = NULL, + .se_if_early_init = imx_scu_init_fw, + .se_if_late_init = NULL, + }, + { + .se_if_id = 5, + .mu_buff_size = 0, + .if_defs = { + .se_if_type = SE_TYPE_ID_V2X_SG, + .se_instance_id = 0, + .cmd_tag = 0x1d, + .rsp_tag = 0xe7, + .success_tag = SECO_SUCCESS_IND, + .base_api_ver = MESSAGING_VERSION_2, + .fw_api_ver = MESSAGING_VERSION_7, + }, + .reserved_dma_ranges = false, + .start_rng = NULL, + .init_trng = NULL, + .se_if_early_init = imx_scu_init_fw, + .se_if_late_init = NULL, + }, + { + .se_if_id = 6, + .mu_buff_size = 0, + .if_defs = { + .se_if_type = SE_TYPE_ID_V2X_SG, + .se_instance_id = 1, + .cmd_tag = 0x1e, + .rsp_tag = 0xe8, + .success_tag = SECO_SUCCESS_IND, + .base_api_ver = MESSAGING_VERSION_2, + .fw_api_ver = MESSAGING_VERSION_7, + }, + .reserved_dma_ranges = false, + .start_rng = NULL, + .init_trng = NULL, + .se_if_early_init = imx_scu_init_fw, + .se_if_late_init = NULL, + }, + }, +}; + static const struct of_device_id se_match[] = { { .compatible = "fsl,imx8ulp-se", .data = (void *)&imx8ulp_info}, { .compatible = "fsl,imx93-se", .data = (void *)&imx93_info}, { .compatible = "fsl,imx95-se", .data = (void *)&imx95_info}, + { .compatible = "fsl,imx8dxl-se", .data = (void *)&imx8dxl_info}, {}, }; @@ -398,6 +539,9 @@ void *imx_get_se_data_info(u32 soc_id, u32 idx) info_list = &imx93_info; break; case SOC_ID_OF_IMX95: info_list = &imx95_info; break; + case SOC_ID_OF_IMX8DXL: + case SOC_ID_OF_IMX8QXP: + info_list = &imx8dxl_info; break; default: return NULL; } @@ -445,12 +589,20 @@ static int se_soc_info(struct se_if_priv *priv) dev_err(priv->dev, "Failed to fetch SoC Info."); return err; } + if (info_list->soc_id == SOC_ID_OF_IMX8DXL) { + struct seco_soc_info *soc_data = (void *)data; - s_info = (void *)data; - var_se_info.board_type = 0; - var_se_info.soc_id = info_list->soc_id; - var_se_info.soc_rev = s_info->d_info.soc_rev; - load_fw->imem.state = s_info->d_addn_info.imem_state; + var_se_info.board_type = soc_data->board_type; + var_se_info.soc_id = soc_data->soc_id; + var_se_info.soc_rev = soc_data->soc_rev; + } else { + s_info = (void *)data; + + var_se_info.board_type = 0; + var_se_info.soc_id = info_list->soc_id; + var_se_info.soc_rev = s_info->d_info.soc_rev; + load_fw->imem.state = s_info->d_addn_info.imem_state; + } } else { dev_err(priv->dev, "Failed to fetch SoC revision."); if (info_list->soc_register) @@ -706,6 +858,15 @@ static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx) if (!se_shared_mem_mgmt->non_secure_mem.ptr) return -ENOMEM; + if (priv->flags & SCU_MEM_CFG) { + if (imx_scu_mem_access(dev_ctx)) { + dev_err(dev_ctx->priv->dev, + "%s: Failed to share access to shared memory\n", + dev_ctx->devname); + return -EPERM; + } + } + se_shared_mem_mgmt->non_secure_mem.size = MAX_DATA_SIZE_PER_USER; se_shared_mem_mgmt->non_secure_mem.pos = 0; @@ -1056,6 +1217,13 @@ static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx, if_info.se_if_id = 0; if_info.interrupt_idx = 0; if_info.tz = 0; + if (get_se_soc_id(priv) == SOC_ID_OF_IMX8DXL || + get_se_soc_id(priv) == SOC_ID_OF_IMX8QXP) { + if_info.se_if_id = info->se_if_id + 1; + if (priv->if_defs->se_if_type > SE_TYPE_ID_SHE) + if_info.se_if_id++; + } + if_info.did = info->se_if_did; if_info.cmd_tag = priv->if_defs->cmd_tag; if_info.rsp_tag = priv->if_defs->rsp_tag; @@ -1118,10 +1286,18 @@ static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx, } /* Select the shared memory to be used for this buffer. */ - if (io.flags & SE_IO_BUF_FLAGS_USE_MU_BUF) + if (io.flags & SE_IO_BUF_FLAGS_USE_MU_BUF) { shared_mem = &dev_ctx->priv->mu_mem; - else - shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem; + } else { + if ((io.flags & SE_IO_BUF_FLAGS_USE_SEC_MEM) && + (dev_ctx->priv->flags & SCU_MEM_CFG)) { + /* App requires to use secure memory for this buffer.*/ + shared_mem = &dev_ctx->se_shared_mem_mgmt.secure_mem; + } else { + /* No specific requirement for this buffer. */ + shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem; + } + } /* Check there is enough space in the shared memory. */ dev_dbg(dev_ctx->priv->dev, @@ -1144,6 +1320,14 @@ static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx, shared_mem->pos += round_up(io.length, 8u); io.ele_addr = (u64)shared_mem->dma_addr + pos; + if (dev_ctx->priv->flags & SCU_MEM_CFG) { + if ((io.flags & SE_IO_BUF_FLAGS_USE_SEC_MEM) && + !(io.flags & SE_IO_BUF_FLAGS_USE_SHORT_ADDR)) { + /*Add base address to get full address.#TODO: Add API*/ + io.ele_addr += SECURE_RAM_BASE_ADDRESS_SCU; + } + } + if (dev_ctx->priv->mu_mem.pos) memset_io(shared_mem->ptr + pos, 0, io.length); else @@ -1210,6 +1394,69 @@ exit: return err; } +/* Configure the shared memory according to user config */ +static int se_ioctl_shared_mem_cfg_handler(struct file *fp, + struct se_if_device_ctx *dev_ctx, + unsigned long arg) +{ + struct se_ioctl_shared_mem_cfg cfg; + int err = -EINVAL; + + /* Check if not already configured. */ + if (dev_ctx->se_shared_mem_mgmt.secure_mem.dma_addr != 0u) { + dev_err(dev_ctx->priv->dev, "Shared memory not configured\n"); + return err; + } + + err = (int)copy_from_user(&cfg, (u8 *)arg, sizeof(cfg)); + if (err) { + dev_err(dev_ctx->priv->dev, "Fail copy memory config\n"); + err = -EFAULT; + return err; + } + + dev_dbg(dev_ctx->priv->dev, "cfg offset: %u(%d)\n", cfg.base_offset, cfg.size); + + err = imx_scu_sec_mem_cfg(fp, cfg.base_offset, cfg.size); + if (err) { + dev_err(dev_ctx->priv->dev, "Failt to map memory\n"); + err = -ENOMEM; + return err; + } + + return err; +} + +static int se_ioctl_signed_msg_handler(struct file *fp, + struct se_if_device_ctx *dev_ctx, + unsigned long arg) +{ + struct se_ioctl_signed_message msg; + int err; + + err = copy_from_user(&msg, (u8 *)arg, sizeof(msg)); + if (err) { + dev_err(dev_ctx->priv->dev, "Failed to copy from user: %d\n", err); + return -EFAULT; + } + + err = imx_scu_signed_msg(fp, msg.message, msg.msg_size, &msg.error_code); + if (err) { + dev_err(dev_ctx->priv->dev, + "Failed to send signed message: %d\n", + err); + return err; + } + + err = copy_to_user((u8 *)arg, &msg, sizeof(msg)); + if (err) { + dev_err(dev_ctx->priv->dev, "Failed to copy to user: %d\n", err); + return -EFAULT; + } + + return err; +} + /* * File operations for user-space */ @@ -1438,6 +1685,18 @@ static long se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) case SE_IOCTL_CMD_SEND_RCV_RSP: err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg); break; + case SE_IOCTL_SHARED_BUF_CFG: + if (priv->flags & SCU_MEM_CFG) + err = se_ioctl_shared_mem_cfg_handler(fp, dev_ctx, arg); + else + err = -EPERM; + break; + case SE_IOCTL_SIGNED_MESSAGE: + if (priv->flags & SCU_SIGNED_MSG_CFG) + err = se_ioctl_signed_msg_handler(fp, dev_ctx, arg); + else + err = -EPERM; + break; default: err = -EINVAL; dev_dbg(priv->dev, @@ -1608,13 +1867,18 @@ static int se_if_probe(struct platform_device *pdev) priv->se_mb_cl.knows_txdone = true; priv->se_mb_cl.rx_callback = se_if_rx_callback; - ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, - MBOX_TX_NAME); + ret = se_if_request_channel(dev, &priv->tx_chan, + &priv->se_mb_cl, + (info_list->soc_id == SOC_ID_OF_IMX8DXL) ? + MBOX_TXDB_NAME : MBOX_TX_NAME); if (ret) goto exit; - ret = se_if_request_channel(dev, &priv->rx_chan, - &priv->se_mb_cl, MBOX_RX_NAME); + ret = se_if_request_channel(dev, + &priv->rx_chan, + &priv->se_mb_cl, + (info_list->soc_id == SOC_ID_OF_IMX8DXL) ? + MBOX_RXDB_NAME : MBOX_RX_NAME); if (ret) goto exit; diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h index 64d91f18c3fe..6528eaf1145b 100644 --- a/drivers/firmware/imx/se_ctrl.h +++ b/drivers/firmware/imx/se_ctrl.h @@ -131,11 +131,14 @@ struct se_if_priv { struct mbox_client se_mb_cl; struct mbox_chan *tx_chan, *rx_chan; + u32 flags; struct se_shared_mem mu_mem; struct gen_pool *mem_pool; const struct se_if_defines *if_defs; struct se_lg_fl_info lg_fl_info; + struct imx_sc_ipc *ipc_scu; + u8 part_owner; struct se_if_device_ctx *priv_dev_ctx; struct list_head dev_ctx_list; u32 active_devctx_count; @@ -147,7 +150,7 @@ struct se_if_priv { #define SE_DUMP_MU_RCV_BUFS 2 #define SE_DUMP_KDEBUG_BUFS 3 -uint32_t get_se_soc_id(struct se_if_priv *priv); +u32 get_se_soc_id(struct se_if_priv *priv); int se_dump_to_logfl(struct se_if_device_ctx *dev_ctx, u8 caller_type, int buf_size, const char *buf, ...); diff --git a/drivers/firmware/imx/seco_init.c b/drivers/firmware/imx/seco_init.c new file mode 100644 index 000000000000..baf4d7d795c8 --- /dev/null +++ b/drivers/firmware/imx/seco_init.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP + * + * File containing client-side RPC functions for the SECO service. These + * function are ported to clients that communicate to the SC. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "seco_init.h" + +static const struct soc_device_attribute soc_info_matches[] = { + { .soc_id = "i.MX8DXL", + .revision = "1.1", + .data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8DXL, .soc_rev = SOC_REV_A1,} + }, + { .soc_id = "i.MX8DXL", + .revision = "1.2", + .data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8DXL, .soc_rev = SOC_REV_B0,} + }, + { .soc_id = "i.MX8QXP", + .revision = "1.1", + .data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QXP, .soc_rev = SOC_REV_B0,} + }, + { .soc_id = "i.MX8QXP", + .revision = "1.2", + .data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QXP, .soc_rev = SOC_REV_C0,} + }, + { .soc_id = "i.MX8QM", + .revision = "1.1", + .data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QM, .soc_rev = SOC_REV_B0,} + }, + { .soc_id = "i.MX8QM", + .revision = "1.2", + .data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QM, .soc_rev = SOC_REV_C0,} + }, + { } +}; + +static int read_fuse(struct se_if_priv *priv, u32 id, u32 *value, u8 mul) +{ + struct nvmem_device *nvmem; + u32 size_to_read = mul * sizeof(u32); + struct device_node *np; + int ret = 0; + + np = priv->dev->of_node; + if (!of_get_property(np, "nvmem", NULL)) + return -EPERM; + + nvmem = devm_nvmem_device_get(priv->dev, NULL); + if (IS_ERR(nvmem)) { + ret = PTR_ERR(nvmem); + + if (ret != -EPROBE_DEFER) + dev_err(priv->dev, "Failed to retrieve nvmem node\n"); + + return ret; + } + + ret = nvmem_device_read(nvmem, id, size_to_read, value); + if (ret < 0) { + dev_err(priv->dev, "Failed to read fuse %d: %d\n", id, ret); + return ret; + } + + if (ret != size_to_read) { + dev_err(priv->dev, "Read only %d instead of %d\n", ret, + size_to_read); + return -ENOMEM; + } + + dev_dbg(priv->dev, "FUSE value 0x%x 0x%x 0x%x 0x%x\n", + value[0], value[1], + value[2], value[3]); + + devm_nvmem_device_put(priv->dev, nvmem); + + return 0; +} + +/* function to fetch SoC revision on the SECO platform */ +int seco_fetch_soc_info(struct se_if_priv *priv, void *data) +{ + struct seco_soc_info *soc_data = data; + const struct soc_device_attribute *imx_soc_match; + u32 fuse_val[4] = {0xFF}; + int err = 0; + + imx_soc_match = soc_device_match(soc_info_matches); + if (!imx_soc_match || !imx_soc_match->data) { + err = -EINVAL; + goto exit; + } + err = read_fuse(priv, 8, (u32 *)&fuse_val, 4); + if (err) { + dev_err(priv->dev, "Fail to read FIPS fuse\n"); + return err; + } + + if (fuse_val[2] & SECO_NON_FIPS) + soc_data->board_type = IMX8DXL_DL1; + else if (fuse_val[0] & V2X_NON_FIPS) + soc_data->board_type = IMX8DXL_DL3; + else if (!fuse_val[0] && !fuse_val[2]) + soc_data->board_type = IMX8DXL_DL2; + + soc_data->soc_id = ((const struct seco_soc_info *)imx_soc_match->data)->soc_id; + soc_data->soc_rev = ((const struct seco_soc_info *)imx_soc_match->data)->soc_rev; + +exit: + return err; +} + +int imx_scu_init_fw(struct se_if_priv *priv) +{ + int ret; + + if (!priv) { + ret = -EINVAL; + goto exit; + } + + ret = imx_scu_get_handle(&priv->ipc_scu); + if (ret) { + dev_err(priv->dev, "Fail to retrieve IPC handle\n"); + goto exit; + } + + ret = imx_sc_rm_get_resource_owner(priv->ipc_scu, IMX_SC_R_SECO, &priv->part_owner); + if (ret) { + dev_err(priv->dev, "Fail get owner of SECO resource\n"); + goto exit; + } + + if (!ret) { + priv->flags |= SCU_MEM_CFG; + + if (get_se_soc_id(priv) == SOC_ID_OF_IMX8DXL && + (priv->if_defs->se_if_type == SE_TYPE_ID_SHE || + priv->if_defs->se_if_type == SE_TYPE_ID_HSM)) + priv->flags |= SCU_SIGNED_MSG_CFG; + } +exit: + return ret; +} + +int imx_scu_sec_mem_cfg(struct file *fp, u32 offset, u32 size) +{ + struct se_if_device_ctx *dev_ctx = fp->private_data; + u64 high_boundary; + int ret = 0; + + high_boundary = offset; + if (high_boundary > SECURE_RAM_SIZE) { + dev_err(dev_ctx->priv->dev, "base offset is over secure memory\n"); + return -ENOMEM; + } + + high_boundary += size; + if (high_boundary > SECURE_RAM_SIZE) { + dev_err(dev_ctx->priv->dev, "total memory is over secure memory\n"); + return -ENOMEM; + } + + dev_ctx->se_shared_mem_mgmt.secure_mem.dma_addr = (dma_addr_t)offset; + dev_ctx->se_shared_mem_mgmt.secure_mem.size = size; + dev_ctx->se_shared_mem_mgmt.secure_mem.pos = 0; + dev_ctx->se_shared_mem_mgmt.secure_mem.ptr = + devm_ioremap(dev_ctx->priv->dev, + (phys_addr_t)(SECURE_RAM_BASE_ADDRESS + + (u64)dev_ctx->se_shared_mem_mgmt.secure_mem.dma_addr), + dev_ctx->se_shared_mem_mgmt.secure_mem.size); + if (!dev_ctx->se_shared_mem_mgmt.secure_mem.ptr) { + dev_err(dev_ctx->priv->dev, "Failed to map secure memory\n"); + return -ENOMEM; + } + + return ret; +} + +int imx_scu_mem_access(struct se_if_device_ctx *dev_ctx) +{ + struct se_if_priv *priv = dev_ctx->priv; + u8 mr; + u64 addr; + int ret; + + addr = dev_ctx->se_shared_mem_mgmt.non_secure_mem.dma_addr; + + ret = imx_sc_rm_find_memreg(priv->ipc_scu, + &mr, + addr, + addr + MAX_DATA_SIZE_PER_USER); + if (ret) { + dev_err(dev_ctx->priv->dev, + "%s: Fail find memreg\n", dev_ctx->devname); + return ret; + } + + ret = imx_sc_rm_set_memreg_permissions(priv->ipc_scu, mr, + priv->part_owner, + IMX_SC_RM_PERM_FULL); + if (ret) { + dev_err(dev_ctx->priv->dev, + "%s: Fail set permission for resource\n", + dev_ctx->devname); + return ret; + } + + return ret; +} + +int imx_scu_signed_msg(struct file *fp, + u8 *msg, + u32 size, + u32 *error) +{ + struct se_if_device_ctx *dev_ctx = fp->private_data; + struct se_if_priv *priv = dev_ctx->priv; + struct se_shared_mem *shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem; + int err; + u64 addr; + u32 pos; + + /* Check there is enough space in the shared memory. */ + if (size >= shared_mem->size - shared_mem->pos) { + dev_err(dev_ctx->priv->dev, + "Not enough mem: %d left, %d required\n", + shared_mem->size - shared_mem->pos, size); + return -ENOMEM; + } + + /* Allocate space in shared memory. 8 bytes aligned. */ + pos = shared_mem->pos; + + /* get physical address from the pos */ + addr = (u64)shared_mem->dma_addr + pos; + + /* copy signed message from user space to this allocated buffer */ + err = copy_from_user(shared_mem->ptr + pos, msg, size); + if (err) { + dev_err(dev_ctx->priv->dev, + "Failed to signed message from user: %d\n", + err); + return -EFAULT; + } + + *error = imx_sc_seco_sab_msg(priv->ipc_scu, addr); + err = *error; + if (err) + dev_err(dev_ctx->priv->dev, "Failt to send signed message\n"); + + return err; +} diff --git a/drivers/firmware/imx/seco_init.h b/drivers/firmware/imx/seco_init.h new file mode 100644 index 000000000000..8b3d86350695 --- /dev/null +++ b/drivers/firmware/imx/seco_init.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2024 NXP + */ + +#ifndef SECO_H +#define SECO_H + +#include "se_ctrl.h" + +#define SCU_MEM_CFG BIT(1) +#define SCU_SIGNED_MSG_CFG BIT(2) +#define SECO_SUCCESS_IND 0x00 + +#define SOC_REV_A1 0xA100 +#define SOC_REV_B0 0xB000 +#define SOC_REV_C0 0xC000 + +#define SECURE_RAM_BASE_ADDRESS (0x31800000ULL) +#define SECURE_RAM_BASE_ADDRESS_SCU (0x20800000u) +#define SECURE_RAM_SIZE (0x10000ULL) + +#define V2X_NON_FIPS 0x00000c00 +#define SECO_NON_FIPS 0x00000018 + +#define IMX8DXL_DL1 0x1 +#define IMX8DXL_DL2 0x2 +#define IMX8DXL_DL3 0x4 + +struct seco_soc_info { + u16 soc_id; + u16 soc_rev; + u16 board_type; +}; + +int seco_fetch_soc_info(struct se_if_priv *priv, void *data); +int imx_scu_init_fw(struct se_if_priv *priv); +int imx_scu_sec_mem_cfg(struct file *fp, u32 offset, u32 size); +int imx_scu_mem_access(struct se_if_device_ctx *dev_ctx); +int imx_scu_signed_msg(struct file *fp, + u8 *msg, + u32 size, + u32 *error); +#endif diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h index 61a6bf19e91b..3bab17f94d5a 100644 --- a/include/linux/firmware/imx/se_api.h +++ b/include/linux/firmware/imx/se_api.h @@ -9,7 +9,11 @@ #include #define SOC_ID_OF_IMX8ULP 0x084D +#define SOC_ID_OF_IMX8DXL 0xE +#define SOC_ID_OF_IMX8QM 0x1 +#define SOC_ID_OF_IMX8QXP 0x2 #define SOC_ID_OF_IMX93 0x9300 +#define SOC_ID_OF_IMX95 0x9500 #define OTP_UNIQ_ID 0x01 #define OTFAD_CONFIG 0x2 diff --git a/include/uapi/linux/se_ioctl.h b/include/uapi/linux/se_ioctl.h index d31941e521c1..c4894c51efc6 100644 --- a/include/uapi/linux/se_ioctl.h +++ b/include/uapi/linux/se_ioctl.h @@ -61,6 +61,13 @@ struct se_ioctl_cmd_snd_rcv_rsp_info { struct se_ioctl_get_soc_info { __u16 soc_id; __u16 soc_rev; + __u8 board_type; +}; + +struct se_ioctl_signed_message { + __u8 *message; + __u32 msg_size; + __u32 error_code; }; /* IO Buffer Flags */ @@ -68,6 +75,7 @@ struct se_ioctl_get_soc_info { #define SE_IO_BUF_FLAGS_IS_INPUT (0x01u) #define SE_IO_BUF_FLAGS_USE_SEC_MEM (0x02u) #define SE_IO_BUF_FLAGS_USE_SHORT_ADDR (0x04u) +#define SE_IO_BUF_FLAGS_USE_MU_BUF (0x08u) #define SE_IO_BUF_FLAGS_IS_IN_OUT (0x10u) /* IOCTLS */ @@ -80,6 +88,11 @@ struct se_ioctl_get_soc_info { */ #define SE_IOCTL_ENABLE_CMD_RCV _IO(SE_IOCTL, 0x01) +/* + * ioctl to get configure the SCU shared buffer. + */ +#define SE_IOCTL_SHARED_BUF_CFG _IOW(SE_IOCTL, 0x02, \ + struct se_ioctl_shared_mem_cfg) /* * ioctl to get the buffer allocated from the memory, which is shared * between kernel and FW. @@ -99,6 +112,13 @@ struct se_ioctl_get_soc_info { */ #define SE_IOCTL_GET_MU_INFO _IOR(SE_IOCTL, 0x04, \ struct se_ioctl_get_if_info) + +/* + * ioctl to send signed message to SE. + */ +#define SE_IOCTL_SIGNED_MESSAGE _IOR(SE_IOCTL, 0x05, \ + struct se_ioctl_signed_message) + /* * ioctl to get SoC Info from user-space. */