summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/linux')
-rw-r--r--libc/sysdeps/linux/xtensa/Makefile.arch3
-rw-r--r--libc/sysdeps/linux/xtensa/__start_context.S100
-rw-r--r--libc/sysdeps/linux/xtensa/getcontext.S99
-rw-r--r--libc/sysdeps/linux/xtensa/makecontext.c179
-rw-r--r--libc/sysdeps/linux/xtensa/setcontext.S116
-rw-r--r--libc/sysdeps/linux/xtensa/swapcontext.S173
-rw-r--r--libc/sysdeps/linux/xtensa/sysdep.h7
-rw-r--r--libc/sysdeps/linux/xtensa/ucontext_i.sym15
8 files changed, 690 insertions, 2 deletions
diff --git a/libc/sysdeps/linux/xtensa/Makefile.arch b/libc/sysdeps/linux/xtensa/Makefile.arch
index 23cd08ee5..f3a93caaa 100644
--- a/libc/sysdeps/linux/xtensa/Makefile.arch
+++ b/libc/sysdeps/linux/xtensa/Makefile.arch
@@ -10,3 +10,6 @@ SSRC-y := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S \
sigrestorer.S syscall.S mmap.S windowspill.S __longjmp.S vfork.S
CSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += fork.c
+
+CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c
+SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += setcontext.S getcontext.S swapcontext.S __start_context.S
diff --git a/libc/sysdeps/linux/xtensa/__start_context.S b/libc/sysdeps/linux/xtensa/__start_context.S
new file mode 100644
index 000000000..a30d7b618
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/__start_context.S
@@ -0,0 +1,100 @@
+/* Copyright (C) 2018 - 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#if defined(__XTENSA_CALL0_ABI__)
+/*
+ * There's no entry instruction, makecontext sets up ucontext_t as if
+ * getcontext was called above and is about to return here.
+ * Registers on entry to this function:
+ * a12: func to call
+ * a13: ucp->uc_link, next context to activate if func returns
+ * a14: func argc
+ */
+ .literal_position
+
+ENTRY_PREFIX(__start_context)
+
+ beqz a14, 1f
+
+ /* load func arguments 0..1 from stack and free that space */
+ l32i a2, a1, 8
+ l32i a3, a1, 12
+ addi a1, a1, 16
+ bltui a14, 3, 1f
+
+ /* load func arguments 2..5 from stack and free that space */
+ l32i a4, a1, 0
+ l32i a5, a1, 4
+ l32i a6, a1, 8
+ l32i a7, a1, 12
+ addi a1, a1, 16
+ /* func arguments 6..argc - 1 are now at the top of the stack */
+1:
+ callx0 a12
+ beqz a13, 1f
+ mov a2, a13
+ movi a4, JUMPTARGET (setcontext)
+ callx0 a4
+1:
+ movi a4, JUMPTARGET (_exit)
+ movi a2, 0
+ callx0 a4
+ ill
+END(__start_context)
+#elif defined(__XTENSA_WINDOWED_ABI__)
+/*
+ * There's no entry instruction, makecontext sets up ucontext_t as if
+ * getcontext was called above and is about to return here.
+ * Registers on entry to this function:
+ * a2: func to call
+ * a3: ucp->uc_link, next context to activate if func returns
+ * a4: func argc
+ * a5..a7: func arguments 0..2
+ */
+ .literal_position
+
+ENTRY_PREFIX(__start_context)
+
+ mov a10, a5
+ mov a11, a6
+ mov a12, a7
+ bltui a4, 4, 1f
+
+ /* load func arguments 3..5 from stack and free that space */
+ l32i a13, a1, 4
+ l32i a14, a1, 8
+ l32i a15, a1, 12
+ addi a5, a1, 16
+ movsp a1, a5
+ /* func arguments 6..argc - 1 are now at the top of the stack */
+1:
+ callx8 a2
+ beqz a3, 1f
+ mov a6, a3
+ movi a4, JUMPTARGET (setcontext)
+ callx4 a4
+1:
+ movi a4, JUMPTARGET (_exit)
+ movi a6, 0
+ callx4 a4
+ ill
+END(__start_context)
+#else
+#error Unsupported Xtensa ABI
+#endif
diff --git a/libc/sysdeps/linux/xtensa/getcontext.S b/libc/sysdeps/linux/xtensa/getcontext.S
new file mode 100644
index 000000000..7588a91b3
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/getcontext.S
@@ -0,0 +1,99 @@
+/* Copyright (C) 2018 - 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include "ucontext_i.h"
+
+#if defined(__XTENSA_CALL0_ABI__)
+ENTRY(__getcontext)
+ s32i a0, a2, MCONTEXT_SC_PC
+ s32i a1, a2, MCONTEXT_SC_A_0 + 4
+
+ /* save callee-saved registers in the context */
+ s32i a12, a2, MCONTEXT_SC_A_0 + 48
+ s32i a13, a2, MCONTEXT_SC_A_0 + 52
+ s32i a14, a2, MCONTEXT_SC_A_0 + 56
+ s32i a15, a2, MCONTEXT_SC_A_0 + 60
+
+ movi a3, 0
+ addi a4, a2, UCONTEXT_SIGMASK
+ movi a2, SIG_BLOCK
+ movi a5, JUMPTARGET (sigprocmask)
+ jx a5
+END(__getcontext)
+#elif defined(__XTENSA_WINDOWED_ABI__)
+ENTRY(__getcontext)
+ movi a4, __window_spill
+ callx4 a4
+ s32i a0, a2, MCONTEXT_SC_PC
+
+ /* copy registers a0..a3 from spill area */
+ addi a3, a1, -16
+ l32i a4, a3, 0
+ l32i a5, a3, 4
+ l32i a6, a3, 8
+ l32i a7, a3, 12
+ s32i a4, a2, MCONTEXT_SC_A_0 + 0
+ s32i a5, a2, MCONTEXT_SC_A_0 + 4
+ s32i a6, a2, MCONTEXT_SC_A_0 + 8
+ s32i a7, a2, MCONTEXT_SC_A_0 + 12
+
+ /* if it was call4 then register saving is done */
+ extui a4, a0, 30, 2
+ bltui a4, 2, 1f
+
+ /* otherwise load spill overflow area address into a3 */
+ addi a3, a5, -16
+ l32i a3, a3, 4
+ addi a3, a3, -32
+ beqi a4, 2, 2f
+
+ /* copy registers a8..a11 from spill overflow area */
+ addi a3, a3, -16
+ l32i a4, a3, 16
+ l32i a5, a3, 20
+ l32i a6, a3, 24
+ l32i a7, a3, 28
+ s32i a4, a2, MCONTEXT_SC_A_0 + 32
+ s32i a5, a2, MCONTEXT_SC_A_0 + 36
+ s32i a6, a2, MCONTEXT_SC_A_0 + 40
+ s32i a7, a2, MCONTEXT_SC_A_0 + 44
+
+ /* copy registers a4..a7 from spill overflow area */
+2:
+ l32i a4, a3, 0
+ l32i a5, a3, 4
+ l32i a6, a3, 8
+ l32i a7, a3, 12
+ s32i a4, a2, MCONTEXT_SC_A_0 + 16
+ s32i a5, a2, MCONTEXT_SC_A_0 + 20
+ s32i a6, a2, MCONTEXT_SC_A_0 + 24
+ s32i a7, a2, MCONTEXT_SC_A_0 + 28
+1:
+ movi a6, SIG_BLOCK
+ movi a7, 0
+ addi a8, a2, UCONTEXT_SIGMASK
+ movi a4, JUMPTARGET (sigprocmask)
+ callx4 a4
+ mov a2, a6
+ retw
+END(__getcontext)
+#else
+#error Unsupported Xtensa ABI
+#endif
+
+weak_alias (__getcontext, getcontext)
diff --git a/libc/sysdeps/linux/xtensa/makecontext.c b/libc/sysdeps/linux/xtensa/makecontext.c
new file mode 100644
index 000000000..da26a0130
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/makecontext.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2018 - 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <ucontext.h>
+
+extern void __start_context (void);
+
+#if defined(__XTENSA_CALL0_ABI__)
+/*
+ * makecontext sets up new stack like this:
+ *
+ * +------------------ stack top (uc_stack.ss_sp + uc_stack.ss_size)
+ * | optional alignment
+ * +------------------ CFA of __start_context, initial sp points here
+ * | optional padding
+ * +------------------ Optional arguments 6..argc - 1
+ * | func arg argc - 1
+ * | func arg argc - 2
+ * | ...
+ * | func arg 6
+ * +------------------ Optional arguments 2..5
+ * | func arg 5
+ * 16 | func arg 4
+ * | func arg 3
+ * | func arg 2
+ * +------------------ Optional arguments 0..1
+ * | func arg 1
+ * 16 | func arg 0
+ * | padding
+ * | padding
+ * +------------------ CFA of pseudo getcontext
+ * |
+ * +------------------ stack bottom (uc_stack.ss_sp)
+ *
+ * When argc is 0 arguments areas are not allocated,
+ * when 1 <= argc < 3 only area for arguments 0..1 is allocated,
+ * when 3 <= argc < 7 areas for arguments 0..1 and 2..5 is allocated,
+ * when argc >= 7 all three arguments areas are allocated.
+ * Arguments 0..5 area is deallocated by the __start_context after
+ * arguments are loaded into registers.
+ * uc_mcontext registers are set as if __start_context made call0
+ * to getcontext, sp points to that pseudo getcontext CFA.
+ * setcontext/swapcontext will arrange for restoring regiters
+ * a1, a12..a15 of __start_context.
+ */
+
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ unsigned long sp = ((unsigned long) ucp->uc_stack.ss_sp
+ + ucp->uc_stack.ss_size) & -16;
+ int i;
+
+ if (argc > 0)
+ sp -= 4 * (argc + 2);
+ sp &= -16;
+
+ ucp->uc_mcontext.sc_pc = (unsigned long) __start_context;
+ ucp->uc_mcontext.sc_a[1] = sp;
+ ucp->uc_mcontext.sc_a[12] = (unsigned long) func;
+ ucp->uc_mcontext.sc_a[13] = (unsigned long) ucp->uc_link;
+ ucp->uc_mcontext.sc_a[14] = argc;
+
+ if (argc)
+ {
+ va_list ap;
+
+ va_start (ap, argc);
+ for (i = 0; i < argc; ++i)
+ ((int *) sp)[i + 2] = va_arg (ap, int);
+ va_end (ap);
+ }
+}
+#elif defined(__XTENSA_WINDOWED_ABI__)
+/*
+ * makecontext sets up new stack like this:
+ *
+ * +------------------ stack top (uc_stack.ss_sp + uc_stack.ss_size)
+ * | optional alignment
+ * +------------------ CFA of __start_context
+ * 16 | Outermost caller spill area
+ * +------------------
+ * 16 | __start_context overflow area
+ * +------------------ initial sp points here
+ * | optional padding
+ * +------------------ Optional arguments 6..argc - 1
+ * | func arg argc - 1
+ * | func arg argc - 2
+ * | ...
+ * | func arg 6
+ * +------------------ Optional arguments 3..5
+ * | func arg 5
+ * 16 | func arg 4
+ * | func arg 3
+ * | padding
+ * +------------------ CFA of pseudo getcontext
+ * 16 | __start_context caller spill area
+ * +------------------
+ * |
+ * +------------------ stack bottom (uc_stack.ss_sp)
+ *
+ * When argc < 4 both arguments areas are not allocated,
+ * when 4 <= argc < 7 only area for arguments 3..5 is allocated,
+ * when argc >= 7 both arguments areas are allocated.
+ * Arguments 3..5 area is deallocated by the __start_context after
+ * arguments are loaded into registers.
+ * uc_mcontext registers are set as if __start_context made call8
+ * to getcontext, sp points to that pseudo getcontext CFA, spill
+ * area under that sp has a1 pointing to the __start_context CFA
+ * at the top of the stack. setcontext/swapcontext will arrange for
+ * restoring regiters a0..a7 of __start_context.
+ */
+
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ unsigned long sp = ((unsigned long) ucp->uc_stack.ss_sp
+ + ucp->uc_stack.ss_size - 32) & -16;
+ unsigned long spill0[4] =
+ {
+ 0, sp + 32, 0, 0,
+ };
+ int i;
+
+ memset ((void *) sp, 0, 32);
+
+ if (argc > 2)
+ sp -= 4 * (argc - 2);
+ sp &= -16;
+
+ ucp->uc_mcontext.sc_pc =
+ ((unsigned long) __start_context & 0x3fffffff) + 0x80000000;
+ ucp->uc_mcontext.sc_a[0] = 0;
+ ucp->uc_mcontext.sc_a[1] = sp;
+ ucp->uc_mcontext.sc_a[2] = (unsigned long) func;
+ ucp->uc_mcontext.sc_a[3] = (unsigned long) ucp->uc_link;
+ ucp->uc_mcontext.sc_a[4] = argc;
+
+ if (argc)
+ {
+ va_list ap;
+
+ va_start (ap, argc);
+ for (i = 0; i < argc; ++i)
+ {
+ if (i < 3)
+ ucp->uc_mcontext.sc_a[5 + i] = va_arg (ap, int);
+ else
+ ((int *) sp)[i - 2] = va_arg (ap, int);
+ }
+ va_end (ap);
+ }
+
+ sp -= 16;
+ memcpy ((void *) sp, spill0, sizeof (spill0));
+}
+#else
+#error Unsupported Xtensa ABI
+#endif
+
+weak_alias (__makecontext, makecontext)
diff --git a/libc/sysdeps/linux/xtensa/setcontext.S b/libc/sysdeps/linux/xtensa/setcontext.S
new file mode 100644
index 000000000..4df7cc049
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/setcontext.S
@@ -0,0 +1,116 @@
+/* Copyright (C) 2018 - 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include "ucontext_i.h"
+
+#if defined(__XTENSA_CALL0_ABI__)
+ENTRY(__setcontext)
+ addi sp, sp, -16
+ s32i a0, sp, 0
+ s32i a2, sp, 4
+
+ addi a3, a2, UCONTEXT_SIGMASK
+ movi a4, 0
+ movi a2, SIG_SETMASK
+ movi a5, JUMPTARGET (sigprocmask)
+ callx0 a5
+ bnez a2, .Lerror
+
+ l32i a2, sp, 4
+ l32i a0, a2, MCONTEXT_SC_PC
+ l32i a1, a2, MCONTEXT_SC_A_0 + 4
+
+ /* load callee-saved registers from the context */
+ l32i a12, a2, MCONTEXT_SC_A_0 + 48
+ l32i a13, a2, MCONTEXT_SC_A_0 + 52
+ l32i a14, a2, MCONTEXT_SC_A_0 + 56
+ l32i a15, a2, MCONTEXT_SC_A_0 + 60
+ movi a2, 0
+ ret
+.Lerror:
+ l32i a0, sp, 0
+ addi sp, sp, 16
+ ret
+END(__setcontext)
+#elif defined(__XTENSA_WINDOWED_ABI__)
+ENTRY(__setcontext)
+ movi a6, SIG_SETMASK
+ addi a7, a2, UCONTEXT_SIGMASK
+ movi a8, 0
+ movi a4, JUMPTARGET (sigprocmask)
+ callx4 a4
+ bnez a6, .Lerror
+ movi a4, __window_spill
+ callx4 a4
+
+ l32i a0, a2, MCONTEXT_SC_PC
+
+ /* copy registers a0..a3 to spill area */
+ addi a3, a1, -16
+ l32i a4, a2, MCONTEXT_SC_A_0 + 0
+ l32i a5, a2, MCONTEXT_SC_A_0 + 4
+ l32i a6, a2, MCONTEXT_SC_A_0 + 8
+ l32i a7, a2, MCONTEXT_SC_A_0 + 12
+ s32i a4, a3, 0
+ s32i a5, a3, 4
+ s32i a6, a3, 8
+ s32i a7, a3, 12
+
+ /* if it was call4 then register setup is done */
+ extui a4, a0, 30, 2
+ bltui a4, 2, 1f
+
+ /* otherwise load spill overflow area address into a3 */
+ addi a3, a5, -16
+ l32i a3, a3, 4
+ addi a3, a3, -32
+ beqi a4, 2, 2f
+
+ /* copy registers a8..a11 to spill overflow area */
+ addi a3, a3, -16
+ l32i a4, a2, MCONTEXT_SC_A_0 + 32
+ l32i a5, a2, MCONTEXT_SC_A_0 + 36
+ l32i a6, a2, MCONTEXT_SC_A_0 + 40
+ l32i a7, a2, MCONTEXT_SC_A_0 + 44
+ s32i a4, a3, 16
+ s32i a5, a3, 20
+ s32i a6, a3, 24
+ s32i a7, a3, 28
+
+ /* copy registers a4..a7 to spill overflow area */
+2:
+ l32i a4, a2, MCONTEXT_SC_A_0 + 16
+ l32i a5, a2, MCONTEXT_SC_A_0 + 20
+ l32i a6, a2, MCONTEXT_SC_A_0 + 24
+ l32i a7, a2, MCONTEXT_SC_A_0 + 28
+ s32i a4, a3, 0
+ s32i a5, a3, 4
+ s32i a6, a3, 8
+ s32i a7, a3, 12
+1:
+ movi a2, 0
+ retw
+.Lerror:
+ mov a2, a6
+ retw
+END(__setcontext)
+#else
+#error Unsupported Xtensa ABI
+#endif
+
+weak_alias (__setcontext, setcontext)
diff --git a/libc/sysdeps/linux/xtensa/swapcontext.S b/libc/sysdeps/linux/xtensa/swapcontext.S
new file mode 100644
index 000000000..a215edc6d
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/swapcontext.S
@@ -0,0 +1,173 @@
+/* Copyright (C) 2018 - 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include "ucontext_i.h"
+
+#if defined(__XTENSA_CALL0_ABI__)
+ENTRY(__swapcontext)
+ s32i a0, a2, MCONTEXT_SC_PC
+ s32i a1, a2, MCONTEXT_SC_A_0 + 4
+
+ /* save callee-saved registers in the context */
+ s32i a12, a2, MCONTEXT_SC_A_0 + 48
+ s32i a13, a2, MCONTEXT_SC_A_0 + 52
+ s32i a14, a2, MCONTEXT_SC_A_0 + 56
+ s32i a15, a2, MCONTEXT_SC_A_0 + 60
+
+ mov a12, a3
+ mov a13, a2
+
+ addi a3, a3, UCONTEXT_SIGMASK
+ addi a4, a2, UCONTEXT_SIGMASK
+ movi a2, SIG_SETMASK
+ movi a5, JUMPTARGET (sigprocmask)
+ callx0 a5
+ bnez a2, .Lerror
+
+ mov a2, a12
+ l32i a0, a2, MCONTEXT_SC_PC
+ l32i a1, a2, MCONTEXT_SC_A_0 + 4
+
+ /* load callee-saved registers from the context */
+ l32i a12, a2, MCONTEXT_SC_A_0 + 48
+ l32i a13, a2, MCONTEXT_SC_A_0 + 52
+ l32i a14, a2, MCONTEXT_SC_A_0 + 56
+ l32i a15, a2, MCONTEXT_SC_A_0 + 60
+
+ movi a2, 0
+ ret
+.Lerror:
+ l32i a0, a13, MCONTEXT_SC_PC
+ l32i a12, a13, MCONTEXT_SC_A_0 + 48
+ l32i a13, a13, MCONTEXT_SC_A_0 + 52
+ ret
+END(__swapcontext)
+#elif defined(__XTENSA_WINDOWED_ABI__)
+ENTRY(__swapcontext)
+ movi a4, __window_spill
+ callx4 a4
+ mov a9, a3
+ s32i a0, a2, MCONTEXT_SC_PC
+
+ /* copy registers a0..a3 from spill area */
+ addi a3, a1, -16
+ l32i a4, a3, 0
+ l32i a5, a3, 4
+ l32i a6, a3, 8
+ l32i a7, a3, 12
+ s32i a4, a2, MCONTEXT_SC_A_0 + 0
+ s32i a5, a2, MCONTEXT_SC_A_0 + 4
+ s32i a6, a2, MCONTEXT_SC_A_0 + 8
+ s32i a7, a2, MCONTEXT_SC_A_0 + 12
+
+ /* if it was call4 then register saving is done */
+ extui a4, a0, 30, 2
+ bltui a4, 2, 1f
+
+ /* otherwise load spill overflow area address into a3 */
+ addi a3, a5, -16
+ l32i a3, a3, 4
+ addi a3, a3, -32
+ beqi a4, 2, 2f
+
+ /* copy registers a8..a11 from spill overflow area */
+ addi a3, a3, -16
+ l32i a4, a3, 16
+ l32i a5, a3, 20
+ l32i a6, a3, 24
+ l32i a7, a3, 28
+ s32i a4, a2, MCONTEXT_SC_A_0 + 32
+ s32i a5, a2, MCONTEXT_SC_A_0 + 36
+ s32i a6, a2, MCONTEXT_SC_A_0 + 40
+ s32i a7, a2, MCONTEXT_SC_A_0 + 44
+
+ /* copy registers a4..a7 from spill overflow area */
+2:
+ l32i a4, a3, 0
+ l32i a5, a3, 4
+ l32i a6, a3, 8
+ l32i a7, a3, 12
+ s32i a4, a2, MCONTEXT_SC_A_0 + 16
+ s32i a5, a2, MCONTEXT_SC_A_0 + 20
+ s32i a6, a2, MCONTEXT_SC_A_0 + 24
+ s32i a7, a2, MCONTEXT_SC_A_0 + 28
+1:
+ movi a6, SIG_SETMASK
+ addi a7, a9, UCONTEXT_SIGMASK
+ addi a8, a2, UCONTEXT_SIGMASK
+ mov a2, a9
+ movi a4, JUMPTARGET (sigprocmask)
+ callx4 a4
+ bnez a6, .Lerror
+
+ l32i a0, a2, MCONTEXT_SC_PC
+
+ /* copy registers a0..a3 to spill area */
+ addi a3, a1, -16
+ l32i a4, a2, MCONTEXT_SC_A_0 + 0
+ l32i a5, a2, MCONTEXT_SC_A_0 + 4
+ l32i a6, a2, MCONTEXT_SC_A_0 + 8
+ l32i a7, a2, MCONTEXT_SC_A_0 + 12
+ s32i a4, a3, 0
+ s32i a5, a3, 4
+ s32i a6, a3, 8
+ s32i a7, a3, 12
+
+ /* if it was call4 then register setup is done */
+ extui a4, a0, 30, 2
+ bltui a4, 2, 1f
+
+ /* otherwise load spill overflow area address into a3 */
+ addi a3, a5, -16
+ l32i a3, a3, 4
+ addi a3, a3, -32
+ beqi a4, 2, 2f
+
+ /* copy registers a8..a11 to spill overflow area */
+ addi a3, a3, -16
+ l32i a4, a2, MCONTEXT_SC_A_0 + 32
+ l32i a5, a2, MCONTEXT_SC_A_0 + 36
+ l32i a6, a2, MCONTEXT_SC_A_0 + 40
+ l32i a7, a2, MCONTEXT_SC_A_0 + 44
+ s32i a4, a3, 16
+ s32i a5, a3, 20
+ s32i a6, a3, 24
+ s32i a7, a3, 28
+
+ /* copy registers a4..a7 to spill overflow area */
+2:
+ l32i a4, a2, MCONTEXT_SC_A_0 + 16
+ l32i a5, a2, MCONTEXT_SC_A_0 + 20
+ l32i a6, a2, MCONTEXT_SC_A_0 + 24
+ l32i a7, a2, MCONTEXT_SC_A_0 + 28
+ s32i a4, a3, 0
+ s32i a5, a3, 4
+ s32i a6, a3, 8
+ s32i a7, a3, 12
+1:
+ movi a2, 0
+ retw
+.Lerror:
+ mov a2, a6
+ retw
+END(__swapcontext)
+#else
+#error Unsupported Xtensa ABI
+#endif
+
+weak_alias (__swapcontext, swapcontext)
diff --git a/libc/sysdeps/linux/xtensa/sysdep.h b/libc/sysdeps/linux/xtensa/sysdep.h
index 0671f0783..80b3f30fc 100644
--- a/libc/sysdeps/linux/xtensa/sysdep.h
+++ b/libc/sysdeps/linux/xtensa/sysdep.h
@@ -39,12 +39,15 @@
#endif
-#define ENTRY(name) \
+#define ENTRY_PREFIX(name) \
.globl C_SYMBOL_NAME(name); \
ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function); \
.align ALIGNARG(2); \
LITERAL_POSITION; \
- C_LABEL(name) \
+ C_LABEL(name)
+
+#define ENTRY(name) \
+ ENTRY_PREFIX(name) \
abi_entry(sp, FRAMESIZE);
#define HIDDEN_ENTRY(name) \
diff --git a/libc/sysdeps/linux/xtensa/ucontext_i.sym b/libc/sysdeps/linux/xtensa/ucontext_i.sym
new file mode 100644
index 000000000..4770c36c9
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/ucontext_i.sym
@@ -0,0 +1,15 @@
+#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_SIGMASK ucontext (uc_sigmask)
+MCONTEXT_SC_A_0 mcontext (sc_a[0])
+MCONTEXT_SC_PC mcontext (sc_pc)