Add the obsolescent SUSv3 family of user context manipulating functions
for kvx.
Signed-off-by: Julian Vetter <jvetter(a)kalrayinc.com>
---
extra/Configs/Config.kvx | 1 +
libc/sysdeps/linux/kvx/Makefile.arch | 2 +
libc/sysdeps/linux/kvx/getcontext.S | 81 ++++++++++++++++++++
libc/sysdeps/linux/kvx/makecontext.c | 53 +++++++++++++
libc/sysdeps/linux/kvx/setcontext.S | 106 ++++++++++++++++++++++++++
libc/sysdeps/linux/kvx/swapcontext.S | 63 +++++++++++++++
libc/sysdeps/linux/kvx/sys/ucontext.h | 4 +-
libc/sysdeps/linux/kvx/ucontext_i.sym | 28 +++++++
8 files changed, 337 insertions(+), 1 deletion(-)
create mode 100644 libc/sysdeps/linux/kvx/getcontext.S
create mode 100644 libc/sysdeps/linux/kvx/makecontext.c
create mode 100644 libc/sysdeps/linux/kvx/setcontext.S
create mode 100644 libc/sysdeps/linux/kvx/swapcontext.S
create mode 100644 libc/sysdeps/linux/kvx/ucontext_i.sym
diff --git a/extra/Configs/Config.kvx b/extra/Configs/Config.kvx
index 04df53c38..4d8152ab9 100644
--- a/extra/Configs/Config.kvx
+++ b/extra/Configs/Config.kvx
@@ -30,6 +30,7 @@ config FORCE_OPTIONS_FOR_ARCH
default y
select ARCH_LITTLE_ENDIAN
select ARCH_HAS_MMU
+ select ARCH_HAS_UCONTEXT
select UCLIBC_HAS_FPU
select UCLIBC_HAS_FENV
select UCLIBC_HAS_WCHAR
diff --git a/libc/sysdeps/linux/kvx/Makefile.arch b/libc/sysdeps/linux/kvx/Makefile.arch
index 3ad290915..18f2118f6 100644
--- a/libc/sysdeps/linux/kvx/Makefile.arch
+++ b/libc/sysdeps/linux/kvx/Makefile.arch
@@ -8,3 +8,5 @@
CSRC-y := __syscall_error.c
CSRC-$(UCLIBC_LINUX_SPECIFIC) += cachectl.c
SSRC-y := setjmp.S bsd-setjmp.S bsd-_setjmp.S __longjmp.S clone.S vfork.S
+CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c
+SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += getcontext.S setcontext.S swapcontext.S
diff --git a/libc/sysdeps/linux/kvx/getcontext.S b/libc/sysdeps/linux/kvx/getcontext.S
new file mode 100644
index 000000000..9440f67ce
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/getcontext.S
@@ -0,0 +1,81 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter(a)kalrayinc.com>
+ */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .text
+
+/*
+ * int getcontext (ucontext_t *ucp)
+ */
+ENTRY(__getcontext)
+ /* Save callee saved registers ($r14, $r18 - $r31)
+ * and some special registers */
+
+ /* Save the entire occtuple, although we only need $sp and $r14 */
+ so MCONTEXT_Q12[$r0] = $r12r13r14r15
+ get $r4 = $lc
+ ;;
+ /* Don't need to save veneer registers $r16 and $r17 */
+ sq (MCONTEXT_Q16 + 16)[$r0] = $r18r19
+ get $r5 = $le
+ ;;
+ so MCONTEXT_Q20[$r0] = $r20r21r22r23
+ get $r6 = $ls
+ ;;
+ so MCONTEXT_Q24[$r0] = $r24r25r26r27
+ get $r7 = $ra
+ ;;
+ so MCONTEXT_Q28[$r0] = $r28r29r30r31
+ get $r8 = $cs
+ ;;
+ so MCONTEXT_LC_LE_LS_RA[$r0] = $r4r5r6r7
+ /* Save ucp and $ra in callee saved registers because below we need to
+ * do a call to sigprocmask and afterwards we need to restore $ra. */
+ copyd $r20 = $r0
+ copyd $r21 = $r7
+ ;;
+ sd MCONTEXT_CS_SPC[$r0] = $r8
+
+ /* Prepare call to sigprocmask */
+ make $r0 = SIG_BLOCK
+ make $r1 = 0
+ ;;
+ /* $r20 points to the ucontext */
+ addd $r2 = $r20, UCONTEXT_SIGMASK
+ /* Already set the return value for when this is called in the context
+ * of swapcontext. Because when this context returns it should look
+ * like as if swapcontext returned with 0. */
+ sd MCONTEXT_Q0[$r20] = $r1
+ ;;
+ /* sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */
+ call sigprocmask
+ ;;
+ /* Restore $ra to point to the caller of this function. So,
+ * __getcontext will return with -1 (set by __syscall_error) and an
+ * appropriate errno */
+ set $ra = $r21
+ ;;
+ /* Check return value of sigprocmask */
+ cb.deqz $r0 ? 1f
+ ;;
+ goto __syscall_error
+ ;;
+1:
+ /* Restore used callee saved registers */
+ lq $r20r21 = MCONTEXT_Q20[$r20]
+ ;;
+ /* Set return value */
+ make $r0 = 0
+ ret
+ ;;
+END(__getcontext)
+weak_alias(__getcontext, getcontext)
diff --git a/libc/sysdeps/linux/kvx/makecontext.c b/libc/sysdeps/linux/kvx/makecontext.c
new file mode 100644
index 000000000..a52eded9f
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/makecontext.c
@@ -0,0 +1,53 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter(a)kalrayinc.com>
+ */
+
+#include <stdarg.h>
+#include <ucontext.h>
+
+
+/* Number of arguments that go in registers. */
+#define NREG_ARGS 12
+
+/* Take a context previously prepared via getcontext() and set to
+ call func() with the given int only args. */
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ extern void __startcontext (void);
+ unsigned long *funcstack;
+ va_list vl;
+ unsigned long *regptr;
+ unsigned int reg;
+
+ /* Start at the top of stack. */
+ funcstack = (unsigned long *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+ funcstack -= argc < NREG_ARGS ? 0 : argc - NREG_ARGS;
+ funcstack = (unsigned long *) (((uintptr_t) funcstack & -32L));
+
+ ucp->uc_mcontext.sc_regs.r12 = (unsigned long) funcstack;
+ /* Use $r20 and $r21 to pass some infos to __startcontext */
+ ucp->uc_mcontext.sc_regs.r20 = (unsigned long) ucp->uc_link;
+ ucp->uc_mcontext.sc_regs.r21 = (unsigned long) func;
+ ucp->uc_mcontext.sc_regs.ra = (unsigned long) __startcontext;
+
+ va_start (vl, argc);
+
+ /* The first twelve arguments go into registers. */
+ regptr = &(ucp->uc_mcontext.sc_regs.r0);
+
+ for (reg = 0; (reg < argc) && (reg < NREG_ARGS); reg++)
+ *regptr++ = va_arg (vl, unsigned long);
+
+ /* And the remainder on the stack. */
+ for (; reg < argc; reg++)
+ *funcstack++ = va_arg (vl, unsigned long);
+
+ va_end (vl);
+}
+weak_alias (__makecontext, makecontext)
diff --git a/libc/sysdeps/linux/kvx/setcontext.S b/libc/sysdeps/linux/kvx/setcontext.S
new file mode 100644
index 000000000..7b91d21d9
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/setcontext.S
@@ -0,0 +1,106 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter(a)kalrayinc.com>
+ */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .text
+
+/*
+ * int setcontext (const ucontext_t *ucp)
+ */
+ENTRY(__setcontext)
+ get $r16 = $ra
+ addd $r12 = $r12, -32
+ ;;
+ /* Save ucp pointer and $ra on the stack because we can't trash
+ * any callee saved registers in case __setcontext returns */
+ sd 16[$r12] = $r16
+ ;;
+ sd 24[$r12] = $r0
+ ;;
+ /* Bring back the signal status. */
+ make $r0 = SIG_SETMASK
+ addd $r1 = $r0, UCONTEXT_SIGMASK
+ make $r2 = 0
+ ;;
+ /* sigprocmask(SIG_SETMASK, &(ucontext->uc_sigmask), NULL) */
+ call sigprocmask
+ ;;
+ /* Check return value of sigprocmask */
+ cb.deqz $r0 ? 1f
+ /* Normally __setcontext does not return. But in case of an error it
+ * returns with -1 and an appropriate errno */
+ ld $r16 = 16[$r12]
+ ;;
+ set $ra = $r16
+ addd $r12 = $r12, 32
+ ;;
+ goto __syscall_error
+ ;;
+1:
+ /* Get back the ucp pointer */
+ ld $r16 = 24[$r12]
+ /* Reset the stack pointer (we can trash $ra here, because we will
+ * never return to after __setcontext from this point onwards) */
+ addd $r12 = $r12, 32
+ ;;
+ /* Restore callee saved registers */
+ lq $r18r19 = (MCONTEXT_Q16 + 16)[$r16]
+ ;;
+ /* Setup $r20, $r21 for the __startcontext to work */
+ lo $r20r21r22r23 = MCONTEXT_Q20[$r16]
+ ;;
+ lo $r24r25r26r27 = MCONTEXT_Q24[$r16]
+ ;;
+ lo $r28r29r30r31 = MCONTEXT_Q28[$r16]
+ ;;
+ /* Restore special registers */
+ lo $r40r41r42r43 = MCONTEXT_LC_LE_LS_RA[$r16]
+ ;;
+ /* Now load argument registers */
+ lo $r0r1r2r3 = MCONTEXT_Q0[$r16]
+ set $lc = $r40
+ ;;
+ lo $r4r5r6r7 = MCONTEXT_Q4[$r16]
+ set $le = $r41
+ ;;
+ lo $r8r9r10r11 = MCONTEXT_Q8[$r16]
+ set $ls = $r42
+ ;;
+ /* Restore $sp */
+ ld $r12 = MCONTEXT_Q12[$r16]
+ /* Restore $ra which points to the $ra set by __getcontext or
+ * to__startcontext if __makecontext was called in between */
+ set $ra = $r43
+ ;;
+ ld $r40 = MCONTEXT_CS_SPC[$r16]
+ ;;
+ ld $r14 = (MCONTEXT_Q12 + 16)[$r16]
+ set $cs = $r40
+ ;;
+ ret
+ ;;
+END(setcontext)
+weak_alias(__setcontext, setcontext)
+
+ENTRY(__startcontext)
+ icall $r21
+ ;;
+ copyd $r0 = $r20
+ /* Check if the new context is 0 if so just call _exit */
+ cb.deqz $r20 ? 1f
+ ;;
+ goto __setcontext
+ ;;
+ /* This should never be reached otherwise kill the thread */
+1: goto _exit
+ ;;
+END(__startcontext)
diff --git a/libc/sysdeps/linux/kvx/swapcontext.S b/libc/sysdeps/linux/kvx/swapcontext.S
new file mode 100644
index 000000000..1abb6a8a8
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/swapcontext.S
@@ -0,0 +1,63 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter(a)kalrayinc.com>
+ */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .text
+
+/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
+
+ENTRY(swapcontext)
+ /* Make space on the stack to save all caller saved registers */
+ get $r16 = $ra
+ addd $r12 = $r12, -32
+ ;;
+
+ /* Save $ra on the stack */
+ sd (24)[$r12] = $r16
+ ;;
+ /* Save the arguments of swapcontext on the stack */
+ sq (8)[$r12] = $r0r1
+ ;;
+ call __getcontext
+ ;;
+
+ /* Save the return value of __getcontext in $r17 */
+ copyd $r17 = $r0
+
+ /* Restore $ra */
+ ld $r16 = (24)[$r12]
+ ;;
+ /* Restore arguments */
+ lq $r0r1 = (8)[$r12]
+ /* Readjust the stack pointer */
+ addd $r12 = $r12, 32
+ /* Also restore $ra */
+ set $ra = $r16
+ ;;
+
+ /* Exit if getcontext() failed */
+ cb.deqz $r17 ? 1f
+ ;;
+
+ /* Set the return value set by __syscall_error in __getcontext */
+ copyd $r0 = $r17
+ ret
+ ;;
+1:
+ /* Store the $sp and $ra in the context to be saved */
+ sd (MCONTEXT_Q12)[$r0] = $r12
+ ;;
+ sd (MCONTEXT_LC_LE_LS_RA + 24)[$r0] = $r16
+ copyd $r0 = $r1
+ goto __setcontext
+ ;;
+END(swapcontext)
diff --git a/libc/sysdeps/linux/kvx/sys/ucontext.h b/libc/sysdeps/linux/kvx/sys/ucontext.h
index a97b83cad..6a30a09e2 100644
--- a/libc/sysdeps/linux/kvx/sys/ucontext.h
+++ b/libc/sysdeps/linux/kvx/sys/ucontext.h
@@ -17,11 +17,13 @@
/* Type for general register. */
typedef unsigned long greg_t;
+typedef struct sigcontext mcontext_t;
+
typedef struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
- struct sigcontext uc_mcontext;
+ mcontext_t uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
} ucontext_t;
diff --git a/libc/sysdeps/linux/kvx/ucontext_i.sym b/libc/sysdeps/linux/kvx/ucontext_i.sym
new file mode 100644
index 000000000..d2b565332
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/ucontext_i.sym
@@ -0,0 +1,28 @@
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/ucontext.h>
+
+SIG_BLOCK
+SIG_SETMASK
+
+-- Offsets of the fields in the ucontext_t structure.
+#define ucontext(member) offsetof (ucontext_t, member)
+#define mcontext(member) ucontext (uc_mcontext.member)
+
+UCONTEXT_FLAGS ucontext (uc_flags)
+UCONTEXT_LINK ucontext (uc_link)
+UCONTEXT_STACK ucontext (uc_stack)
+UCONTEXT_MCONTEXT ucontext (uc_mcontext)
+UCONTEXT_SIGMASK ucontext (uc_sigmask)
+
+MCONTEXT_Q0 mcontext (sc_regs.r0)
+MCONTEXT_Q4 mcontext (sc_regs.r4)
+MCONTEXT_Q8 mcontext (sc_regs.r8)
+MCONTEXT_Q12 mcontext (sc_regs.r12)
+MCONTEXT_Q16 mcontext (sc_regs.r16)
+MCONTEXT_Q20 mcontext (sc_regs.r20)
+MCONTEXT_Q24 mcontext (sc_regs.r24)
+MCONTEXT_Q28 mcontext (sc_regs.r28)
+MCONTEXT_LC_LE_LS_RA mcontext (sc_regs.lc)
+MCONTEXT_CS_SPC mcontext (sc_regs.cs)
--
2.34.1