xref: /openbmc/u-boot/drivers/tee/optee/rpmb.c (revision 5c8fd32b)
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