Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | // SPDX-License-Identifier: BSD-2-Clause /* * Copyright (c) 2018 Linaro Limited */ #include <dm.h> #include <log.h> #include <tee.h> #include <mmc.h> #include <dm/device_compat.h> #include "optee_msg.h" #include "optee_private.h" /* * Request and response definitions must be in sync with the secure side of * OP-TEE. */ /* Request */ struct rpmb_req { u16 cmd; #define RPMB_CMD_DATA_REQ 0x00 #define RPMB_CMD_GET_DEV_INFO 0x01 u16 dev_id; u16 block_count; /* Optional data frames (rpmb_data_frame) follow */ }; #define RPMB_REQ_DATA(req) ((void *)((struct rpmb_req *)(req) + 1)) /* Response to device info request */ struct rpmb_dev_info { u8 cid[16]; u8 rpmb_size_mult; /* EXT CSD-slice 168: RPMB Size */ u8 rel_wr_sec_c; /* EXT CSD-slice 222: Reliable Write Sector */ /* Count */ u8 ret_code; #define RPMB_CMD_GET_DEV_INFO_RET_OK 0x00 #define RPMB_CMD_GET_DEV_INFO_RET_ERROR 0x01 }; static void release_mmc(struct optee_private *priv) { int rc; if (!priv->rpmb_mmc) return; rc = blk_select_hwpart_devnum(UCLASS_MMC, priv->rpmb_dev_id, priv->rpmb_original_part); if (rc) debug("%s: blk_select_hwpart_devnum() failed: %d\n", __func__, rc); priv->rpmb_mmc = NULL; } static struct mmc *get_mmc(struct optee_private *priv, int dev_id) { struct mmc *mmc; int rc; if (priv->rpmb_mmc && priv->rpmb_dev_id == dev_id) return priv->rpmb_mmc; release_mmc(priv); mmc = find_mmc_device(dev_id); if (!mmc) { debug("Cannot find RPMB device\n"); return NULL; } if (mmc_init(mmc)) { log(LOGC_BOARD, LOGL_ERR, "%s:MMC device %d init failed\n", __func__, dev_id); return NULL; } if (!(mmc->version & MMC_VERSION_MMC)) { debug("Device id %d is not an eMMC device\n", dev_id); return NULL; } if (mmc->version < MMC_VERSION_4_41) { debug("Device id %d: RPMB not supported before version 4.41\n", dev_id); return NULL; } priv->rpmb_original_part = mmc_get_blk_desc(mmc)->hwpart; rc = blk_select_hwpart_devnum(UCLASS_MMC, dev_id, MMC_PART_RPMB); if (rc) { debug("Device id %d: cannot select RPMB partition: %d\n", dev_id, rc); return NULL; } priv->rpmb_mmc = mmc; priv->rpmb_dev_id = dev_id; return mmc; } static u32 rpmb_get_dev_info(u16 dev_id, struct rpmb_dev_info *info) { struct mmc *mmc = find_mmc_device(dev_id); int i; if (!mmc) return TEE_ERROR_ITEM_NOT_FOUND; if (mmc_init(mmc)) { log(LOGC_BOARD, LOGL_ERR, "%s:MMC device %d init failed\n", __func__, dev_id); return TEE_ERROR_NOT_SUPPORTED; } if (!mmc->ext_csd) return TEE_ERROR_GENERIC; for (i = 0; i < ARRAY_SIZE(mmc->cid); i++) ((u32 *) info->cid)[i] = cpu_to_be32(mmc->cid[i]); info->rel_wr_sec_c = mmc->ext_csd[222]; info->rpmb_size_mult = mmc->ext_csd[168]; info->ret_code = RPMB_CMD_GET_DEV_INFO_RET_OK; return TEE_SUCCESS; } static u32 rpmb_process_request(struct optee_private *priv, void *req, ulong req_size, void *rsp, ulong rsp_size) { struct rpmb_req *sreq = req; struct mmc *mmc; if (req_size < sizeof(*sreq)) return TEE_ERROR_BAD_PARAMETERS; switch (sreq->cmd) { case RPMB_CMD_DATA_REQ: mmc = get_mmc(priv, sreq->dev_id); if (!mmc) return TEE_ERROR_ITEM_NOT_FOUND; if (mmc_rpmb_route_frames(mmc, RPMB_REQ_DATA(req), req_size - sizeof(struct rpmb_req), rsp, rsp_size)) return TEE_ERROR_BAD_PARAMETERS; return TEE_SUCCESS; case RPMB_CMD_GET_DEV_INFO: if (req_size != sizeof(struct rpmb_req) || rsp_size != sizeof(struct rpmb_dev_info)) { debug("Invalid req/rsp size\n"); return TEE_ERROR_BAD_PARAMETERS; } return rpmb_get_dev_info(sreq->dev_id, rsp); default: debug("Unsupported RPMB command: %d\n", sreq->cmd); return TEE_ERROR_BAD_PARAMETERS; } } void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg) { struct tee_shm *req_shm; struct tee_shm *rsp_shm; void *req_buf; void *rsp_buf; ulong req_size; ulong rsp_size; if (arg->num_params != 2 || arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT || arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) { arg->ret = TEE_ERROR_BAD_PARAMETERS; return; } req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref; req_buf = (u8 *)req_shm->addr + arg->params[0].u.rmem.offs; req_size = arg->params[0].u.rmem.size; rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref; rsp_buf = (u8 *)rsp_shm->addr + arg->params[1].u.rmem.offs; rsp_size = arg->params[1].u.rmem.size; arg->ret = rpmb_process_request(dev_get_priv(dev), req_buf, req_size, rsp_buf, rsp_size); } void optee_suppl_rpmb_release(struct udevice *dev) { release_mmc(dev_get_priv(dev)); } |