1c40a6505SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 2c40a6505SJens Wiklander /* 3c40a6505SJens Wiklander * Copyright (c) 2014, STMicroelectronics International N.V. 4*ef142203SJens Wiklander * Copyright (c) 2015-2020, 2022 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> 11a0e8ffe9SJens 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 17*ef142203SJens Wiklander static TEE_Result check_access(uint32_t flags, const void *uaddr, size_t len) 18c40a6505SJens Wiklander { 1900b3b9a2SJens Wiklander struct ts_session *s = ts_get_current_session(); 207e4100f3SJens Wiklander 21*ef142203SJens Wiklander return vm_check_access_rights(to_user_mode_ctx(s->ctx), flags, 22*ef142203SJens Wiklander (vaddr_t)uaddr, len); 23c40a6505SJens Wiklander } 24c40a6505SJens Wiklander 25c40a6505SJens Wiklander TEE_Result copy_from_user(void *kaddr, const void *uaddr, size_t len) 26c40a6505SJens Wiklander { 277e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER; 28*ef142203SJens Wiklander TEE_Result res = TEE_SUCCESS; 29c40a6505SJens Wiklander 30*ef142203SJens Wiklander uaddr = memtag_strip_tag_const(uaddr); 31*ef142203SJens Wiklander res = check_access(flags, uaddr, len); 327e4100f3SJens Wiklander if (!res) 33c40a6505SJens Wiklander memcpy(kaddr, uaddr, len); 347e4100f3SJens Wiklander 357e4100f3SJens Wiklander return res; 36c40a6505SJens Wiklander } 37c40a6505SJens Wiklander 38c40a6505SJens Wiklander TEE_Result copy_to_user(void *uaddr, const void *kaddr, size_t len) 39c40a6505SJens Wiklander { 407e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER; 41*ef142203SJens Wiklander TEE_Result res = TEE_SUCCESS; 42c40a6505SJens Wiklander 43*ef142203SJens Wiklander uaddr = memtag_strip_tag(uaddr); 44*ef142203SJens Wiklander res = check_access(flags, uaddr, len); 457e4100f3SJens Wiklander if (!res) 46c40a6505SJens Wiklander memcpy(uaddr, kaddr, len); 477e4100f3SJens Wiklander 487e4100f3SJens Wiklander return res; 497e4100f3SJens Wiklander } 507e4100f3SJens Wiklander 517e4100f3SJens Wiklander TEE_Result copy_from_user_private(void *kaddr, const void *uaddr, size_t len) 527e4100f3SJens Wiklander { 537e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_READ; 54*ef142203SJens Wiklander TEE_Result res = TEE_SUCCESS; 557e4100f3SJens Wiklander 56*ef142203SJens Wiklander uaddr = memtag_strip_tag_const(uaddr); 57*ef142203SJens Wiklander res = check_access(flags, uaddr, len); 587e4100f3SJens Wiklander if (!res) 597e4100f3SJens Wiklander memcpy(kaddr, uaddr, len); 607e4100f3SJens Wiklander 617e4100f3SJens Wiklander return res; 627e4100f3SJens Wiklander } 637e4100f3SJens Wiklander 647e4100f3SJens Wiklander TEE_Result copy_to_user_private(void *uaddr, const void *kaddr, size_t len) 657e4100f3SJens Wiklander { 667e4100f3SJens Wiklander uint32_t flags = TEE_MEMORY_ACCESS_WRITE; 67*ef142203SJens Wiklander TEE_Result res = TEE_SUCCESS; 687e4100f3SJens Wiklander 69*ef142203SJens Wiklander uaddr = memtag_strip_tag(uaddr); 70*ef142203SJens Wiklander res = check_access(flags, uaddr, len); 717e4100f3SJens Wiklander if (!res) 727e4100f3SJens Wiklander memcpy(uaddr, kaddr, len); 737e4100f3SJens Wiklander 747e4100f3SJens Wiklander return res; 75c40a6505SJens Wiklander } 76c40a6505SJens Wiklander 77c40a6505SJens Wiklander TEE_Result copy_kaddr_to_uref(uint32_t *uref, void *kaddr) 78c40a6505SJens Wiklander { 79c40a6505SJens Wiklander uint32_t ref = kaddr_to_uref(kaddr); 80c40a6505SJens Wiklander 817e4100f3SJens Wiklander return copy_to_user_private(uref, &ref, sizeof(ref)); 82c40a6505SJens Wiklander } 83c40a6505SJens Wiklander 84c40a6505SJens Wiklander uint32_t kaddr_to_uref(void *kaddr) 85c40a6505SJens Wiklander { 86a0e8ffe9SJens Wiklander if (MEMTAG_IS_ENABLED) { 87a0e8ffe9SJens Wiklander unsigned int uref_tag_shift = 32 - MEMTAG_TAG_WIDTH; 88a0e8ffe9SJens Wiklander vaddr_t uref = memtag_strip_tag_vaddr(kaddr); 89a0e8ffe9SJens Wiklander 90a0e8ffe9SJens Wiklander uref -= VCORE_START_VA; 91a0e8ffe9SJens Wiklander assert(uref < (UINT32_MAX >> MEMTAG_TAG_WIDTH)); 92a0e8ffe9SJens Wiklander uref |= memtag_get_tag(kaddr) << uref_tag_shift; 93a0e8ffe9SJens Wiklander return uref; 94a0e8ffe9SJens Wiklander } 95a0e8ffe9SJens Wiklander 96c40a6505SJens Wiklander assert(((vaddr_t)kaddr - VCORE_START_VA) < UINT32_MAX); 97c40a6505SJens Wiklander return (vaddr_t)kaddr - VCORE_START_VA; 98c40a6505SJens Wiklander } 99c40a6505SJens Wiklander 100c40a6505SJens Wiklander vaddr_t uref_to_vaddr(uint32_t uref) 101c40a6505SJens Wiklander { 102a0e8ffe9SJens Wiklander if (MEMTAG_IS_ENABLED) { 103a0e8ffe9SJens Wiklander vaddr_t u = uref & (UINT32_MAX >> MEMTAG_TAG_WIDTH); 104a0e8ffe9SJens Wiklander unsigned int uref_tag_shift = 32 - MEMTAG_TAG_WIDTH; 105a0e8ffe9SJens Wiklander uint8_t tag = uref >> uref_tag_shift; 106a0e8ffe9SJens Wiklander 107a0e8ffe9SJens Wiklander return memtag_insert_tag_vaddr(VCORE_START_VA + u, tag); 108a0e8ffe9SJens Wiklander } 109a0e8ffe9SJens Wiklander 110c40a6505SJens Wiklander return VCORE_START_VA + uref; 111c40a6505SJens Wiklander } 112