blob: bacced6af6cf56691b9a6cfb3db4aa4393c6255e [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
Jens Wiklanderf1420dd2018-09-25 16:40:14 +02006#include <dm.h>
7#include <log.h>
8#include <tee.h>
9#include <mmc.h>
Simon Glass9bc15642020-02-03 07:36:16 -070010#include <dm/device_compat.h>
Jens Wiklanderf1420dd2018-09-25 16:40:14 +020011
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 */
21struct 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 */
33struct 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
43static void release_mmc(struct optee_private *priv)
44{
45 int rc;
46
47 if (!priv->rpmb_mmc)
48 return;
49
Simon Glassdbfa32c2022-08-11 19:34:59 -060050 rc = blk_select_hwpart_devnum(UCLASS_MMC, priv->rpmb_dev_id,
Jens Wiklanderf1420dd2018-09-25 16:40:14 +020051 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
59static 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 }
Judy Wangf070e642022-05-03 14:04:40 +080074 if (mmc_init(mmc)) {
75 log(LOGC_BOARD, LOGL_ERR, "%s:MMC device %d init failed\n", __func__, dev_id);
76 return NULL;
77 }
Jens Wiklanderf1420dd2018-09-25 16:40:14 +020078 if (!(mmc->version & MMC_VERSION_MMC)) {
79 debug("Device id %d is not an eMMC device\n", dev_id);
80 return NULL;
81 }
82 if (mmc->version < MMC_VERSION_4_41) {
83 debug("Device id %d: RPMB not supported before version 4.41\n",
84 dev_id);
85 return NULL;
86 }
87
88 priv->rpmb_original_part = mmc_get_blk_desc(mmc)->hwpart;
89
Simon Glassdbfa32c2022-08-11 19:34:59 -060090 rc = blk_select_hwpart_devnum(UCLASS_MMC, dev_id, MMC_PART_RPMB);
Jens Wiklanderf1420dd2018-09-25 16:40:14 +020091 if (rc) {
92 debug("Device id %d: cannot select RPMB partition: %d\n",
93 dev_id, rc);
94 return NULL;
95 }
96
97 priv->rpmb_mmc = mmc;
98 priv->rpmb_dev_id = dev_id;
99 return mmc;
100}
101
102static u32 rpmb_get_dev_info(u16 dev_id, struct rpmb_dev_info *info)
103{
104 struct mmc *mmc = find_mmc_device(dev_id);
Jorge Ramirez-Ortiz094c7472019-11-26 17:19:34 +0100105 int i;
Jens Wiklanderf1420dd2018-09-25 16:40:14 +0200106
107 if (!mmc)
108 return TEE_ERROR_ITEM_NOT_FOUND;
109
Judy Wangf070e642022-05-03 14:04:40 +0800110 if (mmc_init(mmc)) {
111 log(LOGC_BOARD, LOGL_ERR, "%s:MMC device %d init failed\n", __func__, dev_id);
112 return TEE_ERROR_NOT_SUPPORTED;
113 }
114
Jens Wiklanderf1420dd2018-09-25 16:40:14 +0200115 if (!mmc->ext_csd)
116 return TEE_ERROR_GENERIC;
117
Jorge Ramirez-Ortiz094c7472019-11-26 17:19:34 +0100118 for (i = 0; i < ARRAY_SIZE(mmc->cid); i++)
119 ((u32 *) info->cid)[i] = cpu_to_be32(mmc->cid[i]);
120
Jens Wiklanderf1420dd2018-09-25 16:40:14 +0200121 info->rel_wr_sec_c = mmc->ext_csd[222];
122 info->rpmb_size_mult = mmc->ext_csd[168];
123 info->ret_code = RPMB_CMD_GET_DEV_INFO_RET_OK;
124
125 return TEE_SUCCESS;
126}
127
128static u32 rpmb_process_request(struct optee_private *priv, void *req,
129 ulong req_size, void *rsp, ulong rsp_size)
130{
131 struct rpmb_req *sreq = req;
132 struct mmc *mmc;
133
134 if (req_size < sizeof(*sreq))
135 return TEE_ERROR_BAD_PARAMETERS;
136
137 switch (sreq->cmd) {
138 case RPMB_CMD_DATA_REQ:
139 mmc = get_mmc(priv, sreq->dev_id);
140 if (!mmc)
141 return TEE_ERROR_ITEM_NOT_FOUND;
142 if (mmc_rpmb_route_frames(mmc, RPMB_REQ_DATA(req),
143 req_size - sizeof(struct rpmb_req),
144 rsp, rsp_size))
145 return TEE_ERROR_BAD_PARAMETERS;
146 return TEE_SUCCESS;
147
148 case RPMB_CMD_GET_DEV_INFO:
149 if (req_size != sizeof(struct rpmb_req) ||
150 rsp_size != sizeof(struct rpmb_dev_info)) {
151 debug("Invalid req/rsp size\n");
152 return TEE_ERROR_BAD_PARAMETERS;
153 }
154 return rpmb_get_dev_info(sreq->dev_id, rsp);
155
156 default:
157 debug("Unsupported RPMB command: %d\n", sreq->cmd);
158 return TEE_ERROR_BAD_PARAMETERS;
159 }
160}
161
162void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg)
163{
164 struct tee_shm *req_shm;
165 struct tee_shm *rsp_shm;
166 void *req_buf;
167 void *rsp_buf;
168 ulong req_size;
169 ulong rsp_size;
170
171 if (arg->num_params != 2 ||
172 arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT ||
173 arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) {
174 arg->ret = TEE_ERROR_BAD_PARAMETERS;
175 return;
176 }
177
178 req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref;
179 req_buf = (u8 *)req_shm->addr + arg->params[0].u.rmem.offs;
180 req_size = arg->params[0].u.rmem.size;
181
182 rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref;
183 rsp_buf = (u8 *)rsp_shm->addr + arg->params[1].u.rmem.offs;
184 rsp_size = arg->params[1].u.rmem.size;
185
186 arg->ret = rpmb_process_request(dev_get_priv(dev), req_buf, req_size,
187 rsp_buf, rsp_size);
188}
189
190void optee_suppl_rpmb_release(struct udevice *dev)
191{
192 release_mmc(dev_get_priv(dev));
193}