aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohannst <johannes.stoelp@gmail.com>2021-02-26 23:19:03 +0100
committerjohannst <johannes.stoelp@gmail.com>2021-02-26 23:19:03 +0100
commit0d881bc974b74dff75c00a3cab5d535cbb2ace46 (patch)
tree35c5892c135d5623879b106e93df4cc235669a8d
parent5fbee6be76c8751c282b45c54b8179ae525e00c1 (diff)
downloadmatcha-threads-0d881bc974b74dff75c00a3cab5d535cbb2ace46.tar.gz
matcha-threads-0d881bc974b74dff75c00a3cab5d535cbb2ace46.zip
added implementation for armv7a
-rw-r--r--.github/workflows/check.yml2
-rw-r--r--Makefile14
-rw-r--r--docker/Dockerfile4
-rw-r--r--lib/Makefile2
-rw-r--r--lib/arch.h2
-rw-r--r--lib/arch/arm/README.md9
-rw-r--r--lib/arch/arm/api.h6
-rw-r--r--lib/arch/arm/init_stack.cc35
-rw-r--r--lib/arch/arm/thread_create.s20
-rw-r--r--lib/arch/arm/yield.s32
10 files changed, 124 insertions, 2 deletions
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 1d7dfa4..e8278d7 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -15,7 +15,7 @@ jobs:
docker/build.sh matcha-box
- name: Run examples
run: |
- for arch in x86_64 arm64; do
+ for arch in x86_64 arm64 arm; do
echo -e "\e[1;32m==> check ARCH=$arch\e0m"
docker run \
--rm \
diff --git a/Makefile b/Makefile
index 0681880..08d4494 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,8 @@ ARCH ?= x86_64
ifeq ($(ARCH),arm64)
PREFIX := aarch64-linux-gnu-
+else ifeq ($(ARCH),arm)
+PREFIX := arm-linux-gnueabi-
endif
CXX := $(PREFIX)g++
@@ -28,6 +30,11 @@ ifeq ($(ARCH),arm64)
-L /usr/aarch64-linux-gnu \
-E LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib \
$<
+else ifeq ($(ARCH),arm)
+ qemu-arm \
+ -L /usr/arm-linux-gnueabi \
+ -E LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib \
+ $<
else
$<
endif
@@ -40,6 +47,13 @@ ifeq ($(ARCH),arm64)
-g 1234 \
$< &
gdb-multiarch -ex 'target remote :1234' -ex 'b main' -ex 'c' $<
+else ifeq ($(ARCH),arm)
+ qemu-arm \
+ -L /usr/arm-linux-gnueabi \
+ -E LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib \
+ -g 1234 \
+ $< &
+ gdb-multiarch -ex 'target remote :1234' -ex 'b main' -ex 'c' $<
else
which cgdb && cgdb --ex 'start' $< \
|| gdb --ex 'start' $<
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 7a41480..703ee7a 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -11,11 +11,13 @@ RUN apt update \
g++ \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
+ gcc-arm-linux-gnueabi \
+ g++-arm-linux-gnueabi \
gdb-multiarch \
qemu-user \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean \
# Remove expensive qemu emulators which are currently not used.
- && rm -f $(find /usr/bin -name 'qemu-*' | grep -v 'qemu-aarch64$')
+ && rm -f $(find /usr/bin -name 'qemu-*' | grep -v 'qemu-aarch64$\|qemu-arm$')
WORKDIR /develop
diff --git a/lib/Makefile b/lib/Makefile
index 24fe7bd..c85d450 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,8 @@ ARCH ?= x86_64
ifeq ($(ARCH),arm64)
PREFIX := aarch64-linux-gnu-
+else ifeq ($(ARCH),arm)
+PREFIX := arm-linux-gnueabi-
endif
AS := $(PREFIX)gcc
diff --git a/lib/arch.h b/lib/arch.h
index bb58576..524d401 100644
--- a/lib/arch.h
+++ b/lib/arch.h
@@ -10,6 +10,8 @@ static_assert(false, "Matcha Threads only supported on Linux!");
# include "arch/x86_64/api.h"
#elif defined(__aarch64__)
# include "arch/arm64/api.h"
+#elif defined(__arm__)
+# include "arch/arm/api.h"
#else
static_assert(false, "Unsupported architecture!");
#endif
diff --git a/lib/arch/arm/README.md b/lib/arch/arm/README.md
new file mode 100644
index 0000000..8631c93
--- /dev/null
+++ b/lib/arch/arm/README.md
@@ -0,0 +1,9 @@
+# Procedure Call Standard ARM64
+
+- Integer/pointer arguments via `r0`-`r3`
+- Integer/pointer return values via `r0`
+- Callee saved registers `r4`-`r11`, `sp`, `lr`, `fp`
+
+## Reference
+- [johannst armv7 notes](https://johannst.github.io/notes/arch/armv7.html)
+
diff --git a/lib/arch/arm/api.h b/lib/arch/arm/api.h
new file mode 100644
index 0000000..c7a688d
--- /dev/null
+++ b/lib/arch/arm/api.h
@@ -0,0 +1,6 @@
+/* Copyright (c) 2021 Johannes Stoelp */
+
+#pragma once
+
+extern "C" void yield(const void* new_stack, void** old_stack);
+void* init_stack(void* stack_ptr, void (*entry)(void*), const void* ctx);
diff --git a/lib/arch/arm/init_stack.cc b/lib/arch/arm/init_stack.cc
new file mode 100644
index 0000000..422be64
--- /dev/null
+++ b/lib/arch/arm/init_stack.cc
@@ -0,0 +1,35 @@
+#include <cassert>
+#include <cstdint> // uintN_t
+
+extern "C" void thread_create();
+
+void* init_stack(void* stack_ptr, void (*entry)(void*), const void* ctx) {
+ static_assert(sizeof(uint32_t) == sizeof(std::uintptr_t), "Pointer must be 32bit!");
+
+ // 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.
+
+ uint32_t* stack = static_cast<uint32_t*>(stack_ptr);
+ // Arguments for `thread_create`.
+ *(--stack) = reinterpret_cast<uint32_t>(ctx);
+ *(--stack) = reinterpret_cast<uint32_t>(entry);
+
+ // Yield epilogue.
+ *(--stack) = reinterpret_cast<uint32_t>(thread_create); // r15 (PC)
+ *(--stack) = static_cast<uint32_t>(0); // r11 (FP)
+
+ // Callee saved registers.
+ *(--stack) = static_cast<uint32_t>(0); // r11
+ *(--stack) = static_cast<uint32_t>(0); // r10
+ *(--stack) = static_cast<uint32_t>(0); // r9
+ *(--stack) = static_cast<uint32_t>(0); // r8
+ *(--stack) = static_cast<uint32_t>(0); // r7
+ *(--stack) = static_cast<uint32_t>(0); // r6
+ *(--stack) = static_cast<uint32_t>(0); // r5
+ *(--stack) = static_cast<uint32_t>(0); // r4
+
+ assert((reinterpret_cast<std::uintptr_t>(stack) & 0x7) == 0); // 8byte aligned
+ return static_cast<void*>(stack);
+}
diff --git a/lib/arch/arm/thread_create.s b/lib/arch/arm/thread_create.s
new file mode 100644
index 0000000..7231c3e
--- /dev/null
+++ b/lib/arch/arm/thread_create.s
@@ -0,0 +1,20 @@
+# Copyright (c) 2021 Johannes Stoelp
+
+ .arch armv7-a
+ .section .text, "ax", %progbits
+
+ # extern "C" void thread_create();
+ .global thread_create
+ .type thread_create, %function
+thread_create:
+ .cfi_startproc
+ ldr r0, [sp, #0x4]
+ ldr r1, [sp]
+
+ blx r1
+
+ # FIXME: no return from thread after user fn finished.
+1:
+ b 1b
+ .cfi_endproc
+ .size thread_create, .-thread_create
diff --git a/lib/arch/arm/yield.s b/lib/arch/arm/yield.s
new file mode 100644
index 0000000..de9d604
--- /dev/null
+++ b/lib/arch/arm/yield.s
@@ -0,0 +1,32 @@
+# Copyright (c) 2021 Johannes Stoelp
+
+ .arch armv7-a
+ .section .text, "ax", %progbits
+
+ # extern "C" void yield(const void* new_stack, void** old_stack);
+ # ^^^^^^^^^ ^^^^^^^^^
+ # x0 x1
+ .global yield
+ .type yield, %function
+yield:
+ .cfi_startproc
+ // prologue
+ push {fp, lr}
+ mov fp, sp
+
+ // push callee saved registers
+ push {r4-r11}
+
+ // arg0: r0 holds new stack
+ // arg1: r1 holds addr to location current stack must be saved
+ mov r2, sp
+ str r2, [r1] // save current stack ptr
+ mov sp, r0 // switch to new stack ptr
+
+ // pop callee saved registers
+ pop {r4-r11}
+
+ // epilogue
+ pop {fp, pc}
+ .cfi_endproc
+ .size yield, .-yield