xref: /optee_os/core/kernel/user_access.c (revision ef142203a36b34925c47cd347197ce45153466fc)
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