Commit 232cfd6d9152fd2a4e7113faec51db2a9ab8c6bd
Committed by
Tom Rini
1 parent
7ab5630a42
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
optee: support routing of rpmb data frames to mmc
Adds support in optee supplicant to route signed (MACed) RPMB frames from OP-TEE Secure OS to MMC and vice versa to manipulate the RPMB partition. Tested-by: Igor Opaniuk <igor.opaniuk@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org> Reviewed-by: Simon Glass <sjg@chromium.org>
Showing 5 changed files with 247 additions and 1 deletions Side-by-side Diff
drivers/tee/optee/Makefile
drivers/tee/optee/core.c
... | ... | @@ -315,6 +315,13 @@ |
315 | 315 | param.a3 = res.a3; |
316 | 316 | handle_rpc(dev, ¶m, &page_list); |
317 | 317 | } else { |
318 | + /* | |
319 | + * In case we've accessed RPMB to serve an RPC | |
320 | + * request we need to restore the previously | |
321 | + * selected partition as the caller may expect it | |
322 | + * to remain unchanged. | |
323 | + */ | |
324 | + optee_suppl_rpmb_release(dev); | |
318 | 325 | return call_err_to_res(res.a0); |
319 | 326 | } |
320 | 327 | } |
... | ... | @@ -651,5 +658,6 @@ |
651 | 658 | .probe = optee_probe, |
652 | 659 | .ops = &optee_ops, |
653 | 660 | .platdata_auto_alloc_size = sizeof(struct optee_pdata), |
661 | + .priv_auto_alloc_size = sizeof(struct optee_private), | |
654 | 662 | }; |
drivers/tee/optee/optee_private.h
... | ... | @@ -6,8 +6,61 @@ |
6 | 6 | #ifndef __OPTEE_PRIVATE_H |
7 | 7 | #define __OPTEE_PRIVATE_H |
8 | 8 | |
9 | +#include <tee.h> | |
10 | +#include <log.h> | |
11 | + | |
12 | +/** | |
13 | + * struct optee_private - OP-TEE driver private data | |
14 | + * @rpmb_mmc: mmc device for the RPMB partition | |
15 | + * @rpmb_dev_id: mmc device id matching @rpmb_mmc | |
16 | + * @rpmb_original_part: the previosly active partition on the mmc device, | |
17 | + * used to restore active the partition when the RPMB | |
18 | + * accesses are finished | |
19 | + */ | |
20 | +struct optee_private { | |
21 | + struct mmc *rpmb_mmc; | |
22 | + int rpmb_dev_id; | |
23 | + int rpmb_original_part; | |
24 | +}; | |
25 | + | |
26 | +struct optee_msg_arg; | |
27 | + | |
28 | +void optee_suppl_cmd(struct udevice *dev, struct tee_shm *shm_arg, | |
29 | + void **page_list); | |
30 | + | |
31 | +#ifdef CONFIG_SUPPORT_EMMC_RPMB | |
32 | +/** | |
33 | + * optee_suppl_cmd_rpmb() - route RPMB frames to mmc | |
34 | + * @dev: device with the selected RPMB partition | |
35 | + * @arg: OP-TEE message holding the frames to transmit to the mmc | |
36 | + * and space for the response frames. | |
37 | + * | |
38 | + * Routes signed (MACed) RPMB frames from OP-TEE Secure OS to MMC and vice | |
39 | + * versa to manipulate the RPMB partition. | |
40 | + */ | |
41 | +void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg); | |
42 | + | |
43 | +/** | |
44 | + * optee_suppl_rpmb_release() - release mmc device | |
45 | + * @dev: mmc device | |
46 | + * | |
47 | + * Releases the mmc device and restores the previously selected partition. | |
48 | + */ | |
49 | +void optee_suppl_rpmb_release(struct udevice *dev); | |
50 | +#else | |
51 | +static inline void optee_suppl_cmd_rpmb(struct udevice *dev, | |
52 | + struct optee_msg_arg *arg) | |
53 | +{ | |
54 | + debug("OPTEE_MSG_RPC_CMD_RPMB not implemented\n"); | |
55 | + arg->ret = TEE_ERROR_NOT_IMPLEMENTED; | |
56 | +} | |
57 | + | |
58 | +static inline void optee_suppl_rpmb_release(struct udevice *dev) | |
59 | +{ | |
60 | +} | |
61 | +#endif | |
62 | + | |
9 | 63 | void *optee_alloc_and_init_page_list(void *buf, ulong len, u64 *phys_buf_ptr); |
10 | -void optee_suppl_cmd(struct udevice *dev, void *shm, void **page_list); | |
11 | 64 | |
12 | 65 | #endif /* __OPTEE_PRIVATE_H */ |
drivers/tee/optee/rpmb.c
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 | +} |
drivers/tee/optee/supplicant.c