summaryrefslogtreecommitdiff
path: root/coroutine/+x86_64.s
diff options
context:
space:
mode:
Diffstat (limited to 'coroutine/+x86_64.s')
-rw-r--r--coroutine/+x86_64.s87
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
+