diff options
author | Volodymyr Babchuk <vlad.babchuk@gmail.com> | 2017-11-29 07:48:30 -0500 |
---|---|---|
committer | Jens Wiklander <jens.wiklander@linaro.org> | 2017-12-15 07:32:31 -0500 |
commit | 3bb48ba5cd60f9685aa8f1ccd9b14a72e237c13f (patch) | |
tree | 21b037f0e3191eab3cdd441b6adb24d862be5c21 | |
parent | de5c6dfc43daa59feb824505f80fe4591f8f8f85 (diff) |
tee: optee: add page list manipulation functions
These functions will be used to pass information about shared
buffers to OP-TEE. ABI between Linux and OP-TEE is defined
in optee_msg.h and optee_smc.h.
optee_msg.h defines OPTEE_MSG_ATTR_NONCONTIG attribute
for shared memory references and describes how such references
should be passed. Note that it uses 64-bit page addresses even
on 32 bit systems. This is done to support LPAE and to unify
interface.
Signed-off-by: Volodymyr Babchuk <vlad.babchuk@gmail.com>
[jw: replacing uint64_t with u64 in optee_fill_pages_list()]
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r-- | drivers/tee/optee/call.c | 91 | ||||
-rw-r--r-- | drivers/tee/optee/optee_private.h | 5 |
2 files changed, 96 insertions, 0 deletions
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index f7b7b404c990..e85860f6e057 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | #include <asm/pgtable.h> | ||
14 | #include <linux/arm-smccc.h> | 15 | #include <linux/arm-smccc.h> |
15 | #include <linux/device.h> | 16 | #include <linux/device.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
@@ -442,3 +443,93 @@ void optee_disable_shm_cache(struct optee *optee) | |||
442 | } | 443 | } |
443 | optee_cq_wait_final(&optee->call_queue, &w); | 444 | optee_cq_wait_final(&optee->call_queue, &w); |
444 | } | 445 | } |
446 | |||
447 | #define PAGELIST_ENTRIES_PER_PAGE \ | ||
448 | ((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1) | ||
449 | |||
450 | /** | ||
451 | * optee_fill_pages_list() - write list of user pages to given shared | ||
452 | * buffer. | ||
453 | * | ||
454 | * @dst: page-aligned buffer where list of pages will be stored | ||
455 | * @pages: array of pages that represents shared buffer | ||
456 | * @num_pages: number of entries in @pages | ||
457 | * @page_offset: offset of user buffer from page start | ||
458 | * | ||
459 | * @dst should be big enough to hold list of user page addresses and | ||
460 | * links to the next pages of buffer | ||
461 | */ | ||
462 | void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages, | ||
463 | size_t page_offset) | ||
464 | { | ||
465 | int n = 0; | ||
466 | phys_addr_t optee_page; | ||
467 | /* | ||
468 | * Refer to OPTEE_MSG_ATTR_NONCONTIG description in optee_msg.h | ||
469 | * for details. | ||
470 | */ | ||
471 | struct { | ||
472 | u64 pages_list[PAGELIST_ENTRIES_PER_PAGE]; | ||
473 | u64 next_page_data; | ||
474 | } *pages_data; | ||
475 | |||
476 | /* | ||
477 | * Currently OP-TEE uses 4k page size and it does not looks | ||
478 | * like this will change in the future. On other hand, there are | ||
479 | * no know ARM architectures with page size < 4k. | ||
480 | * Thus the next built assert looks redundant. But the following | ||
481 | * code heavily relies on this assumption, so it is better be | ||
482 | * safe than sorry. | ||
483 | */ | ||
484 | BUILD_BUG_ON(PAGE_SIZE < OPTEE_MSG_NONCONTIG_PAGE_SIZE); | ||
485 | |||
486 | pages_data = (void *)dst; | ||
487 | /* | ||
488 | * If linux page is bigger than 4k, and user buffer offset is | ||
489 | * larger than 4k/8k/12k/etc this will skip first 4k pages, | ||
490 | * because they bear no value data for OP-TEE. | ||
491 | */ | ||
492 | optee_page = page_to_phys(*pages) + | ||
493 | round_down(page_offset, OPTEE_MSG_NONCONTIG_PAGE_SIZE); | ||
494 | |||
495 | while (true) { | ||
496 | pages_data->pages_list[n++] = optee_page; | ||
497 | |||
498 | if (n == PAGELIST_ENTRIES_PER_PAGE) { | ||
499 | pages_data->next_page_data = | ||
500 | virt_to_phys(pages_data + 1); | ||
501 | pages_data++; | ||
502 | n = 0; | ||
503 | } | ||
504 | |||
505 | optee_page += OPTEE_MSG_NONCONTIG_PAGE_SIZE; | ||
506 | if (!(optee_page & ~PAGE_MASK)) { | ||
507 | if (!--num_pages) | ||
508 | break; | ||
509 | pages++; | ||
510 | optee_page = page_to_phys(*pages); | ||
511 | } | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * The final entry in each pagelist page is a pointer to the next | ||
517 | * pagelist page. | ||
518 | */ | ||
519 | static size_t get_pages_list_size(size_t num_entries) | ||
520 | { | ||
521 | int pages = DIV_ROUND_UP(num_entries, PAGELIST_ENTRIES_PER_PAGE); | ||
522 | |||
523 | return pages * OPTEE_MSG_NONCONTIG_PAGE_SIZE; | ||
524 | } | ||
525 | |||
526 | u64 *optee_allocate_pages_list(size_t num_entries) | ||
527 | { | ||
528 | return alloc_pages_exact(get_pages_list_size(num_entries), GFP_KERNEL); | ||
529 | } | ||
530 | |||
531 | void optee_free_pages_list(void *list, size_t num_entries) | ||
532 | { | ||
533 | free_pages_exact(list, get_pages_list_size(num_entries)); | ||
534 | } | ||
535 | |||
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index c374cd594314..b63213d09d68 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h | |||
@@ -165,6 +165,11 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params, | |||
165 | int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params, | 165 | int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params, |
166 | const struct tee_param *params); | 166 | const struct tee_param *params); |
167 | 167 | ||
168 | u64 *optee_allocate_pages_list(size_t num_entries); | ||
169 | void optee_free_pages_list(void *array, size_t num_entries); | ||
170 | void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages, | ||
171 | size_t page_offset); | ||
172 | |||
168 | /* | 173 | /* |
169 | * Small helpers | 174 | * Small helpers |
170 | */ | 175 | */ |