summaryrefslogtreecommitdiff
path: root/coroutine
diff options
context:
space:
mode:
Diffstat (limited to 'coroutine')
-rw-r--r--coroutine/arm64/Context.S79
-rw-r--r--coroutine/arm64/Context.asm81
-rw-r--r--coroutine/arm64/Context.h25
-rw-r--r--coroutine/ppc64le/Context.S21
-rw-r--r--coroutine/ppc64le/Context.h2
-rw-r--r--coroutine/win32/Context.h1
-rw-r--r--coroutine/win64/Context.h1
7 files changed, 182 insertions, 28 deletions
diff --git a/coroutine/arm64/Context.S b/coroutine/arm64/Context.S
index 11f6aa0810..ce219c0c4d 100644
--- a/coroutine/arm64/Context.S
+++ b/coroutine/arm64/Context.S
@@ -21,6 +21,13 @@
# error "-mbranch-protection flag specified b-key but Context.S does not support this"
#endif
+#if defined(_WIN32)
+## Add more space for certain TEB values on each stack
+#define TEB_OFFSET 0x20
+#else
+#define TEB_OFFSET 0x00
+#endif
+
## NOTE(PAC): Use we HINT mnemonics instead of PAC mnemonics to
## keep compatibility with those assemblers that don't support PAC.
##
@@ -39,19 +46,34 @@ PREFIXED_SYMBOL(coroutine_transfer):
hint #34
#endif
# Make space on the stack for caller registers
- sub sp, sp, 0xa0
+ sub sp, sp, 0xa0 + TEB_OFFSET
# Save caller registers
- stp d8, d9, [sp, 0x00]
- stp d10, d11, [sp, 0x10]
- stp d12, d13, [sp, 0x20]
- stp d14, d15, [sp, 0x30]
- stp x19, x20, [sp, 0x40]
- stp x21, x22, [sp, 0x50]
- stp x23, x24, [sp, 0x60]
- stp x25, x26, [sp, 0x70]
- stp x27, x28, [sp, 0x80]
- stp x29, x30, [sp, 0x90]
+ stp d8, d9, [sp, 0x00 + TEB_OFFSET]
+ stp d10, d11, [sp, 0x10 + TEB_OFFSET]
+ stp d12, d13, [sp, 0x20 + TEB_OFFSET]
+ stp d14, d15, [sp, 0x30 + TEB_OFFSET]
+ stp x19, x20, [sp, 0x40 + TEB_OFFSET]
+ stp x21, x22, [sp, 0x50 + TEB_OFFSET]
+ stp x23, x24, [sp, 0x60 + TEB_OFFSET]
+ stp x25, x26, [sp, 0x70 + TEB_OFFSET]
+ stp x27, x28, [sp, 0x80 + TEB_OFFSET]
+ stp x29, x30, [sp, 0x90 + TEB_OFFSET]
+
+#if defined(_WIN32)
+ # Save certain values from Thread Environment Block (TEB)
+ # x18 points to the TEB on Windows
+ # Read TeStackBase and TeStackLimit at ksarm64.h from TEB
+ ldp x5, x6, [x18, #0x08]
+ # Save them
+ stp x5, x6, [sp, #0x00]
+ # Read TeDeallocationStack at ksarm64.h from TEB
+ ldr x5, [x18, #0x1478]
+ # Read TeFiberData at ksarm64.h from TEB
+ ldr x6, [x18, #0x20]
+ # Save current fiber data and deallocation stack
+ stp x5, x6, [sp, #0x10]
+#endif
# Save stack pointer to x0 (first argument)
mov x2, sp
@@ -61,20 +83,33 @@ PREFIXED_SYMBOL(coroutine_transfer):
ldr x3, [x1, 0]
mov sp, x3
+#if defined(_WIN32)
+ # Restore stack base and limit
+ ldp x5, x6, [sp, #0x00]
+ # Write TeStackBase and TeStackLimit at ksarm64.h to TEB
+ stp x5, x6, [x18, #0x08]
+ # Restore fiber data and deallocation stack
+ ldp x5, x6, [sp, #0x10]
+ # Write TeDeallocationStack at ksarm64.h to TEB
+ str x5, [x18, #0x1478]
+ # Write TeFiberData at ksarm64.h to TEB
+ str x6, [x18, #0x20]
+#endif
+
# Restore caller registers
- ldp d8, d9, [sp, 0x00]
- ldp d10, d11, [sp, 0x10]
- ldp d12, d13, [sp, 0x20]
- ldp d14, d15, [sp, 0x30]
- ldp x19, x20, [sp, 0x40]
- ldp x21, x22, [sp, 0x50]
- ldp x23, x24, [sp, 0x60]
- ldp x25, x26, [sp, 0x70]
- ldp x27, x28, [sp, 0x80]
- ldp x29, x30, [sp, 0x90]
+ ldp d8, d9, [sp, 0x00 + TEB_OFFSET]
+ ldp d10, d11, [sp, 0x10 + TEB_OFFSET]
+ ldp d12, d13, [sp, 0x20 + TEB_OFFSET]
+ ldp d14, d15, [sp, 0x30 + TEB_OFFSET]
+ ldp x19, x20, [sp, 0x40 + TEB_OFFSET]
+ ldp x21, x22, [sp, 0x50 + TEB_OFFSET]
+ ldp x23, x24, [sp, 0x60 + TEB_OFFSET]
+ ldp x25, x26, [sp, 0x70 + TEB_OFFSET]
+ ldp x27, x28, [sp, 0x80 + TEB_OFFSET]
+ ldp x29, x30, [sp, 0x90 + TEB_OFFSET]
# Pop stack frame
- add sp, sp, 0xa0
+ add sp, sp, 0xa0 + TEB_OFFSET
#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0)
# autiasp: Authenticate x30 (LR) with SP and key A
diff --git a/coroutine/arm64/Context.asm b/coroutine/arm64/Context.asm
new file mode 100644
index 0000000000..866fa628e7
--- /dev/null
+++ b/coroutine/arm64/Context.asm
@@ -0,0 +1,81 @@
+ TTL coroutine/arm64/Context.asm
+
+ AREA |.drectve|, DRECTVE
+
+ EXPORT |coroutine_transfer|
+
+ AREA |.text$mn|, CODE, ARM64
+
+;; Add more space for certain TEB values on each stack
+TEB_OFFSET EQU 0x20
+
+;; Incomplete implementation
+coroutine_transfer PROC
+ ; Make space on the stack for caller registers
+ sub sp, sp, 0xa0 + TEB_OFFSET
+
+ ; Save caller registers
+ stp d8, d9, [sp, 0x00 + TEB_OFFSET]
+ stp d10, d11, [sp, 0x10 + TEB_OFFSET]
+ stp d12, d13, [sp, 0x20 + TEB_OFFSET]
+ stp d14, d15, [sp, 0x30 + TEB_OFFSET]
+ stp x19, x20, [sp, 0x40 + TEB_OFFSET]
+ stp x21, x22, [sp, 0x50 + TEB_OFFSET]
+ stp x23, x24, [sp, 0x60 + TEB_OFFSET]
+ stp x25, x26, [sp, 0x70 + TEB_OFFSET]
+ stp x27, x28, [sp, 0x80 + TEB_OFFSET]
+ stp x29, x30, [sp, 0x90 + TEB_OFFSET]
+
+ ;; Save certain values from Thread Environment Block (TEB) x18
+ ;; points to the TEB on Windows
+ ;; Read TeStackBase and TeStackLimit at ksarm64.h from TEB
+ ldp x5, x6, [x18, #0x08]
+ ;; Save them
+ stp x5, x6, [sp, #0x00]
+ ;; Read TeDeallocationStack at ksarm64.h from TEB
+ ldr x5, [x18, #0x1478]
+ ;; Read TeFiberData at ksarm64.h from TEB
+ ldr x6, [x18, #0x20]
+ ;; Save current fiber data and deallocation stack
+ stp x5, x6, [sp, #0x10]
+
+ ; Save stack pointer to x0 (first argument)
+ mov x2, sp
+ str x2, [x0, 0]
+
+ ; Load stack pointer from x1 (second argument)
+ ldr x3, [x1, 0]
+ mov sp, x3
+
+ ;; Restore stack base and limit
+ ldp x5, x6, [sp, #0x00]
+ ;; Write TeStackBase and TeStackLimit at ksarm64.h to TEB
+ stp x5, x6, [x18, #0x08]
+ ;; Restore fiber data and deallocation stack
+ ldp x5, x6, [sp, #0x10]
+ ;; Write TeDeallocationStack at ksarm64.h to TEB
+ str x5, [x18, #0x1478]
+ ;; Write TeFiberData at ksarm64.h to TEB
+ str x6, [x18, #0x20]
+
+ ; Restore caller registers
+ ldp d8, d9, [sp, 0x00 + TEB_OFFSET]
+ ldp d10, d11, [sp, 0x10 + TEB_OFFSET]
+ ldp d12, d13, [sp, 0x20 + TEB_OFFSET]
+ ldp d14, d15, [sp, 0x30 + TEB_OFFSET]
+ ldp x19, x20, [sp, 0x40 + TEB_OFFSET]
+ ldp x21, x22, [sp, 0x50 + TEB_OFFSET]
+ ldp x23, x24, [sp, 0x60 + TEB_OFFSET]
+ ldp x25, x26, [sp, 0x70 + TEB_OFFSET]
+ ldp x27, x28, [sp, 0x80 + TEB_OFFSET]
+ ldp x29, x30, [sp, 0x90 + TEB_OFFSET]
+
+ ; Pop stack frame
+ add sp, sp, 0xa0 + TEB_OFFSET
+
+ ; Jump to return address (in x30)
+ ret
+
+ endp
+
+ end
diff --git a/coroutine/arm64/Context.h b/coroutine/arm64/Context.h
index b6ca5b8dde..468e4155b2 100644
--- a/coroutine/arm64/Context.h
+++ b/coroutine/arm64/Context.h
@@ -15,9 +15,21 @@
#include <stdint.h>
#include <string.h>
+#if defined __GNUC__
#define COROUTINE __attribute__((noreturn)) void
+#define COROUTINE_DECL COROUTINE
+#elif defined _MSC_VER
+#define COROUTINE __declspec(noreturn) void
+#define COROUTINE_DECL void
+#endif
-enum {COROUTINE_REGISTERS = 0xa0 / 8};
+#if defined(_WIN32)
+#define TEB_OFFSET 0x20
+#else
+#define TEB_OFFSET 0x00
+#endif
+
+enum {COROUTINE_REGISTERS = (0xa0 + TEB_OFFSET) / 8};
#if defined(__SANITIZE_ADDRESS__)
#define COROUTINE_SANITIZE_ADDRESS
@@ -44,7 +56,7 @@ struct coroutine_context
#endif
};
-typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
+typedef COROUTINE_DECL(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
static inline void coroutine_initialize_main(struct coroutine_context * context) {
context->stack_pointer = NULL;
@@ -87,7 +99,14 @@ static inline void coroutine_initialize(
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
void *addr = (void*)(uintptr_t)start;
- context->stack_pointer[0x98 / 8] = ptrauth_sign_instruction_addr(addr, (void*)top);
+ context->stack_pointer[(0x98 + TEB_OFFSET) / 8] = ptrauth_sign_instruction_addr(addr, (void*)top);
+#if defined(_WIN32)
+ // save top address of stack as base in TEB
+ context->stack_pointer[0x00 / 8] = (char*)stack + size;
+ // save botton address of stack as limit and deallocation stack in TEB
+ context->stack_pointer[0x08 / 8] = stack;
+ context->stack_pointer[0x10 / 8] = stack;
+#endif
}
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
diff --git a/coroutine/ppc64le/Context.S b/coroutine/ppc64le/Context.S
index cccd002be5..819264c245 100644
--- a/coroutine/ppc64le/Context.S
+++ b/coroutine/ppc64le/Context.S
@@ -1,13 +1,20 @@
#define TOKEN_PASTE(x,y) x##y
+.abiversion 2
.text
.align 2
.globl PREFIXED_SYMBOL(coroutine_transfer)
.type PREFIXED_SYMBOL(coroutine_transfer), @function
PREFIXED_SYMBOL(coroutine_transfer):
+ # Global entry: set up TOC pointer (r2) from r12.
+ # Required by ELFv2 ABI when this function is reached via the PLT.
+ addis 2, 12, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@ha
+ addi 2, 2, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@l
+ .localentry PREFIXED_SYMBOL(coroutine_transfer), .-PREFIXED_SYMBOL(coroutine_transfer)
+
# Make space on the stack for caller registers
- addi 1,1,-152
+ addi 1,1,-160
# Save caller registers
std 14,0(1)
@@ -33,6 +40,10 @@ PREFIXED_SYMBOL(coroutine_transfer):
mflr 0
std 0,144(1)
+ # Save caller special register
+ mfcr 0
+ std 0, 152(1)
+
# Save stack pointer to first argument
std 1,0(3)
@@ -63,8 +74,14 @@ PREFIXED_SYMBOL(coroutine_transfer):
ld 0,144(1)
mtlr 0
+ # Load special registers
+ ld 0,152(1)
+ # Restore cr register cr2, cr3 and cr4 (field index 3,4,5)
+ # (field index is 1-based, field 1 = cr0) using a mask (32|16|8 = 56)
+ mtcrf 56,0
+
# Pop stack frame
- addi 1,1,152
+ addi 1,1,160
# Jump to return address
blr
diff --git a/coroutine/ppc64le/Context.h b/coroutine/ppc64le/Context.h
index fbfaa2ee63..63ea9f19ff 100644
--- a/coroutine/ppc64le/Context.h
+++ b/coroutine/ppc64le/Context.h
@@ -12,7 +12,7 @@
enum {
COROUTINE_REGISTERS =
- 19 /* 18 general purpose registers (r14-r31) and 1 return address */
+ 20 /* 18 general purpose registers (r14-r31), 1 special register (cr) and 1 return address */
+ 4 /* space for fiber_entry() to store the link register */
};
diff --git a/coroutine/win32/Context.h b/coroutine/win32/Context.h
index 243ae5a43b..c1c8fbcd13 100644
--- a/coroutine/win32/Context.h
+++ b/coroutine/win32/Context.h
@@ -16,6 +16,7 @@
#include <string.h>
#define COROUTINE __declspec(noreturn) void __fastcall
+#define COROUTINE_DECL void __fastcall
#define COROUTINE_LIMITED_ADDRESS_SPACE
/* This doesn't include thread information block */
diff --git a/coroutine/win64/Context.h b/coroutine/win64/Context.h
index c5cab729f8..23b21b5c1c 100644
--- a/coroutine/win64/Context.h
+++ b/coroutine/win64/Context.h
@@ -16,6 +16,7 @@
#include <string.h>
#define COROUTINE __declspec(noreturn) void
+#define COROUTINE_DECL void
enum {
COROUTINE_REGISTERS = 8,