1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#ifndef __LIBSEL4_SEL4_SEL4_ARCH_SYSCALLS_H_
14#define __LIBSEL4_SEL4_SEL4_ARCH_SYSCALLS_H_
15
16#include <autoconf.h>
17#include <sel4/arch/functions.h>
18#include <sel4/types.h>
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_recv: Sends one register (destination) to the kernel and expects all
36 *      registers to be returned by the kernel. Used for directed receives that return
37 *      data (e.g. seL4_Recv)
38 *
39 * arm_sys_send_recv: Fills all registers into the kernel and expects all of them
40 *      to be filled on return by the kernel. Used for directed send+receives
41 *      where data flows both directions (e.g. seL4_Call, seL4_ReplyWait)
42 *
43 * arm_sys_nbsend_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 on separate caps (e.g. seL4_NBSendRecv)
46 *
47 * arm_sys_null: Does not send any registers to the kernel or expect anything to
48 *      be returned from the kernel. Used to trigger implicit kernel actions without
49 *      any data (e.g. seL4_Yield)
50 */
51
52static inline void
53arm_sys_send(seL4_Word sys, seL4_Word dest, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1, seL4_Word mr2, seL4_Word mr3)
54{
55    register seL4_Word destptr asm("x0") = dest;
56    register seL4_Word info asm("x1") = info_arg;
57
58    /* Load beginning of the message into registers. */
59    register seL4_Word msg0 asm("x2") = mr0;
60    register seL4_Word msg1 asm("x3") = mr1;
61    register seL4_Word msg2 asm("x4") = mr2;
62    register seL4_Word msg3 asm("x5") = mr3;
63
64    /* Perform the system call. */
65    register seL4_Word scno asm("x7") = sys;
66    asm volatile (
67        "svc #0"
68        : "+r" (destptr), "+r" (msg0), "+r" (msg1), "+r" (msg2),
69        "+r" (msg3), "+r" (info)
70        : "r"(scno)
71    );
72}
73
74static inline void
75arm_sys_send_null(seL4_Word sys, seL4_Word src, seL4_Word info_arg)
76{
77    register seL4_Word destptr asm("x0") = src;
78    register seL4_Word info asm("x1") = info_arg;
79
80    /* Perform the system call. */
81    register seL4_Word scno asm("x7") = sys;
82    asm volatile (
83        "svc #0"
84        : "+r" (destptr), "+r" (info)
85        : "r"(scno)
86    );
87}
88
89static inline void
90arm_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, seL4_Word reply)
91{
92    register seL4_Word src_and_badge asm("x0") = src;
93    register seL4_Word info asm("x1");
94
95    /* Incoming message registers. */
96    register seL4_Word msg0 asm("x2");
97    register seL4_Word msg1 asm("x3");
98    register seL4_Word msg2 asm("x4");
99    register seL4_Word msg3 asm("x5");
100    register seL4_Word reply_reg asm("x6") = reply;
101
102    /* Perform the system call. */
103    register seL4_Word scno asm("x7") = sys;
104    asm volatile (
105        "svc #0"
106        : "=r" (msg0), "=r" (msg1), "=r" (msg2), "=r" (msg3),
107        "=r" (info), "+r" (src_and_badge)
108        : "r"(scno), "r" (reply_reg)
109        : "memory"
110    );
111    *out_badge = src_and_badge;
112    *out_info = info;
113    *out_mr0 = msg0;
114    *out_mr1 = msg1;
115    *out_mr2 = msg2;
116    *out_mr3 = msg3;
117}
118
119static inline void
120arm_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, seL4_Word reply)
121{
122    register seL4_Word destptr asm("x0") = dest;
123    register seL4_Word info asm("x1") = info_arg;
124
125    /* Load beginning of the message into registers. */
126    register seL4_Word msg0 asm("x2") = *in_out_mr0;
127    register seL4_Word msg1 asm("x3") = *in_out_mr1;
128    register seL4_Word msg2 asm("x4") = *in_out_mr2;
129    register seL4_Word msg3 asm("x5") = *in_out_mr3;
130    register seL4_Word reply_reg asm("x6") = reply;
131
132    /* Perform the system call. */
133    register seL4_Word scno asm("x7") = sys;
134    asm volatile (
135        "svc #0"
136        : "+r" (msg0), "+r" (msg1), "+r" (msg2), "+r" (msg3),
137        "+r" (info), "+r" (destptr)
138        : "r"(scno), "r" (reply_reg)
139        : "memory"
140    );
141    *out_info = info;
142    *out_badge = destptr;
143    *in_out_mr0 = msg0;
144    *in_out_mr1 = msg1;
145    *in_out_mr2 = msg2;
146    *in_out_mr3 = msg3;
147}
148
149static inline void
150arm_sys_nbsend_recv(seL4_Word sys, seL4_Word dest, seL4_Word src, seL4_Word *out_badge, seL4_Word info_arg,
151                    seL4_Word *out_info, seL4_Word *in_out_mr0, seL4_Word *in_out_mr1, seL4_Word *in_out_mr2,
152                    seL4_Word *in_out_mr3, seL4_Word reply)
153{
154    register seL4_Word src_and_badge asm("x0") = src;
155    register seL4_Word info asm("x1") = info_arg;
156
157    /* Load the beginning of the message info registers */
158    register seL4_Word msg0 asm("x2") = *in_out_mr0;
159    register seL4_Word msg1 asm("x3") = *in_out_mr1;
160    register seL4_Word msg2 asm("x4") = *in_out_mr2;
161    register seL4_Word msg3 asm("x5") = *in_out_mr3;
162
163    register seL4_Word reply_reg asm("x6") = reply;
164    register seL4_Word dest_reg asm("x8") = dest;
165
166    /* Perform the system call. */
167    register seL4_Word scno asm("x7") = sys;
168    asm volatile (
169        "svc #0"
170        : "+r" (msg0), "+r" (msg1), "+r" (msg2), "+r" (msg3),
171        "+r" (src_and_badge), "+r" (info)
172        : "r" (scno), "r" (reply_reg), "r" (dest_reg)
173        : "memory"
174    );
175
176    *out_badge = src_and_badge;
177    *out_info = info;
178    *in_out_mr0 = msg0;
179    *in_out_mr1 = msg1;
180    *in_out_mr2 = msg2;
181    *in_out_mr3 = msg3;
182}
183
184
185static inline void
186arm_sys_null(seL4_Word sys)
187{
188    register seL4_Word scno asm("x7") = sys;
189    asm volatile (
190        "svc #0"
191        : /* no outputs */
192        : "r"(scno)
193    );
194}
195
196#endif /* __LIBSEL4_SEL4_SEL4_ARCH_SYSCALLS_H_ */
197