1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2015-2020, 2022 Linaro Limited
5  */
6 
7 #include <initcall.h>
8 #include <kernel/linker.h>
9 #include <kernel/user_access.h>
10 #include <kernel/user_mode_ctx.h>
11 #include <memtag.h>
12 #include <mm/vm.h>
13 #include <string.h>
14 #include <tee_api_types.h>
15 #include <types_ext.h>
16 
check_access(uint32_t flags,const void * uaddr,size_t len)17 static TEE_Result check_access(uint32_t flags, const void *uaddr, size_t len)
18 {
19 	struct ts_session *s = ts_get_current_session();
20 
21 	return vm_check_access_rights(to_user_mode_ctx(s->ctx), flags,
22 				      (vaddr_t)uaddr, len);
23 }
24 
copy_from_user(void * kaddr,const void * uaddr,size_t len)25 TEE_Result copy_from_user(void *kaddr, const void *uaddr, size_t len)
26 {
27 	uint32_t flags = TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER;
28 	TEE_Result res = TEE_SUCCESS;
29 
30 	uaddr = memtag_strip_tag_const(uaddr);
31 	res = check_access(flags, uaddr, len);
32 	if (!res)
33 		memcpy(kaddr, uaddr, len);
34 
35 	return res;
36 }
37 
copy_to_user(void * uaddr,const void * kaddr,size_t len)38 TEE_Result copy_to_user(void *uaddr, const void *kaddr, size_t len)
39 {
40 	uint32_t flags = TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER;
41 	TEE_Result res = TEE_SUCCESS;
42 
43 	uaddr = memtag_strip_tag(uaddr);
44 	res = check_access(flags, uaddr, len);
45 	if (!res)
46 		memcpy(uaddr, kaddr, len);
47 
48 	return res;
49 }
50 
copy_from_user_private(void * kaddr,const void * uaddr,size_t len)51 TEE_Result copy_from_user_private(void *kaddr, const void *uaddr, size_t len)
52 {
53 	uint32_t flags = TEE_MEMORY_ACCESS_READ;
54 	TEE_Result res = TEE_SUCCESS;
55 
56 	uaddr = memtag_strip_tag_const(uaddr);
57 	res = check_access(flags, uaddr, len);
58 	if (!res)
59 		memcpy(kaddr, uaddr, len);
60 
61 	return res;
62 }
63 
copy_to_user_private(void * uaddr,const void * kaddr,size_t len)64 TEE_Result copy_to_user_private(void *uaddr, const void *kaddr, size_t len)
65 {
66 	uint32_t flags = TEE_MEMORY_ACCESS_WRITE;
67 	TEE_Result res = TEE_SUCCESS;
68 
69 	uaddr = memtag_strip_tag(uaddr);
70 	res = check_access(flags, uaddr, len);
71 	if (!res)
72 		memcpy(uaddr, kaddr, len);
73 
74 	return res;
75 }
76 
copy_kaddr_to_uref(uint32_t * uref,void * kaddr)77 TEE_Result copy_kaddr_to_uref(uint32_t *uref, void *kaddr)
78 {
79 	uint32_t ref = kaddr_to_uref(kaddr);
80 
81 	return copy_to_user_private(uref, &ref, sizeof(ref));
82 }
83 
kaddr_to_uref(void * kaddr)84 uint32_t kaddr_to_uref(void *kaddr)
85 {
86 	if (MEMTAG_IS_ENABLED) {
87 		unsigned int uref_tag_shift = 32 - MEMTAG_TAG_WIDTH;
88 		vaddr_t uref = memtag_strip_tag_vaddr(kaddr);
89 
90 		uref -= VCORE_START_VA;
91 		assert(uref < (UINT32_MAX >> MEMTAG_TAG_WIDTH));
92 		uref |= memtag_get_tag(kaddr) << uref_tag_shift;
93 		return uref;
94 	}
95 
96 	assert(((vaddr_t)kaddr - VCORE_START_VA) < UINT32_MAX);
97 	return (vaddr_t)kaddr - VCORE_START_VA;
98 }
99 
uref_to_vaddr(uint32_t uref)100 vaddr_t uref_to_vaddr(uint32_t uref)
101 {
102 	if (MEMTAG_IS_ENABLED) {
103 		vaddr_t u = uref & (UINT32_MAX >> MEMTAG_TAG_WIDTH);
104 		unsigned int uref_tag_shift = 32 - MEMTAG_TAG_WIDTH;
105 		uint8_t tag = uref >> uref_tag_shift;
106 
107 		return memtag_insert_tag_vaddr(VCORE_START_VA + u, tag);
108 	}
109 
110 	return VCORE_START_VA + uref;
111 }
112