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