| 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("../../std.zig"); |
| 3 | const SYS = std.os.linux.SYS; |
| 4 | |
| 5 | pub fn syscall0(number: SYS) u64 { |
| 6 | return asm volatile ( |
| 7 | \\ callsys |
| 8 | \\ beq $19, 1f |
| 9 | \\ negq $0, $0 |
| 10 | \\1: |
| 11 | : [ret] "={$0}" (-> u64), |
| 12 | : [number] "{$0}" (number), |
| 13 | : .{ |
| 14 | .r1 = true, |
| 15 | .r2 = true, |
| 16 | .r3 = true, |
| 17 | .r4 = true, |
| 18 | .r5 = true, |
| 19 | .r6 = true, |
| 20 | .r7 = true, |
| 21 | .r8 = true, |
| 22 | .r22 = true, |
| 23 | .r23 = true, |
| 24 | .r24 = true, |
| 25 | .r25 = true, |
| 26 | .r27 = true, |
| 27 | .r28 = true, |
| 28 | .memory = true, |
| 29 | .r16 = true, |
| 30 | .r17 = true, |
| 31 | .r18 = true, |
| 32 | .r20 = true, |
| 33 | .r21 = true, |
| 34 | }); |
| 35 | } |
| 36 | |
| 37 | pub fn syscall1(number: SYS, arg1: u64) u64 { |
| 38 | // These registers are both inputs and clobbers. |
| 39 | var r16_out: u64 = undefined; |
| 40 | return asm volatile ( |
| 41 | \\ callsys |
| 42 | \\ beq $19, 1f |
| 43 | \\ negq $0, $0 |
| 44 | \\1: |
| 45 | : [ret] "={$0}" (-> u64), |
| 46 | [r16_out] "={$16}" (r16_out), |
| 47 | : [number] "{$0}" (number), |
| 48 | [arg1] "{$16}" (arg1), |
| 49 | : .{ |
| 50 | .r1 = true, |
| 51 | .r2 = true, |
| 52 | .r3 = true, |
| 53 | .r4 = true, |
| 54 | .r5 = true, |
| 55 | .r6 = true, |
| 56 | .r7 = true, |
| 57 | .r8 = true, |
| 58 | .r22 = true, |
| 59 | .r23 = true, |
| 60 | .r24 = true, |
| 61 | .r25 = true, |
| 62 | .r27 = true, |
| 63 | .r28 = true, |
| 64 | .memory = true, |
| 65 | .r17 = true, |
| 66 | .r18 = true, |
| 67 | .r20 = true, |
| 68 | .r21 = true, |
| 69 | }); |
| 70 | } |
| 71 | |
| 72 | pub fn syscall2(number: SYS, arg1: u64, arg2: u64) u64 { |
| 73 | // These registers are both inputs and clobbers. |
| 74 | var r16_out: u64 = undefined; |
| 75 | var r17_out: u64 = undefined; |
| 76 | return asm volatile ( |
| 77 | \\ callsys |
| 78 | \\ beq $19, 1f |
| 79 | \\ negq $0, $0 |
| 80 | \\1: |
| 81 | : [ret] "={$0}" (-> u64), |
| 82 | [r16_out] "={$16}" (r16_out), |
| 83 | [r17_out] "={$17}" (r17_out), |
| 84 | : [number] "{$0}" (number), |
| 85 | [arg1] "{$16}" (arg1), |
| 86 | [arg2] "{$17}" (arg2), |
| 87 | : .{ |
| 88 | .r1 = true, |
| 89 | .r2 = true, |
| 90 | .r3 = true, |
| 91 | .r4 = true, |
| 92 | .r5 = true, |
| 93 | .r6 = true, |
| 94 | .r7 = true, |
| 95 | .r8 = true, |
| 96 | .r22 = true, |
| 97 | .r23 = true, |
| 98 | .r24 = true, |
| 99 | .r25 = true, |
| 100 | .r27 = true, |
| 101 | .r28 = true, |
| 102 | .memory = true, |
| 103 | .r18 = true, |
| 104 | .r20 = true, |
| 105 | .r21 = true, |
| 106 | }); |
| 107 | } |
| 108 | |
| 109 | pub fn syscall3(number: SYS, arg1: u64, arg2: u64, arg3: u64) u64 { |
| 110 | // These registers are both inputs and clobbers. |
| 111 | var r16_out: u64 = undefined; |
| 112 | var r17_out: u64 = undefined; |
| 113 | var r18_out: u64 = undefined; |
| 114 | return asm volatile ( |
| 115 | \\ callsys |
| 116 | \\ beq $19, 1f |
| 117 | \\ negq $0, $0 |
| 118 | \\1: |
| 119 | : [ret] "={$0}" (-> u64), |
| 120 | [r16_out] "={$16}" (r16_out), |
| 121 | [r17_out] "={$17}" (r17_out), |
| 122 | [r18_out] "={$18}" (r18_out), |
| 123 | : [number] "{$0}" (number), |
| 124 | [arg1] "{$16}" (arg1), |
| 125 | [arg2] "{$17}" (arg2), |
| 126 | [arg3] "{$18}" (arg3), |
| 127 | : .{ |
| 128 | .r1 = true, |
| 129 | .r2 = true, |
| 130 | .r3 = true, |
| 131 | .r4 = true, |
| 132 | .r5 = true, |
| 133 | .r6 = true, |
| 134 | .r7 = true, |
| 135 | .r8 = true, |
| 136 | .r22 = true, |
| 137 | .r23 = true, |
| 138 | .r24 = true, |
| 139 | .r25 = true, |
| 140 | .r27 = true, |
| 141 | .r28 = true, |
| 142 | .memory = true, |
| 143 | .r20 = true, |
| 144 | .r21 = true, |
| 145 | }); |
| 146 | } |
| 147 | |
| 148 | pub fn syscall4(number: SYS, arg1: u64, arg2: u64, arg3: u64, arg4: u64) u64 { |
| 149 | // These registers are both inputs and clobbers. |
| 150 | var r16_out: u64 = undefined; |
| 151 | var r17_out: u64 = undefined; |
| 152 | var r18_out: u64 = undefined; |
| 153 | var r19_out: u64 = undefined; |
| 154 | return asm volatile ( |
| 155 | \\ callsys |
| 156 | \\ beq $19, 1f |
| 157 | \\ negq $0, $0 |
| 158 | \\1: |
| 159 | : [ret] "={$0}" (-> u64), |
| 160 | [r16_out] "={$16}" (r16_out), |
| 161 | [r17_out] "={$17}" (r17_out), |
| 162 | [r18_out] "={$18}" (r18_out), |
| 163 | [r19_out] "={$19}" (r19_out), |
| 164 | : [number] "{$0}" (number), |
| 165 | [arg1] "{$16}" (arg1), |
| 166 | [arg2] "{$17}" (arg2), |
| 167 | [arg3] "{$18}" (arg3), |
| 168 | [arg4] "{$19}" (arg4), |
| 169 | : .{ |
| 170 | .r1 = true, |
| 171 | .r2 = true, |
| 172 | .r3 = true, |
| 173 | .r4 = true, |
| 174 | .r5 = true, |
| 175 | .r6 = true, |
| 176 | .r7 = true, |
| 177 | .r8 = true, |
| 178 | .r22 = true, |
| 179 | .r23 = true, |
| 180 | .r24 = true, |
| 181 | .r25 = true, |
| 182 | .r27 = true, |
| 183 | .r28 = true, |
| 184 | .memory = true, |
| 185 | .r20 = true, |
| 186 | .r21 = true, |
| 187 | }); |
| 188 | } |
| 189 | |
| 190 | pub fn syscall5(number: SYS, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) u64 { |
| 191 | // These registers are both inputs and clobbers. |
| 192 | var r16_out: u64 = undefined; |
| 193 | var r17_out: u64 = undefined; |
| 194 | var r18_out: u64 = undefined; |
| 195 | var r19_out: u64 = undefined; |
| 196 | var r20_out: u64 = undefined; |
| 197 | return asm volatile ( |
| 198 | \\ callsys |
| 199 | \\ beq $19, 1f |
| 200 | \\ negq $0, $0 |
| 201 | \\1: |
| 202 | : [ret] "={$0}" (-> u64), |
| 203 | [r16_out] "={$16}" (r16_out), |
| 204 | [r17_out] "={$17}" (r17_out), |
| 205 | [r18_out] "={$18}" (r18_out), |
| 206 | [r19_out] "={$19}" (r19_out), |
| 207 | [r20_out] "={$20}" (r20_out), |
| 208 | : [number] "{$0}" (number), |
| 209 | [arg1] "{$16}" (arg1), |
| 210 | [arg2] "{$17}" (arg2), |
| 211 | [arg3] "{$18}" (arg3), |
| 212 | [arg4] "{$19}" (arg4), |
| 213 | [arg5] "{$20}" (arg5), |
| 214 | : .{ |
| 215 | .r1 = true, |
| 216 | .r2 = true, |
| 217 | .r3 = true, |
| 218 | .r4 = true, |
| 219 | .r5 = true, |
| 220 | .r6 = true, |
| 221 | .r7 = true, |
| 222 | .r8 = true, |
| 223 | .r22 = true, |
| 224 | .r23 = true, |
| 225 | .r24 = true, |
| 226 | .r25 = true, |
| 227 | .r27 = true, |
| 228 | .r28 = true, |
| 229 | .memory = true, |
| 230 | .r21 = true, |
| 231 | }); |
| 232 | } |
| 233 | |
| 234 | pub fn syscall6( |
| 235 | number: SYS, |
| 236 | arg1: u64, |
| 237 | arg2: u64, |
| 238 | arg3: u64, |
| 239 | arg4: u64, |
| 240 | arg5: u64, |
| 241 | arg6: u64, |
| 242 | ) u64 { |
| 243 | // These registers are both inputs and clobbers. |
| 244 | var r16_out: u64 = undefined; |
| 245 | var r17_out: u64 = undefined; |
| 246 | var r18_out: u64 = undefined; |
| 247 | var r19_out: u64 = undefined; |
| 248 | var r20_out: u64 = undefined; |
| 249 | var r21_out: u64 = undefined; |
| 250 | return asm volatile ( |
| 251 | \\ callsys |
| 252 | \\ beq $19, 1f |
| 253 | \\ negq $0, $0 |
| 254 | \\1: |
| 255 | : [ret] "={$0}" (-> u64), |
| 256 | [r16_out] "={$16}" (r16_out), |
| 257 | [r17_out] "={$17}" (r17_out), |
| 258 | [r18_out] "={$18}" (r18_out), |
| 259 | [r19_out] "={$19}" (r19_out), |
| 260 | [r20_out] "={$20}" (r20_out), |
| 261 | [r21_out] "={$21}" (r21_out), |
| 262 | : [number] "{$0}" (number), |
| 263 | [arg1] "{$16}" (arg1), |
| 264 | [arg2] "{$17}" (arg2), |
| 265 | [arg3] "{$18}" (arg3), |
| 266 | [arg4] "{$19}" (arg4), |
| 267 | [arg5] "{$20}" (arg5), |
| 268 | [arg6] "{$21}" (arg6), |
| 269 | : .{ |
| 270 | .r1 = true, |
| 271 | .r2 = true, |
| 272 | .r3 = true, |
| 273 | .r4 = true, |
| 274 | .r5 = true, |
| 275 | .r6 = true, |
| 276 | .r7 = true, |
| 277 | .r8 = true, |
| 278 | .r22 = true, |
| 279 | .r23 = true, |
| 280 | .r24 = true, |
| 281 | .r25 = true, |
| 282 | .r27 = true, |
| 283 | .r28 = true, |
| 284 | .memory = true, |
| 285 | }); |
| 286 | } |
| 287 | |
| 288 | pub fn clone() callconv(.naked) u64 { |
| 289 | // __clone(func, stack, flags, arg, ptid, tls, ctid) |
| 290 | // a0, a1, a2, a3, a4, a5, +0 |
| 291 | // |
| 292 | // syscall(SYS_clone, flags, stack, ptid, ctid, tls) |
| 293 | // v0 a0, a1, a2, a3, a4 |
| 294 | asm volatile ( |
| 295 | // a0 = $16, a1 = $17, a2 = $18, a3 = $19, |
| 296 | // a4 = $20, a5 = $21, sp = $30, v0 = $0 |
| 297 | \\ # Save function pointer and argument pointer on new thread stack |
| 298 | \\ ldi $1, -16 |
| 299 | \\ and $17, $1, $17 |
| 300 | \\ lda $17, -16($17) |
| 301 | \\ stq $16, 0($17) |
| 302 | \\ stq $19, 8($17) |
| 303 | \\ |
| 304 | \\ # Shuffle (fn,sp,fl,arg,ptid,tls,ctid) to (fl,sp,ptid,ctid,tls) |
| 305 | \\ mov $18, $16 |
| 306 | \\ mov $20, $18 |
| 307 | \\ ldq $19, 0($30) |
| 308 | \\ mov $21, $20 |
| 309 | \\ |
| 310 | \\ # Actual syscall |
| 311 | \\ ldi $0, 312 # SYS_clone |
| 312 | \\ callsys |
| 313 | \\ beq $19, 1f |
| 314 | \\ negq $0, $0 |
| 315 | \\ ret |
| 316 | \\1: |
| 317 | \\ beq $0, 2f |
| 318 | \\ ret |
| 319 | \\2: |
| 320 | ); |
| 321 | if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( |
| 322 | // ra = $26 |
| 323 | \\ .cfi_undefined $26 |
| 324 | ); |
| 325 | asm volatile ( |
| 326 | // v0 = $0, a0 = $16, ra = $26, sp = $30, fp = $15, pv = $27 |
| 327 | \\ mov 0, $15 |
| 328 | \\ |
| 329 | \\ ldq $27, 0($30) |
| 330 | \\ ldq $16, 8($30) |
| 331 | \\ lda $30, 16($30) |
| 332 | \\ jsr $26, ($27) |
| 333 | \\ |
| 334 | \\ mov $0, $16 |
| 335 | \\ ldi $0, 1 # SYS_exit |
| 336 | \\ callsys |
| 337 | ); |
| 338 | } |
| 339 | |
| 340 | pub fn restore() noreturn { |
| 341 | asm volatile ( |
| 342 | // v0 = $0, a0 = $16, sp = $30 |
| 343 | \\ mov $30, $16 |
| 344 | \\ ldi $0, 103 # SYS_sigreturn |
| 345 | \\ callsys |
| 346 | ); |
| 347 | } |
| 348 | |
| 349 | pub fn restore_rt() noreturn { |
| 350 | asm volatile ( |
| 351 | // v0 = $0, a0 = $16, sp = $30 |
| 352 | \\ mov $30, $16 |
| 353 | \\ ldi $0, 351 # SYS_rt_sigreturn |
| 354 | \\ callsys |
| 355 | ); |
| 356 | } |
| 357 | |
| 358 | pub const VDSO = void; |