aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile33
-rw-r--r--lib/Makefile14
-rw-r--r--lib/arch.h2
-rw-r--r--lib/arch/arm64/api.h6
-rw-r--r--lib/arch/arm64/init_stack.cc37
-rw-r--r--lib/arch/arm64/thread_create.s20
-rw-r--r--lib/arch/arm64/yield.s42
7 files changed, 144 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index b3665cc..47c7c90 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,16 @@
# Copyright (c) 2020 Johannes Stoelp
-CXX := g++
+ARCH ?= x86_64
+
+ifeq ($(ARCH),arm64)
+PREFIX := aarch64-linux-gnu-
+endif
+
+CXX := $(PREFIX)g++
CXXFLAGS := -g -O0 -Wall -Wextra -I.
lib/libmatcha.a:
- make -C lib
+ make -C lib ARCH=$(ARCH)
%.o: %.cc
$(CXX) -c -o $@ $^ $(CXXFLAGS)
@@ -13,12 +19,29 @@ fmt:
fd --type f '.+\.h$$|.+\.cc$$' --exec clang-format -i {}
example/demo1: example/demo1.o lib/libmatcha.a
- $(CXX) -o $@ $^
+ $(CXX) -o $@ $^ $(LDFLAGS)
+ifeq ($(ARCH),arm64)
+ qemu-aarch64 \
+ -L /usr/aarch64-linux-gnu \
+ -E LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib \
+ example/demo1
+else
+ example/demo1
+endif
gdb: example/demo1
+ifeq ($(ARCH),arm64)
+ qemu-aarch64 \
+ -L /usr/aarch64-linux-gnu \
+ -E LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib \
+ -g 1234 \
+ example/demo1 &
+ gdb-multiarch -ex 'target remote :1234' -ex 'b main' -ex 'c' example/demo1
+else
which cgdb && cgdb -x util.gdb -ex 'start' example/demo1 \
|| gdb -x util.gdb -ex 'start' example/demo1
+endif
clean:
- rm -f example/demo1
- rm -f **/*.o **/lib*.a
+ make -C lib clean
+ rm -f example/demo1 example/demo1.o
diff --git a/lib/Makefile b/lib/Makefile
index 78b051e..c880346 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,12 +1,16 @@
# Copyright (c) 2020 Johannes Stoelp
-AS := gcc
+ARCH ?= x86_64
+
+ifeq ($(ARCH),arm64)
+PREFIX := aarch64-linux-gnu-
+endif
+
+AS := $(PREFIX)gcc
ASFLAGS := -g -O0
-CXX := g++
+CXX := $(PREFIX)g++
CXXFLAGS := -g -O0 -Wall -Wextra -I.
-AR := ar
-
-ARCH := x86_64
+AR := $(PREFIX)ar
libmatcha.a: thread.o executor.o \
thread.h executor.h \
diff --git a/lib/arch.h b/lib/arch.h
index fc86cad..9604be8 100644
--- a/lib/arch.h
+++ b/lib/arch.h
@@ -8,6 +8,8 @@ static_assert(false, "Matcha Threads only supported on Linux!");
#if defined(__x86_64__) || defined(__amd64__)
# include "arch/x86_64/api.h"
+#elif defined(__aarch64__)
+# include "arch/arm64/api.h"
#else
static_assert(false, "Matcha Threads only supported on x86_64!");
#endif
diff --git a/lib/arch/arm64/api.h b/lib/arch/arm64/api.h
new file mode 100644
index 0000000..b2babc9
--- /dev/null
+++ b/lib/arch/arm64/api.h
@@ -0,0 +1,6 @@
+/* Copyright (c) 2020 Johannes Stoelp */
+
+#pragma once
+
+extern "C" void yield(const void* new_stack, void* const* old_stack);
+void* init_stack(void* stack_ptr, void (*entry)(void*), void* ctx);
diff --git a/lib/arch/arm64/init_stack.cc b/lib/arch/arm64/init_stack.cc
new file mode 100644
index 0000000..b28d957
--- /dev/null
+++ b/lib/arch/arm64/init_stack.cc
@@ -0,0 +1,37 @@
+#include <cassert>
+#include <cstdint> // uintN_t
+
+extern "C" void thread_create();
+
+void* init_stack(void* stack_ptr, void (*entry)(void*), void* ctx) {
+ static_assert(sizeof(uint64_t) == sizeof(std::uintptr_t), "Pointer must be 64bit!");
+
+ // Setup initial stack frame which will be popped when yielding
+ // first time into the thread.
+ // Basic idea is to yield into Thread::entry() function which will
+ // then call the user function.
+
+ uint64_t* stack = static_cast<uint64_t*>(stack_ptr);
+ // Arguments for `thread_create`.
+ *(--stack) = reinterpret_cast<uint64_t>(ctx);
+ *(--stack) = reinterpret_cast<uint64_t>(entry);
+
+ // Yield epilogue.
+ *(--stack) = reinterpret_cast<uint64_t>(thread_create); // x30 (LR)
+ *(--stack) = static_cast<uint64_t>(0); // x29 (FP)
+
+ // Callee saved registers.
+ *(--stack) = static_cast<uint64_t>(0); // x28
+ *(--stack) = static_cast<uint64_t>(0); // x27
+ *(--stack) = static_cast<uint64_t>(0); // x26
+ *(--stack) = static_cast<uint64_t>(0); // x25
+ *(--stack) = static_cast<uint64_t>(0); // x24
+ *(--stack) = static_cast<uint64_t>(0); // x23
+ *(--stack) = static_cast<uint64_t>(0); // x22
+ *(--stack) = static_cast<uint64_t>(0); // x21
+ *(--stack) = static_cast<uint64_t>(0); // x20
+ *(--stack) = static_cast<uint64_t>(0); // x19
+
+ assert((reinterpret_cast<std::uintptr_t>(stack) & 0xf) == 0); // 16byte aligned
+ return static_cast<void*>(stack);
+}
diff --git a/lib/arch/arm64/thread_create.s b/lib/arch/arm64/thread_create.s
new file mode 100644
index 0000000..dc6fae2
--- /dev/null
+++ b/lib/arch/arm64/thread_create.s
@@ -0,0 +1,20 @@
+# Copyright (c) 2020 Johannes Stoelp
+
+ .arch armv8-a
+ .section .text, "ax", @progbits
+
+ # extern "C" void thread_create();
+ .global thread_create
+ .type thread_create, @function
+thread_create:
+ .cfi_startproc
+ ldr x0, [sp, 0x8]
+ ldr x1, [sp]
+
+ blr x1
+
+ # FIXME: no return from thread after user fn finished.
+1:
+ b 1b
+ .cfi_endproc
+ .size thread_create, .-thread_create
diff --git a/lib/arch/arm64/yield.s b/lib/arch/arm64/yield.s
new file mode 100644
index 0000000..63a4051
--- /dev/null
+++ b/lib/arch/arm64/yield.s
@@ -0,0 +1,42 @@
+# Copyright (c) 2020 Johannes Stoelp
+
+ .arch armv8-a
+ .section .text, "ax", @progbits
+
+ # extern "C" void yield(const void* new_stack, void* const* old_stack);
+ # ^^^^^^^^^ ^^^^^^^^^
+ # rdi rsi
+ .global yield
+ .type yield, @function
+yield:
+ .cfi_startproc
+ // prologue
+ stp x29, x30, [sp, -16]!
+ mov x29, sp
+
+ // push callee saved registers
+ stp x27, x28, [sp, -16]!
+ stp x25, x26, [sp, -16]!
+ stp x23, x24, [sp, -16]!
+ stp x21, x22, [sp, -16]!
+ stp x19, x20, [sp, -16]!
+
+ // arg0: x0 holds new stack
+ // arg1: x1 holds addr to location current stack must be saved
+ mov x2, sp
+ str x2, [x1] // save current stack ptr
+ mov sp, x0 // switch to new stack ptr
+
+ // pop callee saved registers
+ ldp x19, x20, [sp], 16
+ ldp x21, x22, [sp], 16
+ ldp x23, x24, [sp], 16
+ ldp x25, x26, [sp], 16
+ ldp x27, x28, [sp], 16
+
+ // epilogue
+ ldp x29, x30, [sp], 16
+
+ ret
+ .cfi_endproc
+ .size yield, .-yield