diff options
author | Volodymyr Babchuk <vlad.babchuk@gmail.com> | 2017-11-29 07:48:33 -0500 |
---|---|---|
committer | Jens Wiklander <jens.wiklander@linaro.org> | 2017-12-15 07:35:37 -0500 |
commit | 53a107c812de3dd74707458aa751eb457718ff9e (patch) | |
tree | 82eadb0852fe73f3583854aba6e220d7a68f7298 | |
parent | 64cf9d8a672e770fed85a65b5c6767fc0aa1473b (diff) |
tee: optee: add registered buffers handling into RPC calls
With latest changes to OP-TEE we can use any buffers as a shared memory.
Thus, it is possible for supplicant to provide part of own memory
when OP-TEE asks to allocate a shared buffer.
This patch adds support for such feature into RPC handling code.
Now when OP-TEE asks supplicant to allocate shared buffer, supplicant
can use TEE_IOC_SHM_REGISTER to provide such buffer. RPC handler is
aware of this, so it will pass list of allocated pages to OP-TEE.
Signed-off-by: Volodymyr Babchuk <vlad.babchuk@gmail.com>
[jw: fix parenthesis alignment in free_pages_list()]
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r-- | drivers/tee/optee/call.c | 19 | ||||
-rw-r--r-- | drivers/tee/optee/core.c | 2 | ||||
-rw-r--r-- | drivers/tee/optee/optee_private.h | 15 | ||||
-rw-r--r-- | drivers/tee/optee/rpc.c | 77 |
4 files changed, 102 insertions, 11 deletions
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index a05e9e61105f..e675e82ff095 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c | |||
@@ -136,6 +136,7 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg) | |||
136 | struct optee *optee = tee_get_drvdata(ctx->teedev); | 136 | struct optee *optee = tee_get_drvdata(ctx->teedev); |
137 | struct optee_call_waiter w; | 137 | struct optee_call_waiter w; |
138 | struct optee_rpc_param param = { }; | 138 | struct optee_rpc_param param = { }; |
139 | struct optee_call_ctx call_ctx = { }; | ||
139 | u32 ret; | 140 | u32 ret; |
140 | 141 | ||
141 | param.a0 = OPTEE_SMC_CALL_WITH_ARG; | 142 | param.a0 = OPTEE_SMC_CALL_WITH_ARG; |
@@ -160,13 +161,14 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg) | |||
160 | param.a1 = res.a1; | 161 | param.a1 = res.a1; |
161 | param.a2 = res.a2; | 162 | param.a2 = res.a2; |
162 | param.a3 = res.a3; | 163 | param.a3 = res.a3; |
163 | optee_handle_rpc(ctx, ¶m); | 164 | optee_handle_rpc(ctx, ¶m, &call_ctx); |
164 | } else { | 165 | } else { |
165 | ret = res.a0; | 166 | ret = res.a0; |
166 | break; | 167 | break; |
167 | } | 168 | } |
168 | } | 169 | } |
169 | 170 | ||
171 | optee_rpc_finalize_call(&call_ctx); | ||
170 | /* | 172 | /* |
171 | * We're done with our thread in secure world, if there's any | 173 | * We're done with our thread in secure world, if there's any |
172 | * thread waiters wake up one. | 174 | * thread waiters wake up one. |
@@ -602,3 +604,18 @@ int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm) | |||
602 | tee_shm_free(shm_arg); | 604 | tee_shm_free(shm_arg); |
603 | return rc; | 605 | return rc; |
604 | } | 606 | } |
607 | |||
608 | int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm, | ||
609 | struct page **pages, size_t num_pages) | ||
610 | { | ||
611 | /* | ||
612 | * We don't want to register supplicant memory in OP-TEE. | ||
613 | * Instead information about it will be passed in RPC code. | ||
614 | */ | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm) | ||
619 | { | ||
620 | return 0; | ||
621 | } | ||
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 494ad0a23403..ef8e35e4ad88 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c | |||
@@ -331,6 +331,8 @@ static const struct tee_driver_ops optee_supp_ops = { | |||
331 | .release = optee_release, | 331 | .release = optee_release, |
332 | .supp_recv = optee_supp_recv, | 332 | .supp_recv = optee_supp_recv, |
333 | .supp_send = optee_supp_send, | 333 | .supp_send = optee_supp_send, |
334 | .shm_register = optee_shm_register_supp, | ||
335 | .shm_unregister = optee_shm_unregister_supp, | ||
334 | }; | 336 | }; |
335 | 337 | ||
336 | static const struct tee_desc optee_supp_desc = { | 338 | static const struct tee_desc optee_supp_desc = { |
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index d7bc77d95022..61a0052f6a54 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h | |||
@@ -130,7 +130,16 @@ struct optee_rpc_param { | |||
130 | u32 a7; | 130 | u32 a7; |
131 | }; | 131 | }; |
132 | 132 | ||
133 | void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param); | 133 | /* Holds context that is preserved during one STD call */ |
134 | struct optee_call_ctx { | ||
135 | /* information about pages list used in last allocation */ | ||
136 | void *pages_list; | ||
137 | size_t num_entries; | ||
138 | }; | ||
139 | |||
140 | void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param, | ||
141 | struct optee_call_ctx *call_ctx); | ||
142 | void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx); | ||
134 | 143 | ||
135 | void optee_wait_queue_init(struct optee_wait_queue *wq); | 144 | void optee_wait_queue_init(struct optee_wait_queue *wq); |
136 | void optee_wait_queue_exit(struct optee_wait_queue *wq); | 145 | void optee_wait_queue_exit(struct optee_wait_queue *wq); |
@@ -164,6 +173,10 @@ int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm, | |||
164 | struct page **pages, size_t num_pages); | 173 | struct page **pages, size_t num_pages); |
165 | int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm); | 174 | int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm); |
166 | 175 | ||
176 | int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm, | ||
177 | struct page **pages, size_t num_pages); | ||
178 | int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm); | ||
179 | |||
167 | int optee_from_msg_param(struct tee_param *params, size_t num_params, | 180 | int optee_from_msg_param(struct tee_param *params, size_t num_params, |
168 | const struct optee_msg_param *msg_params); | 181 | const struct optee_msg_param *msg_params); |
169 | int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params, | 182 | int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params, |
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c index cef417f4f4d2..690e48a61aca 100644 --- a/drivers/tee/optee/rpc.c +++ b/drivers/tee/optee/rpc.c | |||
@@ -200,7 +200,8 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz) | |||
200 | } | 200 | } |
201 | 201 | ||
202 | static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, | 202 | static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, |
203 | struct optee_msg_arg *arg) | 203 | struct optee_msg_arg *arg, |
204 | struct optee_call_ctx *call_ctx) | ||
204 | { | 205 | { |
205 | phys_addr_t pa; | 206 | phys_addr_t pa; |
206 | struct tee_shm *shm; | 207 | struct tee_shm *shm; |
@@ -245,10 +246,49 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx, | |||
245 | goto bad; | 246 | goto bad; |
246 | } | 247 | } |
247 | 248 | ||
248 | arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; | 249 | sz = tee_shm_get_size(shm); |
249 | arg->params[0].u.tmem.buf_ptr = pa; | 250 | |
250 | arg->params[0].u.tmem.size = sz; | 251 | if (tee_shm_is_registered(shm)) { |
251 | arg->params[0].u.tmem.shm_ref = (unsigned long)shm; | 252 | struct page **pages; |
253 | u64 *pages_list; | ||
254 | size_t page_num; | ||
255 | |||
256 | pages = tee_shm_get_pages(shm, &page_num); | ||
257 | if (!pages || !page_num) { | ||
258 | arg->ret = TEEC_ERROR_OUT_OF_MEMORY; | ||
259 | goto bad; | ||
260 | } | ||
261 | |||
262 | pages_list = optee_allocate_pages_list(page_num); | ||
263 | if (!pages_list) { | ||
264 | arg->ret = TEEC_ERROR_OUT_OF_MEMORY; | ||
265 | goto bad; | ||
266 | } | ||
267 | |||
268 | call_ctx->pages_list = pages_list; | ||
269 | call_ctx->num_entries = page_num; | ||
270 | |||
271 | arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT | | ||
272 | OPTEE_MSG_ATTR_NONCONTIG; | ||
273 | /* | ||
274 | * In the least bits of u.tmem.buf_ptr we store buffer offset | ||
275 | * from 4k page, as described in OP-TEE ABI. | ||
276 | */ | ||
277 | arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) | | ||
278 | (tee_shm_get_page_offset(shm) & | ||
279 | (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1)); | ||
280 | arg->params[0].u.tmem.size = tee_shm_get_size(shm); | ||
281 | arg->params[0].u.tmem.shm_ref = (unsigned long)shm; | ||
282 | |||
283 | optee_fill_pages_list(pages_list, pages, page_num, | ||
284 | tee_shm_get_page_offset(shm)); | ||
285 | } else { | ||
286 | arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; | ||
287 | arg->params[0].u.tmem.buf_ptr = pa; | ||
288 | arg->params[0].u.tmem.size = sz; | ||
289 | arg->params[0].u.tmem.shm_ref = (unsigned long)shm; | ||
290 | } | ||
291 | |||
252 | arg->ret = TEEC_SUCCESS; | 292 | arg->ret = TEEC_SUCCESS; |
253 | return; | 293 | return; |
254 | bad: | 294 | bad: |
@@ -307,8 +347,24 @@ static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx, | |||
307 | arg->ret = TEEC_SUCCESS; | 347 | arg->ret = TEEC_SUCCESS; |
308 | } | 348 | } |
309 | 349 | ||
350 | static void free_pages_list(struct optee_call_ctx *call_ctx) | ||
351 | { | ||
352 | if (call_ctx->pages_list) { | ||
353 | optee_free_pages_list(call_ctx->pages_list, | ||
354 | call_ctx->num_entries); | ||
355 | call_ctx->pages_list = NULL; | ||
356 | call_ctx->num_entries = 0; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx) | ||
361 | { | ||
362 | free_pages_list(call_ctx); | ||
363 | } | ||
364 | |||
310 | static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee, | 365 | static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee, |
311 | struct tee_shm *shm) | 366 | struct tee_shm *shm, |
367 | struct optee_call_ctx *call_ctx) | ||
312 | { | 368 | { |
313 | struct optee_msg_arg *arg; | 369 | struct optee_msg_arg *arg; |
314 | 370 | ||
@@ -329,7 +385,8 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee, | |||
329 | handle_rpc_func_cmd_wait(arg); | 385 | handle_rpc_func_cmd_wait(arg); |
330 | break; | 386 | break; |
331 | case OPTEE_MSG_RPC_CMD_SHM_ALLOC: | 387 | case OPTEE_MSG_RPC_CMD_SHM_ALLOC: |
332 | handle_rpc_func_cmd_shm_alloc(ctx, arg); | 388 | free_pages_list(call_ctx); |
389 | handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx); | ||
333 | break; | 390 | break; |
334 | case OPTEE_MSG_RPC_CMD_SHM_FREE: | 391 | case OPTEE_MSG_RPC_CMD_SHM_FREE: |
335 | handle_rpc_func_cmd_shm_free(ctx, arg); | 392 | handle_rpc_func_cmd_shm_free(ctx, arg); |
@@ -343,10 +400,12 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee, | |||
343 | * optee_handle_rpc() - handle RPC from secure world | 400 | * optee_handle_rpc() - handle RPC from secure world |
344 | * @ctx: context doing the RPC | 401 | * @ctx: context doing the RPC |
345 | * @param: value of registers for the RPC | 402 | * @param: value of registers for the RPC |
403 | * @call_ctx: call context. Preserved during one OP-TEE invocation | ||
346 | * | 404 | * |
347 | * Result of RPC is written back into @param. | 405 | * Result of RPC is written back into @param. |
348 | */ | 406 | */ |
349 | void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param) | 407 | void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param, |
408 | struct optee_call_ctx *call_ctx) | ||
350 | { | 409 | { |
351 | struct tee_device *teedev = ctx->teedev; | 410 | struct tee_device *teedev = ctx->teedev; |
352 | struct optee *optee = tee_get_drvdata(teedev); | 411 | struct optee *optee = tee_get_drvdata(teedev); |
@@ -381,7 +440,7 @@ void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param) | |||
381 | break; | 440 | break; |
382 | case OPTEE_SMC_RPC_FUNC_CMD: | 441 | case OPTEE_SMC_RPC_FUNC_CMD: |
383 | shm = reg_pair_to_ptr(param->a1, param->a2); | 442 | shm = reg_pair_to_ptr(param->a1, param->a2); |
384 | handle_rpc_func_cmd(ctx, optee, shm); | 443 | handle_rpc_func_cmd(ctx, optee, shm, call_ctx); |
385 | break; | 444 | break; |
386 | default: | 445 | default: |
387 | pr_warn("Unknown RPC func 0x%x\n", | 446 | pr_warn("Unknown RPC func 0x%x\n", |