1c40a6505SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 2c40a6505SJens Wiklander /* 3c40a6505SJens Wiklander * Copyright (c) 2014, STMicroelectronics International N.V. 4c40a6505SJens Wiklander * Copyright (c) 2015-2020 Linaro Limited 5c40a6505SJens Wiklander */ 6c40a6505SJens Wiklander 7c40a6505SJens Wiklander #include <initcall.h> 8c40a6505SJens Wiklander #include <kernel/linker.h> 9c40a6505SJens Wiklander #include <kernel/user_access.h> 10c185655eSJelle Sels #include <kernel/user_mode_ctx.h> 11*a0e8ffe9SJens Wiklander #include <memtag.h> 1289c9728dSJens Wiklander #include <mm/vm.h> 13c40a6505SJens Wiklander #include <string.h> 14c40a6505SJens Wiklander #include <tee_api_types.h> 15c40a6505SJens Wiklander #include <types_ext.h> 16c40a6505SJens Wiklander 177e4100f3SJens Wiklander static TEE_Result check_access(uint32_t flags, vaddr_t va, size_t len) 18c40a6505SJens Wiklander { 1900b3b9a2SJens Wiklander struct ts_session *s = ts_get_current_session(); 207e4100f3SJens Wiklander 21c185655eSJelle Sels return vm_check_access_rights(to_user_mode_ctx(s->ctx), flags, va, len); 22c40a6505SJens Wiklander } 23c40a6505SJens Wiklander 24c40a6505SJens Wiklander TEE_Result copy_from_user(void *kaddr, const void *uaddr, size_t len) 25c40a6505SJens Wiklander { 267e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER; 277e4100f3SJens Wiklander TEE_Result res = check_access(flags, (vaddr_t)uaddr, len); 28c40a6505SJens Wiklander 297e4100f3SJens Wiklander if (!res) 30c40a6505SJens Wiklander memcpy(kaddr, uaddr, len); 317e4100f3SJens Wiklander 327e4100f3SJens Wiklander return res; 33c40a6505SJens Wiklander } 34c40a6505SJens Wiklander 35c40a6505SJens Wiklander TEE_Result copy_to_user(void *uaddr, const void *kaddr, size_t len) 36c40a6505SJens Wiklander { 377e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER; 387e4100f3SJens Wiklander TEE_Result res = check_access(flags, (vaddr_t)uaddr, len); 39c40a6505SJens Wiklander 407e4100f3SJens Wiklander if (!res) 41c40a6505SJens Wiklander memcpy(uaddr, kaddr, len); 427e4100f3SJens Wiklander 437e4100f3SJens Wiklander return res; 447e4100f3SJens Wiklander } 457e4100f3SJens Wiklander 467e4100f3SJens Wiklander TEE_Result copy_from_user_private(void *kaddr, const void *uaddr, size_t len) 477e4100f3SJens Wiklander { 487e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_READ; 497e4100f3SJens Wiklander TEE_Result res = check_access(flags, (vaddr_t)uaddr, len); 507e4100f3SJens Wiklander 517e4100f3SJens Wiklander if (!res) 527e4100f3SJens Wiklander memcpy(kaddr, uaddr, len); 537e4100f3SJens Wiklander 547e4100f3SJens Wiklander return res; 557e4100f3SJens Wiklander } 567e4100f3SJens Wiklander 577e4100f3SJens Wiklander TEE_Result copy_to_user_private(void *uaddr, const void *kaddr, size_t len) 587e4100f3SJens Wiklander { 597e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_WRITE; 607e4100f3SJens Wiklander TEE_Result res = check_access(flags, (vaddr_t)uaddr, len); 617e4100f3SJens Wiklander 627e4100f3SJens Wiklander if (!res) 637e4100f3SJens Wiklander memcpy(uaddr, kaddr, len); 647e4100f3SJens Wiklander 657e4100f3SJens Wiklander return res; 66c40a6505SJens Wiklander } 67c40a6505SJens Wiklander 68c40a6505SJens Wiklander TEE_Result copy_kaddr_to_uref(uint32_t *uref, void *kaddr) 69c40a6505SJens Wiklander { 70c40a6505SJens Wiklander uint32_t ref = kaddr_to_uref(kaddr); 71c40a6505SJens Wiklander 727e4100f3SJens Wiklander return copy_to_user_private(uref, &ref, sizeof(ref)); 73c40a6505SJens Wiklander } 74c40a6505SJens Wiklander 75c40a6505SJens Wiklander uint32_t kaddr_to_uref(void *kaddr) 76c40a6505SJens Wiklander { 77*a0e8ffe9SJens Wiklander if (MEMTAG_IS_ENABLED) { 78*a0e8ffe9SJens Wiklander unsigned int uref_tag_shift = 32 - MEMTAG_TAG_WIDTH; 79*a0e8ffe9SJens Wiklander vaddr_t uref = memtag_strip_tag_vaddr(kaddr); 80*a0e8ffe9SJens Wiklander 81*a0e8ffe9SJens Wiklander uref -= VCORE_START_VA; 82*a0e8ffe9SJens Wiklander assert(uref < (UINT32_MAX >> MEMTAG_TAG_WIDTH)); 83*a0e8ffe9SJens Wiklander uref |= memtag_get_tag(kaddr) << uref_tag_shift; 84*a0e8ffe9SJens Wiklander return uref; 85*a0e8ffe9SJens Wiklander } 86*a0e8ffe9SJens Wiklander 87c40a6505SJens Wiklander assert(((vaddr_t)kaddr - VCORE_START_VA) < UINT32_MAX); 88c40a6505SJens Wiklander return (vaddr_t)kaddr - VCORE_START_VA; 89c40a6505SJens Wiklander } 90c40a6505SJens Wiklander 91c40a6505SJens Wiklander vaddr_t uref_to_vaddr(uint32_t uref) 92c40a6505SJens Wiklander { 93*a0e8ffe9SJens Wiklander if (MEMTAG_IS_ENABLED) { 94*a0e8ffe9SJens Wiklander vaddr_t u = uref & (UINT32_MAX >> MEMTAG_TAG_WIDTH); 95*a0e8ffe9SJens Wiklander unsigned int uref_tag_shift = 32 - MEMTAG_TAG_WIDTH; 96*a0e8ffe9SJens Wiklander uint8_t tag = uref >> uref_tag_shift; 97*a0e8ffe9SJens Wiklander 98*a0e8ffe9SJens Wiklander return memtag_insert_tag_vaddr(VCORE_START_VA + u, tag); 99*a0e8ffe9SJens Wiklander } 100*a0e8ffe9SJens Wiklander 101c40a6505SJens Wiklander return VCORE_START_VA + uref; 102c40a6505SJens Wiklander } 103