diff options
Diffstat (limited to 'coroutine/+x86_64.s')
-rw-r--r-- | coroutine/+x86_64.s | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/coroutine/+x86_64.s b/coroutine/+x86_64.s new file mode 100644 index 0000000..aaa69e0 --- /dev/null +++ b/coroutine/+x86_64.s @@ -0,0 +1,87 @@ +.global couroutine._start +.type couroutine._start,@function + +.bss +.align 8 +coro_state: .quad 0 +caller_state: .quad 0 + +.macro savestate to +mov %rsp,(\to) +mov %rbp,8(\to) +mov %r12,16(\to) +mov %r13,24(\to) +mov %r14,32(\to) +mov %r15,40(\to) +mov %rbx,48(\to) +.endm + +.macro loadstate from +mov (\from),%rsp +mov 8(\from),%rbp +mov 16(\from),%r12 +mov 24(\from),%r13 +mov 32(\from),%r14 +mov 40(\from),%r15 +mov 48(\from),%rbx +.endm + +.text +.global coroutine.arch_init +.type couroutine.arch_init,@function +coroutine.arch_init: + movabs $coro_state,%rax + push (%rax) + mov %rsi,(%rax) + + movabs $caller_state,%rax + push (%rax) + sub $56,%rsp + mov %rsp,(%rax) + savestate %rsp + + // Initialize stack pointer to supplied stack. + add %rcx,%rdx + mov %rdx,%rsp + mov %rdx,%rbp + + // rdi contains function to be called by _start. + call coroutine._start + +.global coroutine.arch_resume +.type coroutine.arch_resume,@function +coroutine.arch_resume: + movabs $coro_state,%rax + push (%rax) + mov %rdi,(%rax) + + movabs $caller_state,%rax + push (%rax) + sub $56,%rsp + mov %rsp,(%rax) + savestate %rsp + + loadstate %rdi + mov %rsi,%rax + ret + +.global coroutine.arch_suspend +.type coroutine.arch_suspend,@function +coroutine.arch_suspend: + movabs $coro_state,%rcx + mov (%rcx),%rax + savestate %rax + + movabs $caller_state,%rdx + mov (%rdx),%rax + loadstate %rax + + // The stack pointer (and other callee-saved registers) is now set back to + // the original call to arch_resume. Restore the original coro_state and + // caller_state values and return the value supplied as argument. + add $56,%rsp + pop (%rdx) + pop (%rcx) + mov %rdi,%rax + ret + |