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