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_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_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_reply(seL4_Word sys, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1, seL4_Word mr2, seL4_Word mr3)
76{
77    register seL4_Word info asm("x1") = info_arg;
78
79    /* Load beginning of the message into registers. */
80    register seL4_Word msg0 asm("x2") = mr0;
81    register seL4_Word msg1 asm("x3") = mr1;
82    register seL4_Word msg2 asm("x4") = mr2;
83    register seL4_Word msg3 asm("x5") = mr3;
84
85    /* Perform the system call. */
86    register seL4_Word scno asm("x7") = sys;
87    asm volatile (
88        "svc #0"
89        : "+r" (msg0), "+r" (msg1), "+r" (msg2), "+r" (msg3),
90        "+r" (info)
91        : "r"(scno)
92    );
93}
94
95static inline void
96arm_sys_send_null(seL4_Word sys, seL4_Word src, seL4_Word info_arg)
97{
98    register seL4_Word destptr asm("x0") = src;
99    register seL4_Word info asm("x1") = info_arg;
100
101    /* Perform the system call. */
102    register seL4_Word scno asm("x7") = sys;
103    asm volatile (
104        "svc #0"
105        : "+r" (destptr), "+r" (info)
106        : "r"(scno)
107    );
108}
109
110static inline void
111arm_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)
112{
113    register seL4_Word src_and_badge asm("x0") = src;
114    register seL4_Word info asm("x1");
115
116    /* Incoming message registers. */
117    register seL4_Word msg0 asm("x2");
118    register seL4_Word msg1 asm("x3");
119    register seL4_Word msg2 asm("x4");
120    register seL4_Word msg3 asm("x5");
121
122    /* Perform the system call. */
123    register seL4_Word scno asm("x7") = sys;
124    asm volatile (
125        "svc #0"
126        : "=r" (msg0), "=r" (msg1), "=r" (msg2), "=r" (msg3),
127        "=r" (info), "+r" (src_and_badge)
128        : "r"(scno)
129        : "memory"
130    );
131    *out_badge = src_and_badge;
132    *out_info = info;
133    *out_mr0 = msg0;
134    *out_mr1 = msg1;
135    *out_mr2 = msg2;
136    *out_mr3 = msg3;
137}
138
139static inline void
140arm_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)
141{
142    register seL4_Word destptr asm("x0") = dest;
143    register seL4_Word info asm("x1") = info_arg;
144
145    /* Load beginning of the message into registers. */
146    register seL4_Word msg0 asm("x2") = *in_out_mr0;
147    register seL4_Word msg1 asm("x3") = *in_out_mr1;
148    register seL4_Word msg2 asm("x4") = *in_out_mr2;
149    register seL4_Word msg3 asm("x5") = *in_out_mr3;
150
151    /* Perform the system call. */
152    register seL4_Word scno asm("x7") = sys;
153    asm volatile (
154        "svc #0"
155        : "+r" (msg0), "+r" (msg1), "+r" (msg2), "+r" (msg3),
156        "+r" (info), "+r" (destptr)
157        : "r"(scno)
158        : "memory"
159    );
160    *out_info = info;
161    *out_badge = destptr;
162    *in_out_mr0 = msg0;
163    *in_out_mr1 = msg1;
164    *in_out_mr2 = msg2;
165    *in_out_mr3 = msg3;
166}
167
168static inline void
169arm_sys_null(seL4_Word sys)
170{
171    register seL4_Word scno asm("x7") = sys;
172    asm volatile (
173        "svc #0"
174        : /* no outputs */
175        : "r"(scno)
176    );
177}
178
179#endif /* __LIBSEL4_SEL4_SEL4_ARCH_SYSCALLS_H_ */
180