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
57static 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
80static 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
102static 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
116static 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
146static 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
178static 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
214static 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