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