diff options
Diffstat (limited to 'libc/sysdeps/linux/kvx/setcontext.S')
-rw-r--r-- | libc/sysdeps/linux/kvx/setcontext.S | 106 |
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) |