Explorar o código

libc: kvx: add {get,set,swap,make}context functions

Add the obsolescent SUSv3 family of user context manipulating functions
for kvx.

Signed-off-by: Julian Vetter <jvetter@kalrayinc.com>
Julian Vetter hai 3 semanas
pai
achega
77d35096a0

+ 1 - 0
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

+ 2 - 0
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

+ 81 - 0
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@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)

+ 53 - 0
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@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)

+ 106 - 0
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@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)

+ 63 - 0
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@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)

+ 3 - 1
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;
 

+ 28 - 0
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)