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/functions.h>
11 #include <sel4/types.h>
12 
13 #ifdef CONFIG_KERNEL_MCS
14 #define MCS_PARAM_DECL(r)    register seL4_Word reply_reg asm(r) = reply
15 #define MCS_PARAM    , "r"(reply_reg)
16 #else
17 #define MCS_PARAM_DECL(r)
18 #define MCS_PARAM
19 #endif
20 
21 /*
22  * To simplify the definition of the various seL4 syscalls/syscall-wrappers we define
23  * some helper assembly functions. These functions are designed to cover the different
24  * cases of sending/receiving data in registers to/from the kernel. The most 'complex'
25  * version is arm_sys_send_recv, and all other functions are limited versions that allow
26  * for registers to not be unnecessarily clobbered
27  *
28  * arm_sys_send: Fills all registers into the kernel, expects nothing to be sent back
29  *      by the kernel. Used for direction one way sends that contain data (e.g. seL4_Send,
30  *      seL4_NBSend)
31  *
32  * arm_sys_send_null: Only fills metadata registers into the kernel (skips message
33  *      registers). Expects nothing to be sent back by the kernel. Used by directional
34  *      one way sends that do not contain data (e.g. seL4_Notify)
35  *
36  * arm_sys_reply: Similar to arm_sys_send except it does not take a word for the
37  *      destination register. Used for undirected one way sends that contain data
38  *      (e.g. seL4_Reply)
39  *
40  * arm_sys_recv: Sends one register (destination) to the kernel and expects all
41  *      registers to be returned by the kernel. Used for directed receives that return
42  *      data (e.g. seL4_Recv)
43  *
44  * arm_sys_send_recv: Fills all registers into the kernel and expects all of them
45  *      to be filled on return by the kernel. Used for directed send+receives
46  *      where data flows both directions (e.g. seL4_Call, seL4_ReplyWait)
47  *
48  * arm_sys_nbsend_recv: Fills all registers into the kernel and expects all of them
49  *      to be filled on return by the kernel. Used for directed send+receives
50  *      where data flows both directions on separate caps (e.g. seL4_NBSendRecv)
51  *
52  * arm_sys_null: Does not send any registers to the kernel or expect anything to
53  *      be returned from the kernel. Used to trigger implicit kernel actions without
54  *      any data (e.g. seL4_Yield)
55  */
56 
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)57 static inline void arm_sys_send(seL4_Word sys, seL4_Word dest, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1,
58                                 seL4_Word mr2, seL4_Word mr3)
59 {
60     register seL4_Word destptr asm("x0") = dest;
61     register seL4_Word info asm("x1") = info_arg;
62 
63     /* Load beginning of the message into registers. */
64     register seL4_Word msg0 asm("x2") = mr0;
65     register seL4_Word msg1 asm("x3") = mr1;
66     register seL4_Word msg2 asm("x4") = mr2;
67     register seL4_Word msg3 asm("x5") = mr3;
68 
69     /* Perform the system call. */
70     register seL4_Word scno asm("x7") = sys;
71     asm volatile(
72         "svc #0"
73         : "+r"(destptr), "+r"(msg0), "+r"(msg1), "+r"(msg2),
74         "+r"(msg3), "+r"(info)
75         : "r"(scno)
76     );
77 }
78 
79 #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)80 static inline void arm_sys_reply(seL4_Word sys, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1, seL4_Word mr2,
81                                  seL4_Word mr3)
82 {
83     register seL4_Word info asm("x1") = info_arg;
84 
85     /* Load beginning of the message into registers. */
86     register seL4_Word msg0 asm("x2") = mr0;
87     register seL4_Word msg1 asm("x3") = mr1;
88     register seL4_Word msg2 asm("x4") = mr2;
89     register seL4_Word msg3 asm("x5") = mr3;
90 
91     /* Perform the system call. */
92     register seL4_Word scno asm("x7") = sys;
93     asm volatile(
94         "svc #0"
95         : "+r"(msg0), "+r"(msg1), "+r"(msg2), "+r"(msg3),
96         "+r"(info)
97         : "r"(scno)
98     );
99 }
100 #endif
101 
arm_sys_send_null(seL4_Word sys,seL4_Word src,seL4_Word info_arg)102 static inline void arm_sys_send_null(seL4_Word sys, seL4_Word src, seL4_Word info_arg)
103 {
104     register seL4_Word destptr asm("x0") = src;
105     register seL4_Word info asm("x1") = info_arg;
106 
107     /* Perform the system call. */
108     register seL4_Word scno asm("x7") = sys;
109     asm volatile(
110         "svc #0"
111         : "+r"(destptr), "+r"(info)
112         : "r"(scno)
113     );
114 }
115 
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)116 static inline void arm_sys_recv(seL4_Word sys, seL4_Word src, seL4_Word *out_badge, seL4_Word *out_info,
117                                 seL4_Word *out_mr0, seL4_Word *out_mr1, seL4_Word *out_mr2, seL4_Word *out_mr3, LIBSEL4_UNUSED seL4_Word reply)
118 {
119     register seL4_Word src_and_badge asm("x0") = src;
120     register seL4_Word info asm("x1");
121 
122     /* Incoming message registers. */
123     register seL4_Word msg0 asm("x2");
124     register seL4_Word msg1 asm("x3");
125     register seL4_Word msg2 asm("x4");
126     register seL4_Word msg3 asm("x5");
127     MCS_PARAM_DECL("x6");
128 
129     /* Perform the system call. */
130     register seL4_Word scno asm("x7") = sys;
131     asm volatile(
132         "svc #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("x0") = dest;
151     register seL4_Word info asm("x1") = info_arg;
152 
153     /* Load beginning of the message into registers. */
154     register seL4_Word msg0 asm("x2") = *in_out_mr0;
155     register seL4_Word msg1 asm("x3") = *in_out_mr1;
156     register seL4_Word msg2 asm("x4") = *in_out_mr2;
157     register seL4_Word msg3 asm("x5") = *in_out_mr3;
158     MCS_PARAM_DECL("x6");
159 
160     /* Perform the system call. */
161     register seL4_Word scno asm("x7") = sys;
162     asm volatile(
163         "svc #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("x0") = src;
184     register seL4_Word info asm("x1") = info_arg;
185 
186     /* Load the beginning of the message info registers */
187     register seL4_Word msg0 asm("x2") = *in_out_mr0;
188     register seL4_Word msg1 asm("x3") = *in_out_mr1;
189     register seL4_Word msg2 asm("x4") = *in_out_mr2;
190     register seL4_Word msg3 asm("x5") = *in_out_mr3;
191 
192     register seL4_Word reply_reg asm("x6") = reply;
193     register seL4_Word dest_reg asm("x8") = dest;
194 
195     /* Perform the system call. */
196     register seL4_Word scno asm("x7") = sys;
197     asm volatile(
198         "svc #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("x7") = sys;
217     asm volatile(
218         "svc #0"
219         : /* no outputs */
220         : "r"(scno)
221     );
222 }
223