summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/kvx/setcontext.S
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/linux/kvx/setcontext.S')
-rw-r--r--libc/sysdeps/linux/kvx/setcontext.S106
1 files changed, 106 insertions, 0 deletions
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@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)