1 /*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #pragma once
8
9 #include <autoconf.h>
10 #include <sel4/types.h>
11
12 #ifdef CONFIG_KERNEL_MCS
13 #define MCS_PARAM_DECL(r) register seL4_Word reply_reg asm(r) = reply
14 #define MCS_PARAM , "r"(reply_reg)
15 #else
16 #define MCS_PARAM_DECL(r)
17 #define MCS_PARAM
18 #endif
19
20 /*
21 * To simplify the definition of the various seL4 syscalls/syscall-wrappers we define
22 * some helper assembly functions. These functions are designed to cover the different
23 * cases of sending/receiving data in registers to/from the kernel. The most 'complex'
24 * version is arm_sys_send_recv, and all other functions are limited versions that allow
25 * for registers to not be unnecessarily clobbered
26 *
27 * arm_sys_send: Fills all registers into the kernel, expects nothing to be sent back
28 * by the kernel. Used for direction one way sends that contain data (e.g. seL4_Send,
29 * seL4_NBSend)
30 *
31 * arm_sys_send_null: Only fills metadata registers into the kernel (skips message
32 * registers). Expects nothing to be sent back by the kernel. Used by directional
33 * one way sends that do not contain data (e.g. seL4_Notify)
34 *
35 * arm_sys_reply: Similar to arm_sys_send except it does not take a word for the
36 * destination register. Used for undirected one way sends that contain data
37 * (e.g. seL4_Reply)
38 *
39 * arm_sys_recv: Sends one register (destination) to the kernel and expects all
40 * registers to be returned by the kernel. Used for directed receives that return
41 * data (e.g. seL4_Recv)
42 *
43 * arm_sys_send_recv: Fills all registers into the kernel and expects all of them
44 * to be filled on return by the kernel. Used for directed send+receives
45 * where data flows both directions (e.g. seL4_Call, seL4_ReplyWait)
46 *
47 * arm_sys_send_recv: Fills all registers into the kernel and expects all of them
48 * to be filled on return by the kernel. Used for directed send+receives
49 * where data flows both directions on separate caps (e.g. seL4_NBSendRecv)
50 *
51 * arm_sys_null: Does not send any registers to the kernel or expect anything to
52 * be returned from the kernel. Used to trigger implicit kernel actions without
53 * any data (e.g. seL4_Yield)
54 */
55
arm_sys_send(seL4_Word sys,seL4_Word dest,seL4_Word info_arg,seL4_Word mr0,seL4_Word mr1,seL4_Word mr2,seL4_Word mr3)56 static inline void arm_sys_send(seL4_Word sys, seL4_Word dest, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1,
57 seL4_Word mr2, seL4_Word mr3)
58 {
59 register seL4_Word destptr asm("r0") = dest;
60 register seL4_Word info asm("r1") = info_arg;
61
62 /* Load beginning of the message into registers. */
63 register seL4_Word msg0 asm("r2") = mr0;
64 register seL4_Word msg1 asm("r3") = mr1;
65 register seL4_Word msg2 asm("r4") = mr2;
66 register seL4_Word msg3 asm("r5") = mr3;
67
68 /* Perform the system call. */
69 register seL4_Word scno asm("r7") = sys;
70 asm volatile(
71 "swi $0"
72 : "+r"(destptr), "+r"(msg0), "+r"(msg1), "+r"(msg2),
73 "+r"(msg3), "+r"(info)
74 : "r"(scno)
75 );
76 }
77
78 #ifndef CONFIG_KERNEL_MCS
arm_sys_reply(seL4_Word sys,seL4_Word info_arg,seL4_Word mr0,seL4_Word mr1,seL4_Word mr2,seL4_Word mr3)79 static inline void arm_sys_reply(seL4_Word sys, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1, seL4_Word mr2,
80 seL4_Word mr3)
81 {
82 register seL4_Word info asm("r1") = info_arg;
83
84 /* Load beginning of the message into registers. */
85 register seL4_Word msg0 asm("r2") = mr0;
86 register seL4_Word msg1 asm("r3") = mr1;
87 register seL4_Word msg2 asm("r4") = mr2;
88 register seL4_Word msg3 asm("r5") = mr3;
89
90 /* Perform the system call. */
91 register seL4_Word scno asm("r7") = sys;
92 asm volatile(
93 "swi $0"
94 : "+r"(msg0), "+r"(msg1), "+r"(msg2), "+r"(msg3),
95 "+r"(info)
96 : "r"(scno)
97 );
98 }
99 #endif
100
arm_sys_send_null(seL4_Word sys,seL4_Word src,seL4_Word info_arg)101 static inline void arm_sys_send_null(seL4_Word sys, seL4_Word src, seL4_Word info_arg)
102 {
103 register seL4_Word destptr asm("r0") = src;
104 register seL4_Word info asm("r1") = info_arg;
105
106 /* Perform the system call. */
107 register seL4_Word scno asm("r7") = sys;
108 asm volatile(
109 "swi $0"
110 : "+r"(destptr), "+r"(info)
111 : "r"(scno)
112 );
113 }
114
arm_sys_recv(seL4_Word sys,seL4_Word src,seL4_Word * out_badge,seL4_Word * out_info,seL4_Word * out_mr0,seL4_Word * out_mr1,seL4_Word * out_mr2,seL4_Word * out_mr3,LIBSEL4_UNUSED seL4_Word reply)115 static inline void arm_sys_recv(seL4_Word sys, seL4_Word src, seL4_Word *out_badge, seL4_Word *out_info,
116 seL4_Word *out_mr0, seL4_Word *out_mr1, seL4_Word *out_mr2, seL4_Word *out_mr3, LIBSEL4_UNUSED seL4_Word reply)
117 {
118 register seL4_Word src_and_badge asm("r0") = src;
119 register seL4_Word info asm("r1");
120
121 /* Incoming message registers. */
122 register seL4_Word msg0 asm("r2");
123 register seL4_Word msg1 asm("r3");
124 register seL4_Word msg2 asm("r4");
125 register seL4_Word msg3 asm("r5");
126
127 MCS_PARAM_DECL("r6");
128
129 /* Perform the system call. */
130 register seL4_Word scno asm("r7") = sys;
131 asm volatile(
132 "swi $0"
133 : "=r"(msg0), "=r"(msg1), "=r"(msg2), "=r"(msg3),
134 "=r"(info), "+r"(src_and_badge)
135 : "r"(scno) MCS_PARAM
136 : "memory"
137 );
138 *out_badge = src_and_badge;
139 *out_info = info;
140 *out_mr0 = msg0;
141 *out_mr1 = msg1;
142 *out_mr2 = msg2;
143 *out_mr3 = msg3;
144 }
145
arm_sys_send_recv(seL4_Word sys,seL4_Word dest,seL4_Word * out_badge,seL4_Word info_arg,seL4_Word * out_info,seL4_Word * in_out_mr0,seL4_Word * in_out_mr1,seL4_Word * in_out_mr2,seL4_Word * in_out_mr3,LIBSEL4_UNUSED seL4_Word reply)146 static inline void arm_sys_send_recv(seL4_Word sys, seL4_Word dest, seL4_Word *out_badge, seL4_Word info_arg,
147 seL4_Word *out_info, seL4_Word *in_out_mr0, seL4_Word *in_out_mr1, seL4_Word *in_out_mr2, seL4_Word *in_out_mr3,
148 LIBSEL4_UNUSED seL4_Word reply)
149 {
150 register seL4_Word destptr asm("r0") = dest;
151 register seL4_Word info asm("r1") = info_arg;
152
153 /* Load beginning of the message into registers. */
154 register seL4_Word msg0 asm("r2") = *in_out_mr0;
155 register seL4_Word msg1 asm("r3") = *in_out_mr1;
156 register seL4_Word msg2 asm("r4") = *in_out_mr2;
157 register seL4_Word msg3 asm("r5") = *in_out_mr3;
158
159 /* Perform the system call. */
160 MCS_PARAM_DECL("r6");
161 register seL4_Word scno asm("r7") = sys;
162 asm volatile(
163 "swi $0"
164 : "+r"(msg0), "+r"(msg1), "+r"(msg2), "+r"(msg3),
165 "+r"(info), "+r"(destptr)
166 : "r"(scno) MCS_PARAM
167 : "memory"
168 );
169 *out_info = info;
170 *out_badge = destptr;
171 *in_out_mr0 = msg0;
172 *in_out_mr1 = msg1;
173 *in_out_mr2 = msg2;
174 *in_out_mr3 = msg3;
175 }
176
177 #ifdef CONFIG_KERNEL_MCS
arm_sys_nbsend_recv(seL4_Word sys,seL4_Word dest,seL4_Word src,seL4_Word * out_badge,seL4_Word info_arg,seL4_Word * out_info,seL4_Word * in_out_mr0,seL4_Word * in_out_mr1,seL4_Word * in_out_mr2,seL4_Word * in_out_mr3,seL4_Word reply)178 static inline void arm_sys_nbsend_recv(seL4_Word sys, seL4_Word dest, seL4_Word src, seL4_Word *out_badge,
179 seL4_Word info_arg,
180 seL4_Word *out_info, seL4_Word *in_out_mr0, seL4_Word *in_out_mr1, seL4_Word *in_out_mr2,
181 seL4_Word *in_out_mr3, seL4_Word reply)
182 {
183 register seL4_Word src_and_badge asm("r0") = src;
184 register seL4_Word info asm("r1") = info_arg;
185
186 /* Load the beginning of the message info registers */
187 register seL4_Word msg0 asm("r2") = *in_out_mr0;
188 register seL4_Word msg1 asm("r3") = *in_out_mr1;
189 register seL4_Word msg2 asm("r4") = *in_out_mr2;
190 register seL4_Word msg3 asm("r5") = *in_out_mr3;
191
192 register seL4_Word reply_reg asm("r6") = reply;
193 register seL4_Word dest_reg asm("r8") = dest;
194
195 /* Perform the system call. */
196 register seL4_Word scno asm("r7") = sys;
197 asm volatile(
198 "swi $0"
199 : "+r"(msg0), "+r"(msg1), "+r"(msg2), "+r"(msg3),
200 "+r"(src_and_badge), "+r"(info)
201 : "r"(scno), "r"(reply_reg), "r"(dest_reg)
202 : "memory"
203 );
204
205 *out_badge = src_and_badge;
206 *out_info = info;
207 *in_out_mr0 = msg0;
208 *in_out_mr1 = msg1;
209 *in_out_mr2 = msg2;
210 *in_out_mr3 = msg3;
211 }
212 #endif
213
arm_sys_null(seL4_Word sys)214 static inline void arm_sys_null(seL4_Word sys)
215 {
216 register seL4_Word scno asm("r7") = sys;
217 asm volatile(
218 "swi $0"
219 : /* no outputs */
220 : "r"(scno)
221 );
222 }
223