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 #include <zephyr/internal/syscall_handler.h>
11 #include <zephyr/llext/symbol.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(XTENSA_SYSCALL_ASM
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 EXPORT_SYMBOL(xtensa_syscall_helper_args_6);
37 
xtensa_syscall_helper_args_5(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5,uintptr_t call_id)38 uintptr_t xtensa_syscall_helper_args_5(uintptr_t arg1, uintptr_t arg2,
39 				       uintptr_t arg3, uintptr_t arg4,
40 				       uintptr_t arg5, uintptr_t call_id)
41 {
42 	register uintptr_t a2 __asm__("%a2") = call_id;
43 	register uintptr_t a6 __asm__("%a6") = arg1;
44 	register uintptr_t a3 __asm__("%a3") = arg2;
45 	register uintptr_t a4 __asm__("%a4") = arg3;
46 	register uintptr_t a5 __asm__("%a5") = arg4;
47 	register uintptr_t a8 __asm__("%a8") = arg5;
48 
49 	__asm__ volatile(XTENSA_SYSCALL_ASM
50 			 : "=r" (a2)
51 			 : "r" (a2), "r" (a6), "r" (a3), "r" (a4),
52 			   "r" (a5), "r" (a8)
53 			 : "memory");
54 
55 	return a2;
56 }
57 EXPORT_SYMBOL(xtensa_syscall_helper_args_5);
58 
xtensa_syscall_helper_args_4(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t call_id)59 uintptr_t xtensa_syscall_helper_args_4(uintptr_t arg1, uintptr_t arg2,
60 				       uintptr_t arg3, uintptr_t arg4,
61 				       uintptr_t call_id)
62 {
63 	register uintptr_t a2 __asm__("%a2") = call_id;
64 	register uintptr_t a6 __asm__("%a6") = arg1;
65 	register uintptr_t a3 __asm__("%a3") = arg2;
66 	register uintptr_t a4 __asm__("%a4") = arg3;
67 	register uintptr_t a5 __asm__("%a5") = arg4;
68 
69 	__asm__ volatile(XTENSA_SYSCALL_ASM
70 			 : "=r" (a2)
71 			 : "r" (a2), "r" (a6), "r" (a3), "r" (a4),
72 			   "r" (a5)
73 			 : "memory");
74 
75 	return a2;
76 }
77 EXPORT_SYMBOL(xtensa_syscall_helper_args_4);
78 
79 #endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */
80 
81 #if XCHAL_HAVE_THREADPTR == 0
82 #include <xtensa/config/core-isa.h>
83 #include <xtensa/config/core.h>
84 
xtensa_is_user_context(void)85 bool xtensa_is_user_context(void)
86 {
87 	uint32_t ret;
88 
89 	__asm__ volatile(".global xtensa_is_user_context_epc\n"
90 			 "        xtensa_is_user_context_epc:\n"
91 			 "                syscall\n"
92 			 "                mov %0, a2\n"
93 			 : "=r"(ret) : : "a2");
94 
95 	return ret != 0;
96 }
97 #endif /* XCHAL_HAVE_THREADPTR */
98 
arch_user_string_nlen(const char * s,size_t maxsize,int * err_arg)99 size_t arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg)
100 {
101 	/* Check if we can actually read the whole length.
102 	 *
103 	 * arch_user_string_nlen() is supposed to naively go through
104 	 * the string passed from user thread, and relies on page faults
105 	 * to catch inaccessible strings, such that user thread can pass
106 	 * a string that is shorter than the max length this function
107 	 * caller expects. So at least we want to make sure kernel has
108 	 * access to the whole length, aka. memory being mapped.
109 	 * Note that arch_user_string_nlen() should never result in
110 	 * thread termination due to page faults, and must always
111 	 * return to the caller with err_arg set or cleared.
112 	 * For MMU systems, unmapped memory will result in a DTLB miss
113 	 * and that might trigger an infinite DTLB miss storm if
114 	 * the corresponding L2 page table never exists in the first
115 	 * place (which would result in DTLB misses through L1 page
116 	 * table), until some other exceptions occur to break
117 	 * the cycle.
118 	 * For MPU systems, this would simply results in access errors
119 	 * and the exception handler will terminate the thread.
120 	 */
121 	if (arch_buffer_validate(s, maxsize, 0)) {
122 		/*
123 		 * API says we need to set err_arg to -1 if there are
124 		 * any errors.
125 		 */
126 		*err_arg = -1;
127 
128 		return 0;
129 	}
130 
131 	/* No error and we can proceed to getting the string length. */
132 	*err_arg = 0;
133 
134 	return strnlen(s, maxsize);
135 }
136