Skip to content

Commit 3bb48ba

Browse files
lorcjenswi-linaro
authored andcommitted
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 <[email protected]> [jw: replacing uint64_t with u64 in optee_fill_pages_list()] Signed-off-by: Jens Wiklander <[email protected]>
1 parent de5c6df commit 3bb48ba

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

drivers/tee/optee/call.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* GNU General Public License for more details.
1212
*
1313
*/
14+
#include <asm/pgtable.h>
1415
#include <linux/arm-smccc.h>
1516
#include <linux/device.h>
1617
#include <linux/err.h>
@@ -442,3 +443,93 @@ void optee_disable_shm_cache(struct optee *optee)
442443
}
443444
optee_cq_wait_final(&optee->call_queue, &w);
444445
}
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+

drivers/tee/optee/optee_private.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params,
165165
int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
166166
const struct tee_param *params);
167167

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+
168173
/*
169174
* Small helpers
170175
*/

0 commit comments

Comments
 (0)