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