1 /*
2  * Copyright (c) 2020 BayLibre, SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief RISCV specific syscall header
10  *
11  * This header contains the RISCV specific syscall interface.  It is
12  * included by the syscall interface architecture-abstraction header
13  * (include/arch/syscall.h)
14  */
15 
16 #ifndef ZEPHYR_INCLUDE_ARCH_RISCV_SYSCALL_H_
17 #define ZEPHYR_INCLUDE_ARCH_RISCV_SYSCALL_H_
18 
19 /*
20  * Privileged mode system calls
21  */
22 #define RV_ECALL_RUNTIME_EXCEPT		0
23 #define RV_ECALL_IRQ_OFFLOAD		1
24 #define RV_ECALL_SCHEDULE		2
25 
26 #ifndef _ASMLANGUAGE
27 
28 #include <zephyr/types.h>
29 #include <stdbool.h>
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 /*
36  * Syscall invocation macros. riscv-specific machine constraints used to ensure
37  * args land in the proper registers.
38  */
arch_syscall_invoke6(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5,uintptr_t arg6,uintptr_t call_id)39 static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2,
40 					     uintptr_t arg3, uintptr_t arg4,
41 					     uintptr_t arg5, uintptr_t arg6,
42 					     uintptr_t call_id)
43 {
44 	register unsigned long a0 __asm__ ("a0") = arg1;
45 	register unsigned long a1 __asm__ ("a1") = arg2;
46 	register unsigned long a2 __asm__ ("a2") = arg3;
47 	register unsigned long a3 __asm__ ("a3") = arg4;
48 	register unsigned long a4 __asm__ ("a4") = arg5;
49 	register unsigned long a5 __asm__ ("a5") = arg6;
50 	register unsigned long t0 __asm__ ("t0") = call_id;
51 
52 	__asm__ volatile ("ecall"
53 			  : "+r" (a0)
54 			  : "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5),
55 			  "r" (t0)
56 			  : "memory");
57 	return a0;
58 }
59 
arch_syscall_invoke5(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t arg5,uintptr_t call_id)60 static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2,
61 					     uintptr_t arg3, uintptr_t arg4,
62 					     uintptr_t arg5,
63 					     uintptr_t call_id)
64 {
65 	register unsigned long a0 __asm__ ("a0") = arg1;
66 	register unsigned long a1 __asm__ ("a1") = arg2;
67 	register unsigned long a2 __asm__ ("a2") = arg3;
68 	register unsigned long a3 __asm__ ("a3") = arg4;
69 	register unsigned long a4 __asm__ ("a4") = arg5;
70 	register unsigned long t0 __asm__ ("t0") = call_id;
71 
72 	__asm__ volatile ("ecall"
73 			  : "+r" (a0)
74 			  : "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (t0)
75 			  : "memory");
76 	return a0;
77 }
78 
arch_syscall_invoke4(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t arg4,uintptr_t call_id)79 static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2,
80 					     uintptr_t arg3, uintptr_t arg4,
81 					     uintptr_t call_id)
82 {
83 	register unsigned long a0 __asm__ ("a0") = arg1;
84 	register unsigned long a1 __asm__ ("a1") = arg2;
85 	register unsigned long a2 __asm__ ("a2") = arg3;
86 	register unsigned long a3 __asm__ ("a3") = arg4;
87 	register unsigned long t0 __asm__ ("t0") = call_id;
88 
89 	__asm__ volatile ("ecall"
90 			  : "+r" (a0)
91 			  : "r" (a1), "r" (a2), "r" (a3), "r" (t0)
92 			  : "memory");
93 	return a0;
94 }
95 
arch_syscall_invoke3(uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,uintptr_t call_id)96 static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2,
97 					     uintptr_t arg3,
98 					     uintptr_t call_id)
99 {
100 	register unsigned long a0 __asm__ ("a0") = arg1;
101 	register unsigned long a1 __asm__ ("a1") = arg2;
102 	register unsigned long a2 __asm__ ("a2") = arg3;
103 	register unsigned long t0 __asm__ ("t0") = call_id;
104 
105 	__asm__ volatile ("ecall"
106 			  : "+r" (a0)
107 			  : "r" (a1), "r" (a2), "r" (t0)
108 			  : "memory");
109 	return a0;
110 }
111 
arch_syscall_invoke2(uintptr_t arg1,uintptr_t arg2,uintptr_t call_id)112 static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2,
113 					     uintptr_t call_id)
114 {
115 	register unsigned long a0 __asm__ ("a0") = arg1;
116 	register unsigned long a1 __asm__ ("a1") = arg2;
117 	register unsigned long t0 __asm__ ("t0") = call_id;
118 
119 	__asm__ volatile ("ecall"
120 			  : "+r" (a0)
121 			  : "r" (a1), "r" (t0)
122 			  : "memory");
123 	return a0;
124 }
125 
arch_syscall_invoke1(uintptr_t arg1,uintptr_t call_id)126 static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, uintptr_t call_id)
127 {
128 	register unsigned long a0 __asm__ ("a0") = arg1;
129 	register unsigned long t0 __asm__ ("t0") = call_id;
130 
131 	__asm__ volatile ("ecall"
132 			  : "+r" (a0)
133 			  : "r" (t0)
134 			  : "memory");
135 	return a0;
136 }
137 
arch_syscall_invoke0(uintptr_t call_id)138 static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id)
139 {
140 	register unsigned long a0 __asm__ ("a0");
141 	register unsigned long t0 __asm__ ("t0") = call_id;
142 
143 	__asm__ volatile ("ecall"
144 			  : "=r" (a0)
145 			  : "r" (t0)
146 			  : "memory");
147 	return a0;
148 }
149 
150 #ifdef CONFIG_USERSPACE
151 register unsigned long riscv_tp_reg __asm__ ("tp");
152 
arch_is_user_context(void)153 static inline bool arch_is_user_context(void)
154 {
155 	/* don't try accessing TLS variables if tp is not initialized */
156 	if (riscv_tp_reg == 0) {
157 		return false;
158 	}
159 
160 	/* Defined in arch/riscv/core/thread.c */
161 	extern __thread uint8_t is_user_mode;
162 
163 	return is_user_mode != 0;
164 }
165 #endif
166 
167 #ifdef __cplusplus
168 }
169 #endif
170 
171 #endif /* _ASMLANGUAGE */
172 #endif /* ZEPHYR_INCLUDE_ARCH_RISCV_SYSCALL_H_ */
173