1 /*
2  * Copyright (c) 2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 
9 #include <zephyr/arch/xtensa/syscall.h>
10 
11 #include <zephyr/internal/syscall_handler.h>
12 #include <xtensa_internal.h>
13 
14 #ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER
xtensa_syscall_helper_args_6(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5,uintptr_t arg6,uintptr_t call_id)15 uintptr_t xtensa_syscall_helper_args_6(uintptr_t arg1, uintptr_t arg2,
16 				       uintptr_t arg3, uintptr_t arg4,
17 				       uintptr_t arg5, uintptr_t arg6,
18 				       uintptr_t call_id)
19 {
20 	register uintptr_t a2 __asm__("%a2") = call_id;
21 	register uintptr_t a6 __asm__("%a6") = arg1;
22 	register uintptr_t a3 __asm__("%a3") = arg2;
23 	register uintptr_t a4 __asm__("%a4") = arg3;
24 	register uintptr_t a5 __asm__("%a5") = arg4;
25 	register uintptr_t a8 __asm__("%a8") = arg5;
26 	register uintptr_t a9 __asm__("%a9") = arg6;
27 
28 	__asm__ volatile("syscall\n\t"
29 			 : "=r" (a2)
30 			 : "r" (a2), "r" (a6), "r" (a3), "r" (a4),
31 			   "r" (a5), "r" (a8), "r" (a9)
32 			 : "memory");
33 
34 	return a2;
35 }
36 
xtensa_syscall_helper_args_5(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5,uintptr_t call_id)37 uintptr_t xtensa_syscall_helper_args_5(uintptr_t arg1, uintptr_t arg2,
38 				       uintptr_t arg3, uintptr_t arg4,
39 				       uintptr_t arg5, uintptr_t call_id)
40 {
41 	register uintptr_t a2 __asm__("%a2") = call_id;
42 	register uintptr_t a6 __asm__("%a6") = arg1;
43 	register uintptr_t a3 __asm__("%a3") = arg2;
44 	register uintptr_t a4 __asm__("%a4") = arg3;
45 	register uintptr_t a5 __asm__("%a5") = arg4;
46 	register uintptr_t a8 __asm__("%a8") = arg5;
47 
48 	__asm__ volatile("syscall\n\t"
49 			 : "=r" (a2)
50 			 : "r" (a2), "r" (a6), "r" (a3), "r" (a4),
51 			   "r" (a5), "r" (a8)
52 			 : "memory");
53 
54 	return a2;
55 }
56 
xtensa_syscall_helper_args_4(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t call_id)57 uintptr_t xtensa_syscall_helper_args_4(uintptr_t arg1, uintptr_t arg2,
58 				       uintptr_t arg3, uintptr_t arg4,
59 				       uintptr_t call_id)
60 {
61 	register uintptr_t a2 __asm__("%a2") = call_id;
62 	register uintptr_t a6 __asm__("%a6") = arg1;
63 	register uintptr_t a3 __asm__("%a3") = arg2;
64 	register uintptr_t a4 __asm__("%a4") = arg3;
65 	register uintptr_t a5 __asm__("%a5") = arg4;
66 
67 	__asm__ volatile("syscall\n\t"
68 			 : "=r" (a2)
69 			 : "r" (a2), "r" (a6), "r" (a3), "r" (a4),
70 			   "r" (a5)
71 			 : "memory");
72 
73 	return a2;
74 }
75 
xtensa_syscall_helper_args_3(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t call_id)76 uintptr_t xtensa_syscall_helper_args_3(uintptr_t arg1, uintptr_t arg2,
77 				       uintptr_t arg3, uintptr_t call_id)
78 {
79 	register uintptr_t a2 __asm__("%a2") = call_id;
80 	register uintptr_t a6 __asm__("%a6") = arg1;
81 	register uintptr_t a3 __asm__("%a3") = arg2;
82 	register uintptr_t a4 __asm__("%a4") = arg3;
83 
84 	__asm__ volatile("syscall\n\t"
85 			 : "=r" (a2)
86 			 : "r" (a2), "r" (a6), "r" (a3), "r" (a4)
87 			 : "memory");
88 
89 	return a2;
90 }
91 
xtensa_syscall_helper_args_2(uintptr_t arg1,uintptr_t arg2,uintptr_t call_id)92 uintptr_t xtensa_syscall_helper_args_2(uintptr_t arg1, uintptr_t arg2,
93 				       uintptr_t call_id)
94 {
95 	register uintptr_t a2 __asm__("%a2") = call_id;
96 	register uintptr_t a6 __asm__("%a6") = arg1;
97 	register uintptr_t a3 __asm__("%a3") = arg2;
98 
99 	__asm__ volatile("syscall\n\t"
100 			 : "=r" (a2)
101 			 : "r" (a2), "r" (a6), "r" (a3)
102 			 : "memory");
103 
104 	return a2;
105 }
106 
xtensa_syscall_helper_args_1(uintptr_t arg1,uintptr_t call_id)107 uintptr_t xtensa_syscall_helper_args_1(uintptr_t arg1, uintptr_t call_id)
108 {
109 	register uintptr_t a2 __asm__("%a2") = call_id;
110 	register uintptr_t a6 __asm__("%a6") = arg1;
111 
112 	__asm__ volatile("syscall\n\t"
113 			 : "=r" (a2)
114 			 : "r" (a2), "r" (a6)
115 			 : "memory");
116 
117 	return a2;
118 }
119 
xtensa_syscall_helper_args_0(uintptr_t call_id)120 uintptr_t xtensa_syscall_helper_args_0(uintptr_t call_id)
121 {
122 	register uintptr_t a2 __asm__("%a2") = call_id;
123 
124 	__asm__ volatile("syscall\n\t"
125 			 : "=r" (a2)
126 			 : "r" (a2)
127 			 : "memory");
128 
129 	return a2;
130 }
131 #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */
132 
133 #if XCHAL_HAVE_THREADPTR == 0
134 #include <xtensa/config/core-isa.h>
135 #include <xtensa/config/core.h>
136 
xtensa_is_user_context(void)137 bool xtensa_is_user_context(void)
138 {
139 	uint32_t ret;
140 
141 	__asm__ volatile(".global xtensa_is_user_context_epc\n"
142 			 "        xtensa_is_user_context_epc:\n"
143 			 "                syscall\n"
144 			 "                mov %0, a2\n"
145 			 : "=r"(ret) : : "a2");
146 
147 	return ret != 0;
148 }
149 #endif /* XCHAL_HAVE_THREADPTR */
150 
arch_user_string_nlen(const char * s,size_t maxsize,int * err_arg)151 size_t arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg)
152 {
153 	/* Check if we can actually read the whole length.
154 	 *
155 	 * arch_user_string_nlen() is supposed to naively go through
156 	 * the string passed from user thread, and relies on page faults
157 	 * to catch inaccessible strings, such that user thread can pass
158 	 * a string that is shorter than the max length this function
159 	 * caller expects. So at least we want to make sure kernel has
160 	 * access to the whole length, aka. memory being mapped.
161 	 * Note that arch_user_string_nlen() should never result in
162 	 * thread termination due to page faults, and must always
163 	 * return to the caller with err_arg set or cleared.
164 	 * For MMU systems, unmapped memory will result in a DTLB miss
165 	 * and that might trigger an infinite DTLB miss storm if
166 	 * the corresponding L2 page table never exists in the first
167 	 * place (which would result in DTLB misses through L1 page
168 	 * table), until some other exceptions occur to break
169 	 * the cycle.
170 	 * For MPU systems, this would simply results in access errors
171 	 * and the exception handler will terminate the thread.
172 	 */
173 	if (!xtensa_mem_kernel_has_access((void *)s, maxsize, 0)) {
174 		/*
175 		 * API says we need to set err_arg to -1 if there are
176 		 * any errors.
177 		 */
178 		*err_arg = -1;
179 
180 		return 0;
181 	}
182 
183 	/* No error and we can proceed to getting the string length. */
184 	*err_arg = 0;
185 
186 	return strnlen(s, maxsize);
187 }
188