1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2020 NXP
4 */
5
6 #include <command.h>
7 #include <common.h>
8 #include <env.h>
9 #include <errno.h>
10 #include <image.h>
11 #include <malloc.h>
12 #include <mmc.h>
13 #include <tee.h>
14 #include <tee/optee_ta_avb.h>
15
16 static struct udevice *tee;
17 static u32 session;
18
avb_ta_open_session(void)19 static int avb_ta_open_session(void)
20 {
21 const struct tee_optee_ta_uuid uuid = TA_AVB_UUID;
22 struct tee_open_session_arg arg;
23 int rc;
24
25 tee = tee_find_device(tee, NULL, NULL, NULL);
26 if (!tee)
27 return -ENODEV;
28
29 memset(&arg, 0, sizeof(arg));
30 tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
31 rc = tee_open_session(tee, &arg, 0, NULL);
32 if (!rc)
33 session = arg.session;
34
35 return 0;
36 }
37
invoke_func(u32 func,ulong num_param,struct tee_param * param)38 static int invoke_func(u32 func, ulong num_param, struct tee_param *param)
39 {
40 struct tee_invoke_arg arg;
41
42 if (!tee)
43 if (avb_ta_open_session())
44 return -ENODEV;
45
46 memset(&arg, 0, sizeof(arg));
47 arg.func = func;
48 arg.session = session;
49
50 if (tee_invoke_func(tee, &arg, num_param, param))
51 return -EFAULT;
52 switch (arg.ret) {
53 case TEE_SUCCESS:
54 return 0;
55 case TEE_ERROR_OUT_OF_MEMORY:
56 case TEE_ERROR_STORAGE_NO_SPACE:
57 return -ENOSPC;
58 case TEE_ERROR_ITEM_NOT_FOUND:
59 return -EIO;
60 case TEE_ERROR_TARGET_DEAD:
61 /*
62 * The TA has paniced, close the session to reload the TA
63 * for the next request.
64 */
65 tee_close_session(tee, session);
66 tee = NULL;
67 return -EIO;
68 default:
69 return -EIO;
70 }
71 }
72
read_persistent_value(const char * name,size_t buffer_size,u8 * out_buffer,size_t * out_num_bytes_read)73 static int read_persistent_value(const char *name,
74 size_t buffer_size,
75 u8 *out_buffer,
76 size_t *out_num_bytes_read)
77 {
78 int rc = 0;
79 struct tee_shm *shm_name;
80 struct tee_shm *shm_buf;
81 struct tee_param param[2];
82 size_t name_size = strlen(name) + 1;
83
84 if (!tee)
85 if (avb_ta_open_session())
86 return -ENODEV;
87
88 rc = tee_shm_alloc(tee, name_size,
89 TEE_SHM_ALLOC, &shm_name);
90 if (rc)
91 return -ENOMEM;
92
93 rc = tee_shm_alloc(tee, buffer_size,
94 TEE_SHM_ALLOC, &shm_buf);
95 if (rc) {
96 rc = -ENOMEM;
97 goto free_name;
98 }
99
100 memcpy(shm_name->addr, name, name_size);
101
102 memset(param, 0, sizeof(param));
103 param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
104 param[0].u.memref.shm = shm_name;
105 param[0].u.memref.size = name_size;
106 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
107 param[1].u.memref.shm = shm_buf;
108 param[1].u.memref.size = buffer_size;
109
110 rc = invoke_func(TA_AVB_CMD_READ_PERSIST_VALUE,
111 2, param);
112 if (rc)
113 goto out;
114
115 if (param[1].u.memref.size > buffer_size) {
116 rc = -EINVAL;
117 goto out;
118 }
119
120 *out_num_bytes_read = param[1].u.memref.size;
121
122 memcpy(out_buffer, shm_buf->addr, *out_num_bytes_read);
123
124 out:
125 tee_shm_free(shm_buf);
126 free_name:
127 tee_shm_free(shm_name);
128
129 return rc;
130 }
131
write_persistent_value(const char * name,size_t value_size,const u8 * value)132 static int write_persistent_value(const char *name,
133 size_t value_size,
134 const u8 *value)
135 {
136 int rc = 0;
137 struct tee_shm *shm_name;
138 struct tee_shm *shm_buf;
139 struct tee_param param[2];
140 size_t name_size = strlen(name) + 1;
141
142 if (!tee) {
143 if (avb_ta_open_session())
144 return -ENODEV;
145 }
146 if (!value_size)
147 return -EINVAL;
148
149 rc = tee_shm_alloc(tee, name_size,
150 TEE_SHM_ALLOC, &shm_name);
151 if (rc)
152 return -ENOMEM;
153
154 rc = tee_shm_alloc(tee, value_size,
155 TEE_SHM_ALLOC, &shm_buf);
156 if (rc) {
157 rc = -ENOMEM;
158 goto free_name;
159 }
160
161 memcpy(shm_name->addr, name, name_size);
162 memcpy(shm_buf->addr, value, value_size);
163
164 memset(param, 0, sizeof(param));
165 param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
166 param[0].u.memref.shm = shm_name;
167 param[0].u.memref.size = name_size;
168 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
169 param[1].u.memref.shm = shm_buf;
170 param[1].u.memref.size = value_size;
171
172 rc = invoke_func(TA_AVB_CMD_WRITE_PERSIST_VALUE,
173 2, param);
174 if (rc)
175 goto out;
176
177 out:
178 tee_shm_free(shm_buf);
179 free_name:
180 tee_shm_free(shm_name);
181
182 return rc;
183 }
184
do_optee_rpmb_read(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])185 int do_optee_rpmb_read(struct cmd_tbl *cmdtp, int flag, int argc,
186 char * const argv[])
187 {
188 const char *name;
189 size_t bytes;
190 size_t bytes_read;
191 void *buffer;
192 char *endp;
193
194 if (argc != 3)
195 return CMD_RET_USAGE;
196
197 name = argv[1];
198 bytes = simple_strtoul(argv[2], &endp, 10);
199 if (*endp && *endp != '\n')
200 return CMD_RET_USAGE;
201
202 buffer = malloc(bytes);
203 if (!buffer)
204 return CMD_RET_FAILURE;
205
206 if (read_persistent_value(name, bytes, buffer, &bytes_read) == 0) {
207 printf("Read %zu bytes, value = %s\n", bytes_read,
208 (char *)buffer);
209 free(buffer);
210 return CMD_RET_SUCCESS;
211 }
212
213 printf("Failed to read persistent value\n");
214
215 free(buffer);
216
217 return CMD_RET_FAILURE;
218 }
219
do_optee_rpmb_write(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])220 int do_optee_rpmb_write(struct cmd_tbl *cmdtp, int flag, int argc,
221 char * const argv[])
222 {
223 const char *name;
224 const char *value;
225
226 if (argc != 3)
227 return CMD_RET_USAGE;
228
229 name = argv[1];
230 value = argv[2];
231
232 if (write_persistent_value(name, strlen(value) + 1,
233 (const uint8_t *)value) == 0) {
234 printf("Wrote %zu bytes\n", strlen(value) + 1);
235 return CMD_RET_SUCCESS;
236 }
237
238 printf("Failed to write persistent value\n");
239
240 return CMD_RET_FAILURE;
241 }
242
243 static struct cmd_tbl cmd_optee_rpmb[] = {
244 U_BOOT_CMD_MKENT(read_pvalue, 3, 0, do_optee_rpmb_read, "", ""),
245 U_BOOT_CMD_MKENT(write_pvalue, 3, 0, do_optee_rpmb_write, "", ""),
246 };
247
do_optee_rpmb(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])248 static int do_optee_rpmb(struct cmd_tbl *cmdtp, int flag, int argc,
249 char * const argv[])
250 {
251 struct cmd_tbl *cp;
252
253 cp = find_cmd_tbl(argv[1], cmd_optee_rpmb, ARRAY_SIZE(cmd_optee_rpmb));
254
255 argc--;
256 argv++;
257
258 if (!cp || argc > cp->maxargs)
259 return CMD_RET_USAGE;
260
261 if (flag == CMD_FLAG_REPEAT)
262 return CMD_RET_FAILURE;
263
264 return cp->cmd(cmdtp, flag, argc, argv);
265 }
266
267 U_BOOT_CMD (
268 optee_rpmb, 29, 0, do_optee_rpmb,
269 "Provides commands for testing secure storage on RPMB on OPTEE",
270 "read_pvalue <name> <bytes> - read a persistent value <name>\n"
271 "optee_rpmb write_pvalue <name> <value> - write a persistent value <name>\n"
272 );
273