]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/tee/optee/rpmb.c
dm: core: Create a new header file for 'compat' features
[thirdparty/u-boot.git] / drivers / tee / optee / rpmb.c
CommitLineData
232cfd6d
JW
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>
336d4615 11#include <dm/device_compat.h>
232cfd6d
JW
12
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 }
75 if (!(mmc->version & MMC_VERSION_MMC)) {
76 debug("Device id %d is not an eMMC device\n", dev_id);
77 return NULL;
78 }
79 if (mmc->version < MMC_VERSION_4_41) {
80 debug("Device id %d: RPMB not supported before version 4.41\n",
81 dev_id);
82 return NULL;
83 }
84
85 priv->rpmb_original_part = mmc_get_blk_desc(mmc)->hwpart;
86
87 rc = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_id, MMC_PART_RPMB);
88 if (rc) {
89 debug("Device id %d: cannot select RPMB partition: %d\n",
90 dev_id, rc);
91 return NULL;
92 }
93
94 priv->rpmb_mmc = mmc;
95 priv->rpmb_dev_id = dev_id;
96 return mmc;
97}
98
99static u32 rpmb_get_dev_info(u16 dev_id, struct rpmb_dev_info *info)
100{
101 struct mmc *mmc = find_mmc_device(dev_id);
2464b229 102 int i;
232cfd6d
JW
103
104 if (!mmc)
105 return TEE_ERROR_ITEM_NOT_FOUND;
106
107 if (!mmc->ext_csd)
108 return TEE_ERROR_GENERIC;
109
2464b229
JRO
110 for (i = 0; i < ARRAY_SIZE(mmc->cid); i++)
111 ((u32 *) info->cid)[i] = cpu_to_be32(mmc->cid[i]);
112
232cfd6d
JW
113 info->rel_wr_sec_c = mmc->ext_csd[222];
114 info->rpmb_size_mult = mmc->ext_csd[168];
115 info->ret_code = RPMB_CMD_GET_DEV_INFO_RET_OK;
116
117 return TEE_SUCCESS;
118}
119
120static u32 rpmb_process_request(struct optee_private *priv, void *req,
121 ulong req_size, void *rsp, ulong rsp_size)
122{
123 struct rpmb_req *sreq = req;
124 struct mmc *mmc;
125
126 if (req_size < sizeof(*sreq))
127 return TEE_ERROR_BAD_PARAMETERS;
128
129 switch (sreq->cmd) {
130 case RPMB_CMD_DATA_REQ:
131 mmc = get_mmc(priv, sreq->dev_id);
132 if (!mmc)
133 return TEE_ERROR_ITEM_NOT_FOUND;
134 if (mmc_rpmb_route_frames(mmc, RPMB_REQ_DATA(req),
135 req_size - sizeof(struct rpmb_req),
136 rsp, rsp_size))
137 return TEE_ERROR_BAD_PARAMETERS;
138 return TEE_SUCCESS;
139
140 case RPMB_CMD_GET_DEV_INFO:
141 if (req_size != sizeof(struct rpmb_req) ||
142 rsp_size != sizeof(struct rpmb_dev_info)) {
143 debug("Invalid req/rsp size\n");
144 return TEE_ERROR_BAD_PARAMETERS;
145 }
146 return rpmb_get_dev_info(sreq->dev_id, rsp);
147
148 default:
149 debug("Unsupported RPMB command: %d\n", sreq->cmd);
150 return TEE_ERROR_BAD_PARAMETERS;
151 }
152}
153
154void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg)
155{
156 struct tee_shm *req_shm;
157 struct tee_shm *rsp_shm;
158 void *req_buf;
159 void *rsp_buf;
160 ulong req_size;
161 ulong rsp_size;
162
163 if (arg->num_params != 2 ||
164 arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT ||
165 arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) {
166 arg->ret = TEE_ERROR_BAD_PARAMETERS;
167 return;
168 }
169
170 req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref;
171 req_buf = (u8 *)req_shm->addr + arg->params[0].u.rmem.offs;
172 req_size = arg->params[0].u.rmem.size;
173
174 rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref;
175 rsp_buf = (u8 *)rsp_shm->addr + arg->params[1].u.rmem.offs;
176 rsp_size = arg->params[1].u.rmem.size;
177
178 arg->ret = rpmb_process_request(dev_get_priv(dev), req_buf, req_size,
179 rsp_buf, rsp_size);
180}
181
182void optee_suppl_rpmb_release(struct udevice *dev)
183{
184 release_mmc(dev_get_priv(dev));
185}