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/types.h> 11 12#ifdef CONFIG_KERNEL_MCS 13#define MCS_PARAM_DECL(r) register seL4_Word reply_reg asm(r) = reply 14#define MCS_PARAM , "r"(reply_reg) 15#else 16#define MCS_PARAM_DECL(r) 17#define MCS_PARAM 18#endif 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_send_recv: Fills all registers into the kernel and expects all of them 48 * to be filled on return by the kernel. Used for directed send+receives 49 * where data flows both directions on separate caps (e.g. seL4_NBSendRecv) 50 * 51 * arm_sys_null: Does not send any registers to the kernel or expect anything to 52 * be returned from the kernel. Used to trigger implicit kernel actions without 53 * any data (e.g. seL4_Yield) 54 */ 55 56static inline void arm_sys_send(seL4_Word sys, seL4_Word dest, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1, 57 seL4_Word mr2, seL4_Word mr3) 58{ 59 register seL4_Word destptr asm("r0") = dest; 60 register seL4_Word info asm("r1") = info_arg; 61 62 /* Load beginning of the message into registers. */ 63 register seL4_Word msg0 asm("r2") = mr0; 64 register seL4_Word msg1 asm("r3") = mr1; 65 register seL4_Word msg2 asm("r4") = mr2; 66 register seL4_Word msg3 asm("r5") = mr3; 67 68 /* Perform the system call. */ 69 register seL4_Word scno asm("r7") = sys; 70 asm volatile( 71 "swi $0" 72 : "+r"(destptr), "+r"(msg0), "+r"(msg1), "+r"(msg2), 73 "+r"(msg3), "+r"(info) 74 : "r"(scno) 75 ); 76} 77 78#ifndef CONFIG_KERNEL_MCS 79static inline void arm_sys_reply(seL4_Word sys, seL4_Word info_arg, seL4_Word mr0, seL4_Word mr1, seL4_Word mr2, 80 seL4_Word mr3) 81{ 82 register seL4_Word info asm("r1") = info_arg; 83 84 /* Load beginning of the message into registers. */ 85 register seL4_Word msg0 asm("r2") = mr0; 86 register seL4_Word msg1 asm("r3") = mr1; 87 register seL4_Word msg2 asm("r4") = mr2; 88 register seL4_Word msg3 asm("r5") = mr3; 89 90 /* Perform the system call. */ 91 register seL4_Word scno asm("r7") = sys; 92 asm volatile( 93 "swi $0" 94 : "+r"(msg0), "+r"(msg1), "+r"(msg2), "+r"(msg3), 95 "+r"(info) 96 : "r"(scno) 97 ); 98} 99#endif 100 101static inline void arm_sys_send_null(seL4_Word sys, seL4_Word src, seL4_Word info_arg) 102{ 103 register seL4_Word destptr asm("r0") = src; 104 register seL4_Word info asm("r1") = info_arg; 105 106 /* Perform the system call. */ 107 register seL4_Word scno asm("r7") = sys; 108 asm volatile( 109 "swi $0" 110 : "+r"(destptr), "+r"(info) 111 : "r"(scno) 112 ); 113} 114 115static inline void arm_sys_recv(seL4_Word sys, seL4_Word src, seL4_Word *out_badge, seL4_Word *out_info, 116 seL4_Word *out_mr0, seL4_Word *out_mr1, seL4_Word *out_mr2, seL4_Word *out_mr3, LIBSEL4_UNUSED seL4_Word reply) 117{ 118 register seL4_Word src_and_badge asm("r0") = src; 119 register seL4_Word info asm("r1"); 120 121 /* Incoming message registers. */ 122 register seL4_Word msg0 asm("r2"); 123 register seL4_Word msg1 asm("r3"); 124 register seL4_Word msg2 asm("r4"); 125 register seL4_Word msg3 asm("r5"); 126 127 MCS_PARAM_DECL("r6"); 128 129 /* Perform the system call. */ 130 register seL4_Word scno asm("r7") = sys; 131 asm volatile( 132 "swi $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("r0") = dest; 151 register seL4_Word info asm("r1") = info_arg; 152 153 /* Load beginning of the message into registers. */ 154 register seL4_Word msg0 asm("r2") = *in_out_mr0; 155 register seL4_Word msg1 asm("r3") = *in_out_mr1; 156 register seL4_Word msg2 asm("r4") = *in_out_mr2; 157 register seL4_Word msg3 asm("r5") = *in_out_mr3; 158 159 /* Perform the system call. */ 160 MCS_PARAM_DECL("r6"); 161 register seL4_Word scno asm("r7") = sys; 162 asm volatile( 163 "swi $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("r0") = src; 184 register seL4_Word info asm("r1") = info_arg; 185 186 /* Load the beginning of the message info registers */ 187 register seL4_Word msg0 asm("r2") = *in_out_mr0; 188 register seL4_Word msg1 asm("r3") = *in_out_mr1; 189 register seL4_Word msg2 asm("r4") = *in_out_mr2; 190 register seL4_Word msg3 asm("r5") = *in_out_mr3; 191 192 register seL4_Word reply_reg asm("r6") = reply; 193 register seL4_Word dest_reg asm("r8") = dest; 194 195 /* Perform the system call. */ 196 register seL4_Word scno asm("r7") = sys; 197 asm volatile( 198 "swi $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("r7") = sys; 217 asm volatile( 218 "swi $0" 219 : /* no outputs */ 220 : "r"(scno) 221 ); 222} 223