From 737a8cdf201355aa1a4d7f5531808be1ea128996 Mon Sep 17 00:00:00 2001 From: M1ralai Date: Sun, 18 Oct 2026 03:31:35 +0300 Subject: [PATCH] Add initial Darwin ARM64 context switching support --- arm64-ucontext.h | 30 +++++++++++++++++++ asm.S | 77 +++++++++++++++++++++++++++++++++++++++++++++++- context.c | 36 +++++++++++++++++++++- taskimpl.h | 2 ++ 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 arm64-ucontext.h diff --git a/arm64-ucontext.h b/arm64-ucontext.h new file mode 100644 index 0000000..7a3831a --- /dev/null +++ b/arm64-ucontext.h @@ -0,0 +1,30 @@ +#define setcontext(u) _setmcontext(&(u)->mc) +#define getcontext(u) _getmcontext(&(u)->mc) +typedef struct mcontext mcontext_t; +typedef struct ucontext ucontext_t; +struct mcontext +{ + ulong gpr[10]; /* x19-x28 */ + ulong fp; /* x29 */ + ulong lr; /* x30 */ + ulong sp; /* stack pointer */ + ulong x0; /* return value / first argument */ + ulong x1; /* second argument */ + ulong fpr[8]; /* d8-d15 */ +}; + +struct ucontext +{ + struct { + void *ss_sp; + uint ss_size; + } uc_stack; + sigset_t uc_sigmask; + mcontext_t mc; +}; + +void makecontext(ucontext_t*, void(*)(void), int, ...); +int swapcontext(ucontext_t*, const ucontext_t*); +int _getmcontext(mcontext_t*); +void _setmcontext(const mcontext_t*); + diff --git a/asm.S b/asm.S index 205b0b8..f6959c8 100644 --- a/asm.S +++ b/asm.S @@ -13,7 +13,11 @@ #endif #if defined(__APPLE__) -#if defined(__i386__) +#if defined(__aarch64__) || defined(__arm64__) +#define NEEDARM64CONTEXT 1 +#define SET __setmcontext +#define GET __getmcontext +#elif defined(__i386__) #define NEEDX86CONTEXT 1 #define SET _setmcontext #define GET _getmcontext @@ -46,6 +50,77 @@ #define GET getmcontext #endif +#ifdef NEEDARM64CONTEXT + +.text +.p2align 2 + +.globl GET +GET: + /* Save callee-saved general-purpose registers */ + stp x19, x20, [x0, #0] + stp x21, x22, [x0, #16] + stp x23, x24, [x0, #32] + stp x25, x26, [x0, #48] + stp x27, x28, [x0, #64] + + /* Save frame pointer and link register */ + stp x29, x30, [x0, #80] + + /* Save stack pointer */ + mov x9, sp + str x9, [x0, #96] + + /* Return 1 when this context is restored */ + mov x9, #1 + str x9, [x0, #104] + str x1, [x0, #112] + + /* Save callee-saved floating-point registers */ + stp d8, d9, [x0, #120] + stp d10, d11, [x0, #136] + stp d12, d13, [x0, #152] + stp d14, d15, [x0, #168] + + /* First getcontext call returns 0 */ + mov w0, #0 + ret + + +.globl SET +SET: + /* x0 points to mcontext */ + mov x9, x0 + + /* Restore general-purpose registers */ + ldp x19, x20, [x9, #0] + ldp x21, x22, [x9, #16] + ldp x23, x24, [x9, #32] + ldp x25, x26, [x9, #48] + ldp x27, x28, [x9, #64] + + /* Restore frame pointer and return address */ + ldp x29, x30, [x9, #80] + + /* Restore stack pointer */ + ldr x10, [x9, #96] + + /* Restore floating-point registers */ + ldp d8, d9, [x9, #120] + ldp d10, d11, [x9, #136] + ldp d12, d13, [x9, #152] + ldp d14, d15, [x9, #168] + + mov sp, x10 + + /* Restore return value / task arguments */ + ldr x0, [x9, #104] + ldr x1, [x9, #112] + + ret + +#endif + #ifdef NEEDX86CONTEXT .globl SET SET: diff --git a/context.c b/context.c index b17bf15..0e76b1b 100644 --- a/context.c +++ b/context.c @@ -3,7 +3,10 @@ #include "taskimpl.h" #if defined(__APPLE__) -#if defined(__i386__) +#if defined(__aarch64__) || defined(__arm64__) +#define NEEDARM64MAKECONTEXT +#define NEEDSWAPCONTEXT +#elif defined(__i386__) #define NEEDX86MAKECONTEXT #define NEEDSWAPCONTEXT #elif defined(__x86_64__) @@ -40,6 +43,37 @@ #define NEEDMIPSMAKECONTEXT #endif +#ifdef NEEDARM64MAKECONTEXT + +void +makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) +{ + uintptr_t sp; + va_list arg; + + if(argc != 2){ + fprint(2, "makecontext: expected 2 arguments\n"); + abort(); + } + + sp = (uintptr_t)ucp->uc_stack.ss_sp + + ucp->uc_stack.ss_size; + + sp &= ~(uintptr_t)0xF; + + memset(&ucp->mc, 0, sizeof ucp->mc); + + ucp->mc.sp = (ulong)sp; + ucp->mc.lr = (ulong)(uintptr_t)func; + + va_start(arg, argc); + ucp->mc.x0 = va_arg(arg, uint); + ucp->mc.x1 = va_arg(arg, uint); + va_end(arg); +} + +#endif + #ifdef NEEDPOWERMAKECONTEXT void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) diff --git a/taskimpl.h b/taskimpl.h index abf30e6..f92e834 100644 --- a/taskimpl.h +++ b/taskimpl.h @@ -127,6 +127,8 @@ extern void makecontext(ucontext_t*, void(*)(), int, ...); # include "386-ucontext.h" # elif defined(__x86_64__) # include "amd64-ucontext.h" +# elif defined(__aarch64__) || defined (__arm64__) +# include "arm64-ucontext.h" # else # include "power-ucontext.h" # endif