1pub const supported = switch (builtin.cpu.arch) {
2 .aarch64, .riscv64, .x86_64 => true,
3 else => false,
4};
5
6/// Stores the cpu state of an inactive fiber.
7pub const Context = switch (builtin.cpu.arch) {
8 .aarch64 => extern struct {
9 sp: u64,
10 fp: u64,
11 pc: u64,
12 },
13 .riscv64 => extern struct {
14 sp: u64,
15 fp: u64,
16 pc: u64,
17 },
18 .x86_64 => extern struct {
19 rsp: u64,
20 rbp: u64,
21 rip: u64,
22 },
23 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),
24};
25
26pub const Switch = extern struct { old: *Context, new: *Context };
27
28/// Fills `s.old` with the current cpu state, and restores the cpu state stored in `s.new`.
29pub inline fn contextSwitch(s: *const Switch) *const Switch {
30 return switch (builtin.cpu.arch) {
31 .aarch64 => asm volatile (
32 \\ ldp x0, x2, [x1]
33 \\ ldr x3, [x2, #16]
34 \\ mov x4, sp
35 \\ stp x4, fp, [x0]
36 \\ adr x5, 0f
37 \\ ldp x4, fp, [x2]
38 \\ str x5, [x0, #16]
39 \\ mov sp, x4
40 \\ br x3
41 \\0:
42 : [received_message] "={x1}" (-> *const Switch),
43 : [message_to_send] "{x1}" (s),
44 : .{
45 .x0 = true,
46 .x1 = true,
47 .x2 = true,
48 .x3 = true,
49 .x4 = true,
50 .x5 = true,
51 .x6 = true,
52 .x7 = true,
53 .x8 = true,
54 .x9 = true,
55 .x10 = true,
56 .x11 = true,
57 .x12 = true,
58 .x13 = true,
59 .x14 = true,
60 .x15 = true,
61 .x16 = true,
62 .x17 = true,
63 .x19 = true,
64 .x20 = true,
65 .x21 = true,
66 .x22 = true,
67 .x23 = true,
68 .x24 = true,
69 .x25 = true,
70 .x26 = true,
71 .x27 = true,
72 .x28 = true,
73 .x30 = true,
74 .z0 = true,
75 .z1 = true,
76 .z2 = true,
77 .z3 = true,
78 .z4 = true,
79 .z5 = true,
80 .z6 = true,
81 .z7 = true,
82 .z8 = true,
83 .z9 = true,
84 .z10 = true,
85 .z11 = true,
86 .z12 = true,
87 .z13 = true,
88 .z14 = true,
89 .z15 = true,
90 .z16 = true,
91 .z17 = true,
92 .z18 = true,
93 .z19 = true,
94 .z20 = true,
95 .z21 = true,
96 .z22 = true,
97 .z23 = true,
98 .z24 = true,
99 .z25 = true,
100 .z26 = true,
101 .z27 = true,
102 .z28 = true,
103 .z29 = true,
104 .z30 = true,
105 .z31 = true,
106 .p0 = true,
107 .p1 = true,
108 .p2 = true,
109 .p3 = true,
110 .p4 = true,
111 .p5 = true,
112 .p6 = true,
113 .p7 = true,
114 .p8 = true,
115 .p9 = true,
116 .p10 = true,
117 .p11 = true,
118 .p12 = true,
119 .p13 = true,
120 .p14 = true,
121 .p15 = true,
122 .fpcr = true,
123 .fpsr = true,
124 .ffr = true,
125 .memory = true,
126 }),
127 .riscv64 => asm volatile (
128 \\ ld a0, 0(a1)
129 \\ ld a2, 8(a1)
130 \\ lla a3, 0f
131 \\ sd sp, 0(a0)
132 \\ sd fp, 8(a0)
133 \\ sd a3, 16(a0)
134 \\ ld sp, 0(a2)
135 \\ ld fp, 8(a2)
136 \\ ld a3, 16(a2)
137 \\ jr a3
138 \\0:
139 : [received_message] "={a1}" (-> *const Switch),
140 : [message_to_send] "{a1}" (s),
141 : .{
142 .x1 = true,
143 .x3 = true,
144 .x4 = true,
145 .x5 = true,
146 .x6 = true,
147 .x7 = true,
148 .x9 = true,
149 .x10 = true,
150 .x11 = true,
151 .x12 = true,
152 .x13 = true,
153 .x14 = true,
154 .x15 = true,
155 .x16 = true,
156 .x17 = true,
157 .x18 = true,
158 .x19 = true,
159 .x20 = true,
160 .x21 = true,
161 .x22 = true,
162 .x23 = true,
163 .x24 = true,
164 .x25 = true,
165 .x26 = true,
166 .x27 = true,
167 .x28 = true,
168 .x29 = true,
169 .x30 = true,
170 .x31 = true,
171 .f0 = true,
172 .f1 = true,
173 .f2 = true,
174 .f3 = true,
175 .f4 = true,
176 .f5 = true,
177 .f6 = true,
178 .f7 = true,
179 .f8 = true,
180 .f9 = true,
181 .f10 = true,
182 .f11 = true,
183 .f12 = true,
184 .f13 = true,
185 .f14 = true,
186 .f15 = true,
187 .f16 = true,
188 .f17 = true,
189 .f18 = true,
190 .f19 = true,
191 .f20 = true,
192 .f21 = true,
193 .f22 = true,
194 .f23 = true,
195 .f24 = true,
196 .f25 = true,
197 .f26 = true,
198 .f27 = true,
199 .f28 = true,
200 .f29 = true,
201 .f30 = true,
202 .f31 = true,
203 .v0 = true,
204 .v1 = true,
205 .v2 = true,
206 .v3 = true,
207 .v4 = true,
208 .v5 = true,
209 .v6 = true,
210 .v7 = true,
211 .v8 = true,
212 .v9 = true,
213 .v10 = true,
214 .v11 = true,
215 .v12 = true,
216 .v13 = true,
217 .v14 = true,
218 .v15 = true,
219 .v16 = true,
220 .v17 = true,
221 .v18 = true,
222 .v19 = true,
223 .v20 = true,
224 .v21 = true,
225 .v22 = true,
226 .v23 = true,
227 .v24 = true,
228 .v25 = true,
229 .v26 = true,
230 .v27 = true,
231 .v28 = true,
232 .v29 = true,
233 .v30 = true,
234 .v31 = true,
235 .vtype = true,
236 .vl = true,
237 .vxsat = true,
238 .vxrm = true,
239 .vcsr = true,
240 .fflags = true,
241 .frm = true,
242 .memory = true,
243 }),
244 .x86_64 => asm volatile (
245 \\ movq 0(%%rsi), %%rax
246 \\ movq 8(%%rsi), %%rcx
247 \\ leaq 0f(%%rip), %%rdx
248 \\ movq %%rsp, 0(%%rax)
249 \\ movq %%rbp, 8(%%rax)
250 \\ movq %%rdx, 16(%%rax)
251 \\ movq 0(%%rcx), %%rsp
252 \\ movq 8(%%rcx), %%rbp
253 \\ jmpq *16(%%rcx)
254 \\0:
255 : [received_message] "={rsi}" (-> *const Switch),
256 : [message_to_send] "{rsi}" (s),
257 : .{
258 .rax = true,
259 .rcx = true,
260 .rdx = true,
261 .rbx = true,
262 .rsi = true,
263 .rdi = true,
264 .r8 = true,
265 .r9 = true,
266 .r10 = true,
267 .r11 = true,
268 .r12 = true,
269 .r13 = true,
270 .r14 = true,
271 .r15 = true,
272 .mm0 = true,
273 .mm1 = true,
274 .mm2 = true,
275 .mm3 = true,
276 .mm4 = true,
277 .mm5 = true,
278 .mm6 = true,
279 .mm7 = true,
280 .zmm0 = true,
281 .zmm1 = true,
282 .zmm2 = true,
283 .zmm3 = true,
284 .zmm4 = true,
285 .zmm5 = true,
286 .zmm6 = true,
287 .zmm7 = true,
288 .zmm8 = true,
289 .zmm9 = true,
290 .zmm10 = true,
291 .zmm11 = true,
292 .zmm12 = true,
293 .zmm13 = true,
294 .zmm14 = true,
295 .zmm15 = true,
296 .zmm16 = true,
297 .zmm17 = true,
298 .zmm18 = true,
299 .zmm19 = true,
300 .zmm20 = true,
301 .zmm21 = true,
302 .zmm22 = true,
303 .zmm23 = true,
304 .zmm24 = true,
305 .zmm25 = true,
306 .zmm26 = true,
307 .zmm27 = true,
308 .zmm28 = true,
309 .zmm29 = true,
310 .zmm30 = true,
311 .zmm31 = true,
312 .fpsr = true,
313 .fpcr = true,
314 .mxcsr = true,
315 .rflags = true,
316 .dirflag = true,
317 .memory = true,
318 }),
319 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),
320 };
321}
322
323const builtin = @import("builtin");