-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathcoru_platform.c
More file actions
264 lines (236 loc) · 7.96 KB
/
Copy pathcoru_platform.c
File metadata and controls
264 lines (236 loc) · 7.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/*
* coru, platform specific functions
*
* Copyright (c) 2019 Christopher Haster
* Distributed under the MIT license
*/
#include "coru.h"
#include "coru_platform.h"
// Terminate a coroutine, defined in coru.c
//
// Must be called when coroutine's main function returns.
extern void coru_halt(void);
// Platform specific operations
// x86 32-bits
#if defined(__i386__)
// Setup stack
int coru_plat_init(void **psp, uintptr_t **pcanary,
void (*cb)(void*), void *data,
void *buffer, size_t size) {
// check that stack is aligned
CORU_ASSERT((uint32_t)buffer % 4 == 0 && size % 4 == 0);
uint32_t *sp = (uint32_t*)((char*)buffer + size);
// setup stack
sp[-7] = 0; // edi
sp[-6] = 0; // esi
sp[-5] = 0; // ebx
sp[-4] = 0; // ebp
sp[-3] = (uint32_t)cb; // ret to cb(data)
sp[-2] = (uint32_t)coru_halt; // ret to coru_halt()
sp[-1] = (uint32_t)data; // arg to cb(data)
// setup stack pointer and canary
*psp = &sp[-7];
*pcanary = &sp[-size/sizeof(uint32_t)];
return 0;
}
// Swap stacks
uintptr_t coru_plat_yield(void **sp, uintptr_t arg);
__asm__ (
".globl coru_plat_yield \n"
"coru_plat_yield: \n"
"\t mov 8(%esp), %eax \n" // save arg to eax, return this later
"\t mov 4(%esp), %edx \n" // load new esp to edx
"\t push %ebp \n" // push callee saved registers
"\t push %ebx \n"
"\t push %esi \n"
"\t push %edi \n"
"\t xchg %esp, (%edx) \n" // swap stack
"\t pop %edi \n" // pop callee saved registers
"\t pop %esi \n"
"\t pop %ebx \n"
"\t pop %ebp \n"
"\t ret \n" // return eax
);
// x86 64-bits
#elif defined(__amd64__)
// Here we need a prologue to get data to the callback when
// we startup a coroutine.
void coru_plat_prologue(void);
__asm__ (
".globl coru_plat_prologue \n"
"coru_plat_prologue: \n"
"\t mov %r13, %rdi \n" // tail call cb(data)
"\t jmp *%r12 \n"
);
// Setup stack
int coru_plat_init(void **psp, uintptr_t **pcanary,
void (*cb)(void*), void *data,
void *buffer, size_t size) {
// check that stack is aligned
CORU_ASSERT((uint64_t)buffer % 4 == 0 && size % 4 == 0);
uint64_t *sp = (uint64_t*)((char*)buffer + size);
// setup stack
sp[-8] = 0; // rbx
sp[-7] = 0; // rbp
sp[-6] = (uint64_t)cb; // r12
sp[-5] = (uint64_t)data; // r13
sp[-4] = 0; // r14
sp[-3] = 0; // r15
sp[-2] = (uint64_t)coru_plat_prologue; // ret to coru_plat_prologue()
sp[-1] = (uint64_t)coru_halt; // ret to coru_halt()
// setup stack pointer and canary
*psp = &sp[-8];
*pcanary = &sp[-size/sizeof(uint64_t)];
return 0;
}
// Swap stacks
uintptr_t coru_plat_yield(void **sp, uintptr_t arg);
__asm__ (
".globl coru_plat_yield \n"
"coru_plat_yield: \n"
"\t push %r15 \n" // push callee saved registers
"\t push %r14 \n"
"\t push %r13 \n"
"\t push %r12 \n"
"\t push %rbp \n"
"\t push %rbx \n"
"\t xchg %rsp, (%rdi) \n" // swap stack
"\t pop %rbx \n" // pop callee saved registers
"\t pop %rbp \n"
"\t pop %r12 \n"
"\t pop %r13 \n"
"\t pop %r14 \n"
"\t pop %r15 \n"
"\t mov %rsi, %rax \n" // return arg
"\t ret \n"
);
// ARM thumb mode
#elif defined(__thumb__)
// Here we need a prologue to get both data and coru_halt
// into the appropriate registers.
void coru_plat_prologue(void);
__asm__ (
".thumb_func \n"
".global coru_plat_prologue \n"
"coru_plat_prologue: \n"
"\t mov lr, r6 \n" // setup lr to ret to coru_halt()
"\t mov r0, r5 \n" // tail call cb(data)
"\t bx r4 \n"
);
// Setup stack
int coru_plat_init(void **psp, uintptr_t **pcanary,
void (*cb)(void*), void *data,
void *buffer, size_t size) {
// check that stack is aligned
CORU_ASSERT((uint32_t)buffer % 4 == 0 && size % 4 == 0);
uint32_t *sp = (uint32_t*)((char*)buffer + size);
// setup stack
sp[-9] = 0; // r8
sp[-8] = 0; // r9
sp[-7] = 0; // r10
sp[-6] = 0; // r11
sp[-5] = (uint32_t)cb; // r4
sp[-4] = (uint32_t)data; // r5
sp[-3] = (uint32_t)coru_halt; // r6
sp[-2] = 0; // r7
sp[-1] = (uint32_t)coru_plat_prologue; // ret to coru_plat_prologue
// setup stack pointer and canary
*psp = &sp[-9];
*pcanary = &sp[-size/sizeof(uint32_t)];
return 0;
}
// Swap stacks
uintptr_t coru_plat_yield(void **sp, uintptr_t arg);
__asm__ (
".thumb_func \n"
".global coru_plat_yield \n"
"coru_plat_yield: \n"
"\t push {r4,r5,r6,r7,lr} \n" // push callee saved registers
"\t mov r4, r8 \n" // yes we need these moves, thumb1 can
"\t mov r5, r9 \n" // only push r0-r7 at the same time
"\t mov r6, r10 \n"
"\t mov r7, r11 \n"
"\t push {r4,r5,r6,r7} \n"
"\t mov r2, sp \n" // swap stack, takes several instructions
"\t ldr r3, [r0] \n" // here because thumb1 can't load/store sp
"\t str r2, [r0] \n"
"\t mov sp, r3 \n"
"\t mov r0, r1 \n" // return arg
"\t pop {r4,r5,r6,r7} \n" // pop callee saved registers and return
"\t mov r8, r4 \n"
"\t mov r9, r5 \n"
"\t mov r10, r6 \n"
"\t mov r11, r7 \n"
"\t pop {r4,r5,r6,r7,pc} \n"
);
// MIPS
#elif defined(__mips__)
// Here we need a prologue to get both data and coru_halt
// into the appropriate registers.
void coru_plat_prologue(void);
__asm__ (
".globl coru_plat_prologue \n"
"coru_plat_prologue: \n"
"\t move $ra, $s2 \n" // setup $ra to return to core_halt()
"\t addiu $sp, $sp, -4 \n" // tail call cb(data)
"\t move $a0, $s1 \n"
"\t j $s0 \n"
);
int coru_plat_init(void **psp, uintptr_t **pcanary,
void (*cb)(void*), void *data,
void *buffer, size_t size) {
// check that stack is aligned
CORU_ASSERT((uint32_t)buffer % 4 == 0 && size % 4 == 0);
uint32_t *sp = (uint32_t*)((char*)buffer + size);
// setup stack
sp[-10] = (uint32_t)cb; // $s0
sp[-9 ] = (uint32_t)data; // $s1
sp[-8 ] = (uint32_t)coru_halt; // $s2
sp[-7 ] = 0; // $s3
sp[-6 ] = 0; // $s4
sp[-5 ] = 0; // $s5
sp[-4 ] = 0; // $s6
sp[-3 ] = 0; // $s7
sp[-2 ] = 0; // $fp
sp[-1 ] = (uint32_t)coru_plat_prologue; // $ra
// setup stack pointer and canary
*psp = &sp[-10];
*pcanary = &sp[-size/sizeof(uint32_t)];
return 0;
}
// Swap stacks
uintptr_t coru_plat_yield(void **sp, uintptr_t arg);
__asm__ (
".globl coru_plat_yield \n"
"coru_plat_yield: \n"
"\t addiu $sp, $sp, -40 \n" // push callee saved registers
"\t sw $s0, 0($sp) \n"
"\t sw $s1, 4($sp) \n"
"\t sw $s2, 8($sp) \n"
"\t sw $s3, 12($sp) \n"
"\t sw $s4, 16($sp) \n"
"\t sw $s5, 20($sp) \n"
"\t sw $s6, 24($sp) \n"
"\t sw $s7, 28($sp) \n"
"\t sw $fp, 32($sp) \n"
"\t sw $ra, 36($sp) \n"
"\t lw $t0, ($a0) \n" // swap stack
"\t sw $sp, ($a0) \n"
"\t move $sp, $t0 \n"
"\t lw $s0, 0($sp) \n" // pop callee saved registers
"\t lw $s1, 4($sp) \n"
"\t lw $s2, 8($sp) \n"
"\t lw $s3, 12($sp) \n"
"\t lw $s4, 16($sp) \n"
"\t lw $s5, 20($sp) \n"
"\t lw $s6, 24($sp) \n"
"\t lw $s7, 28($sp) \n"
"\t lw $fp, 32($sp) \n"
"\t lw $ra, 36($sp) \n"
"\t addiu $sp, $sp, 40 \n"
"\t move $v0, $a1 \n" // return arg
"\t j $ra \n"
);
#else
#error "Unknown platform! Please update coru_platform.c"
#endif