]>
Commit | Line | Data |
---|---|---|
bcc6c574 RG |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ); |