diff mbox series

[uclibc-ng-devel] xtensa: implement user context manipulation functions

Message ID 20220617033219.792243-1-jcmvbkbc@gmail.com
State Superseded
Headers show
Series [uclibc-ng-devel] xtensa: implement user context manipulation functions | expand

Commit Message

Max Filippov June 17, 2022, 3:32 a.m. UTC
Implement getcontext, makecontext, setcontext and swapcontext.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
 extra/Configs/Config.xtensa                 |   3 +-
 libc/sysdeps/linux/xtensa/Makefile.arch     |   3 +
 libc/sysdeps/linux/xtensa/__start_context.S | 103 +++++++++++
 libc/sysdeps/linux/xtensa/getcontext.S      |  99 +++++++++++
 libc/sysdeps/linux/xtensa/makecontext.c     | 179 ++++++++++++++++++++
 libc/sysdeps/linux/xtensa/setcontext.S      | 116 +++++++++++++
 libc/sysdeps/linux/xtensa/swapcontext.S     | 173 +++++++++++++++++++
 libc/sysdeps/linux/xtensa/sysdep.h          |   7 +-
 libc/sysdeps/linux/xtensa/ucontext_i.sym    |  15 ++
 9 files changed, 695 insertions(+), 3 deletions(-)
 create mode 100644 libc/sysdeps/linux/xtensa/__start_context.S
 create mode 100644 libc/sysdeps/linux/xtensa/getcontext.S
 create mode 100644 libc/sysdeps/linux/xtensa/makecontext.c
 create mode 100644 libc/sysdeps/linux/xtensa/setcontext.S
 create mode 100644 libc/sysdeps/linux/xtensa/swapcontext.S
 create mode 100644 libc/sysdeps/linux/xtensa/ucontext_i.sym
diff mbox series

Patch

diff --git a/extra/Configs/Config.xtensa b/extra/Configs/Config.xtensa
index 3ee8817ba1a2..7316c542d896 100644
--- a/extra/Configs/Config.xtensa
+++ b/extra/Configs/Config.xtensa
@@ -10,5 +10,6 @@  config TARGET_ARCH
 config FORCE_OPTIONS_FOR_ARCH
 	bool
 	default y
-	select ARCH_HAS_DEPRECATED_SYSCALLS
 	select ARCH_ANY_ENDIAN
+	select ARCH_HAS_DEPRECATED_SYSCALLS
+	select ARCH_HAS_UCONTEXT
diff --git a/libc/sysdeps/linux/xtensa/Makefile.arch b/libc/sysdeps/linux/xtensa/Makefile.arch
index 23cd08ee5687..f3a93caaafb1 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 000000000000..f92c01112fa7
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/__start_context.S
@@ -0,0 +1,103 @@ 
+/* 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
+ *   a2..a4: func arguments 0..2
+ *
+ */
+	.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 000000000000..fbb70c3f8720
--- /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, 0
+	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, 0
+	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 000000000000..da26a0130325
--- /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 000000000000..4df7cc049006
--- /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 000000000000..a215edc6d54a
--- /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 0671f0783477..80b3f30fcc5d 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 000000000000..4770c36c9e1d
--- /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)