From patchwork Wed May 22 12:05:04 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markos Chandras X-Patchwork-Id: 245597 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from silver.osuosl.org (silver.osuosl.org [140.211.166.136]) by ozlabs.org (Postfix) with ESMTP id 1DD7E2C00A0 for ; Wed, 22 May 2013 22:06:35 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id C8D7631D29; Wed, 22 May 2013 12:06:33 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kqfFvuepMmch; Wed, 22 May 2013 12:06:15 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by silver.osuosl.org (Postfix) with ESMTP id EB7772FF59; Wed, 22 May 2013 12:06:14 +0000 (UTC) X-Original-To: buildroot@lists.busybox.net Delivered-To: buildroot@osuosl.org Received: from whitealder.osuosl.org (whitealder.osuosl.org [140.211.166.138]) by ash.osuosl.org (Postfix) with ESMTP id A91EA8F7AF for ; Wed, 22 May 2013 12:06:20 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 091A48CF27 for ; Wed, 22 May 2013 12:06:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WNPj5fUmLqgI for ; Wed, 22 May 2013 12:06:07 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from multi.imgtec.com (multi.imgtec.com [194.200.65.239]) by whitealder.osuosl.org (Postfix) with ESMTPS id EE0E78CF5B for ; Wed, 22 May 2013 12:06:05 +0000 (UTC) From: Markos Chandras To: Date: Wed, 22 May 2013 13:05:04 +0100 Message-ID: <1369224304-24734-1-git-send-email-markos.chandras@gmail.com> X-Mailer: git-send-email 1.8.2.1 MIME-Version: 1.0 X-SEF-Processed: 7_3_0_01181__2013_05_22_13_06_04 Subject: [Buildroot] [PATCH] uClibc: Add upstream patch for context functions X-BeenThere: buildroot@busybox.net X-Mailman-Version: 2.1.14 Precedence: list List-Id: Discussion and development of buildroot List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: buildroot-bounces@busybox.net Sender: buildroot-bounces@busybox.net From: Markos Chandras These functions are needed by some packages like mongrel2 and maybe others. Fixes: http://autobuild.buildroot.net/results/8e132a2b03a7b5ae94199db7db86883c05dca700/build-end.log Signed-off-by: Markos Chandras --- Given this patch is quite big, another option would be for these packages to depend on !BR2_TOOLCHAIN_BUILDROOT || BR2_UCLIBC_VERSION_SNAPSHOT --- .../uClibc/uClibc-0.9.33.2-context-funcs.patch | 2493 ++++++++++++++++++++ toolchain/uClibc/uClibc-0.9.33.config | 2 + toolchain/uClibc/uclibc.mk | 3 + 3 files changed, 2498 insertions(+) create mode 100644 toolchain/uClibc/uClibc-0.9.33.2-context-funcs.patch diff --git a/toolchain/uClibc/uClibc-0.9.33.2-context-funcs.patch b/toolchain/uClibc/uClibc-0.9.33.2-context-funcs.patch new file mode 100644 index 0000000..f20065a --- /dev/null +++ b/toolchain/uClibc/uClibc-0.9.33.2-context-funcs.patch @@ -0,0 +1,2493 @@ +The following patch adds {get,set,swap,make}context user context functions +and lives in the uClibc master branch. + +http://git.uclibc.org/uClibc/commit/?id=a8dc90eaaa5e6474beac828558d969b1aafee4af + +Signed-off-by: Markos Chandras + +From a8dc90eaaa5e6474beac828558d969b1aafee4af Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Wed, 09 Jan 2013 15:17:21 +0000 +Subject: libc: add {get,set,swap,make}context user context manipulation functions + +Add the obsolescent SUSv3 family of user context manipulating functions +for arm, i386, mips, x86_64. + +Signed-off-by: Timon ter Braak +Signed-off-by: Florian Fainelli +Signed-off-by: Bernhard Reutner-Fischer +Signed-off-by: Natanael Copa +Signed-off-by: Bernhard Reutner-Fischer +--- +diff --git a/Rules.mak b/Rules.mak +index 96871e1..8943fbf 100644 +--- a/Rules.mak ++++ b/Rules.mak +@@ -813,3 +813,5 @@ SHARED_END_FILES:=$(LIBGCC_DIR)crtendS.o $(top_builddir)lib/crtn.o + endif + + LOCAL_INSTALL_PATH := install_dir ++ ++PTHREAD_GENERATE_MANGLE ?= -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*\$$/\#define \1 \2/p" +diff --git a/extra/Configs/Config.arm b/extra/Configs/Config.arm +index 0bb2971..dc53643 100644 +--- a/extra/Configs/Config.arm ++++ b/extra/Configs/Config.arm +@@ -11,6 +11,7 @@ config FORCE_OPTIONS_FOR_ARCH + bool + default y + select ARCH_ANY_ENDIAN ++ select ARCH_HAS_UCONTEXT + + config CONFIG_ARM_EABI + bool "Build for EABI" +diff --git a/extra/Configs/Config.i386 b/extra/Configs/Config.i386 +index 288aa5e..92cee3b 100644 +--- a/extra/Configs/Config.i386 ++++ b/extra/Configs/Config.i386 +@@ -12,6 +12,7 @@ config FORCE_OPTIONS_FOR_ARCH + default y + select ARCH_LITTLE_ENDIAN + select ARCH_HAS_MMU ++ select ARCH_HAS_UCONTEXT + + choice + prompt "Target x86 Processor Family" +diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in +index 4bb6812..62bcd9b 100644 +--- a/extra/Configs/Config.in ++++ b/extra/Configs/Config.in +@@ -261,6 +261,9 @@ config ARCH_HAS_NO_LDSO + bool + select ARCH_HAS_NO_SHARED + ++config ARCH_HAS_UCONTEXT ++ bool ++ + config HAVE_SHARED + bool "Enable shared libraries" + depends on !ARCH_HAS_NO_SHARED +@@ -678,6 +681,19 @@ config UCLIBC_SUSV3_LEGACY + + WARNING! ABI incompatibility. + ++config UCLIBC_HAS_CONTEXT_FUNCS ++ bool "Use obsolescent context control functions" ++ depends on UCLIBC_SUSV3_LEGACY && ARCH_HAS_UCONTEXT ++ help ++ Add into library the SuSv3 obsolescent functions used for context ++ control. The setcontext family allows the implementation in C of ++ advanced control flow patterns such as iterators, fibers, and ++ coroutines. They may be viewed as an advanced version of ++ setjmp/longjmp; whereas the latter allows only a single non-local jump ++ up the stack, setcontext allows the creation of multiple cooperative ++ threads of control, each with its own stack. ++ These functions are: setcontext, getcontext, makecontext, swapcontext. ++ + config UCLIBC_SUSV3_LEGACY_MACROS + bool "Enable SuSv3 LEGACY macros" + help +diff --git a/extra/Configs/Config.mips b/extra/Configs/Config.mips +index 063b07c..48e0b64 100644 +--- a/extra/Configs/Config.mips ++++ b/extra/Configs/Config.mips +@@ -11,6 +11,7 @@ config FORCE_OPTIONS_FOR_ARCH + bool + default y + select ARCH_ANY_ENDIAN ++ select ARCH_HAS_UCONTEXT + + choice + prompt "Target ABI" +diff --git a/extra/Configs/Config.x86_64 b/extra/Configs/Config.x86_64 +index 1b28088..4c8c3a9 100644 +--- a/extra/Configs/Config.x86_64 ++++ b/extra/Configs/Config.x86_64 +@@ -12,3 +12,4 @@ config FORCE_OPTIONS_FOR_ARCH + default y + select ARCH_LITTLE_ENDIAN + select ARCH_HAS_MMU ++ select ARCH_HAS_UCONTEXT +diff --git a/include/ucontext.h b/include/ucontext.h +index 14a1270..f11db77 100644 +--- a/include/ucontext.h ++++ b/include/ucontext.h +@@ -15,17 +15,43 @@ + License along with the GNU C Library; if not, see + . */ + ++/* The System V ABI user-level context switching support functions ++ are marked obsolescent by SuSv3. */ ++ + #ifndef _UCONTEXT_H + #define _UCONTEXT_H 1 + + #include + ++#ifdef __UCLIBC_HAS_CONTEXT_FUNCS__ ++ + /* Get machine dependent definition of data structures. */ + #include + +-/* The System V ABI user-level context switching support functions +- * are marked obsolescent by SuSv3, and are not implemented by +- * uClibc. This header is therefore empty. */ ++__BEGIN_DECLS ++ ++/* Get user context and store it in variable pointed to by UCP. */ ++extern int getcontext (ucontext_t *__ucp) __THROW; ++ ++/* Set user context from information of variable pointed to by UCP. */ ++extern int setcontext (const ucontext_t *__ucp) __THROW; ++ ++/* Save current context in context variable pointed to by OUCP and set ++ context from variable pointed to by UCP. */ ++extern int swapcontext (ucontext_t *__restrict __oucp, ++ const ucontext_t *__restrict __ucp) __THROW; ++ ++/* Manipulate user context UCP to continue with calling functions FUNC ++ and the ARGC-1 parameters following ARGC when the context is used ++ the next time in `setcontext' or `swapcontext'. ++ ++ We cannot say anything about the parameters FUNC takes; `void' ++ is as good as any other choice. */ ++extern void makecontext (ucontext_t *__ucp, void (*__func) (void), ++ int __argc, ...) __THROW; ++ ++__END_DECLS + ++#endif + + #endif /* ucontext.h */ +diff --git a/libc/.gitignore b/libc/.gitignore +new file mode 100644 +index 0000000..f4c0305 +--- /dev/null ++++ b/libc/.gitignore +@@ -0,0 +1 @@ ++ucontext_i.[chs] +diff --git a/libc/sysdeps/linux/Makefile.commonarch b/libc/sysdeps/linux/Makefile.commonarch +index c1bc5df..ac89e72 100644 +--- a/libc/sysdeps/linux/Makefile.commonarch ++++ b/libc/sysdeps/linux/Makefile.commonarch +@@ -37,5 +37,23 @@ headers-y += $(ARCH_HEADERS_OUT) + headers_clean-y += HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)) + HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)): + $(do_rm) $(ARCH_HEADERS_OUT) +- + endif ++ ++CFLAGS-ucontext_i.c = -S ++ ++$(ARCH_OUT)/ucontext_i.c: $(ARCH_DIR)/ucontext_i.sym ++ $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ ++ ++$(ARCH_OUT)/ucontext_i.s: $(ARCH_OUT)/ucontext_i.c ++ $(compile.c) ++ ++$(ARCH_OUT)/ucontext_i.h: $(ARCH_OUT)/ucontext_i.s ++ $(do_sed) $(PTHREAD_GENERATE_MANGLE) $< > $@ ++ ++pregen-headers-$(UCLIBC_HAS_CONTEXT_FUNCS) += $(ARCH_OUT)/ucontext_i.h ++ ++headers_clean-$(UCLIBC_HAS_CONTEXT_FUNCS) += \ ++ HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)/ucontext_i) ++ ++HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)/ucontext_i): ++ $(do_rm) $(addprefix $(ARCH_OUT)/ucontext_i., c h s) +diff --git a/libc/sysdeps/linux/arm/Makefile.arch b/libc/sysdeps/linux/arm/Makefile.arch +index 5fc3e54..36d988b 100644 +--- a/libc/sysdeps/linux/arm/Makefile.arch ++++ b/libc/sysdeps/linux/arm/Makefile.arch +@@ -43,3 +43,8 @@ libc-static-y += $(ARCH_OUT)/aeabi_lcsts.o $(ARCH_OUT)/aeabi_math.o \ + libc-nonshared-y += $(ARCH_OUT)/aeabi_lcsts.os $(ARCH_OUT)/aeabi_math.os \ + $(ARCH_OUT)/aeabi_sighandlers.os $(ARCH_OUT)/aeabi_unwind_cpp_pr1.o + endif ++ ++ifeq ($(UCLIBC_HAS_CONTEXT_FUNCS),y) ++CSRC += makecontext.c ++SSRC += getcontext.S setcontext.S swapcontext.S ++endif +diff --git a/libc/sysdeps/linux/arm/getcontext.S b/libc/sysdeps/linux/arm/getcontext.S +new file mode 100644 +index 0000000..a987c52 +--- /dev/null ++++ b/libc/sysdeps/linux/arm/getcontext.S +@@ -0,0 +1,80 @@ ++/* Copyright (C) 2012 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ .syntax unified ++ .text ++ ++/* int getcontext (ucontext_t *ucp) */ ++ ++ENTRY(__getcontext) ++ /* No need to save r0-r3, d0-d7, or d16-d31. */ ++ add r1, r0, #MCONTEXT_ARM_R4 ++ stmia r1, {r4-r11} ++ ++ /* Save R13 separately as Thumb can't STM it. */ ++ str r13, [r0, #MCONTEXT_ARM_SP] ++ str r14, [r0, #MCONTEXT_ARM_LR] ++ /* Return to LR */ ++ str r14, [r0, #MCONTEXT_ARM_PC] ++ /* Return zero */ ++ mov r2, #0 ++ str r2, [r0, #MCONTEXT_ARM_R0] ++ ++ /* Save ucontext_t * across the next call. */ ++ mov r4, r0 ++ ++ /* __sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */ ++ mov r0, #SIG_BLOCK ++ mov r1, #0 ++ add r2, r4, #UCONTEXT_SIGMASK ++ bl PLTJMP(sigprocmask) ++ ++#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__ ++# ifdef __VFP_FP__ ++ /* Store the VFP registers. */ ++ /* Following instruction is fstmiax ip!, {d8-d15}. */ ++ stc p11, cr8, [r0], #64 ++ /* Store the floating-point status register. */ ++ /* Following instruction is fmrx r2, fpscr. */ ++ mrc p10, 7, r1, cr1, cr0, 0 ++ str r1, [r0], #4 ++# endif ++#endif ++#ifdef __IWMMXT__ ++ /* Save the call-preserved iWMMXt registers. */ ++ /* Following instructions are wstrd wr10, [r0], #8 (etc.) */ ++ stcl p1, cr10, [r0], #8 ++ stcl p1, cr11, [r0], #8 ++ stcl p1, cr12, [r0], #8 ++ stcl p1, cr13, [r0], #8 ++ stcl p1, cr14, [r0], #8 ++ stcl p1, cr15, [r0], #8 ++#endif ++ ++ /* Restore the clobbered R4 and LR. */ ++ ldr r14, [r4, #MCONTEXT_ARM_LR] ++ ldr r4, [r4, #MCONTEXT_ARM_R4] ++ ++ mov r0, #0 ++ DO_RET(r14) ++ ++END(__getcontext) ++weak_alias(__getcontext, getcontext) +diff --git a/libc/sysdeps/linux/arm/makecontext.c b/libc/sysdeps/linux/arm/makecontext.c +new file mode 100644 +index 0000000..d6ae6f0 +--- /dev/null ++++ b/libc/sysdeps/linux/arm/makecontext.c +@@ -0,0 +1,73 @@ ++/* Copyright (C) 2012 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 ++ . */ ++ ++#include ++#include ++ ++/* Number of arguments that go in registers. */ ++#define NREG_ARGS 4 ++ ++/* 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; ++ int misaligned; ++ ++ /* Start at the top of stack. */ ++ funcstack = (unsigned long *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); ++ ++ /* Ensure the stack stays eight byte aligned. */ ++ misaligned = ((unsigned long) funcstack & 4) != 0; ++ ++ if ((argc > NREG_ARGS) && (argc & 1) != 0) ++ misaligned = !misaligned; ++ ++ if (misaligned) ++ funcstack -= 1; ++ ++ va_start (vl, argc); ++ ++ /* Reserve space for the on-stack arguments. */ ++ if (argc > NREG_ARGS) ++ funcstack -= (argc - NREG_ARGS); ++ ++ ucp->uc_mcontext.arm_sp = (unsigned long) funcstack; ++ ucp->uc_mcontext.arm_pc = (unsigned long) func; ++ ++ /* Exit to startcontext() with the next context in R4 */ ++ ucp->uc_mcontext.arm_r4 = (unsigned long) ucp->uc_link; ++ ucp->uc_mcontext.arm_lr = (unsigned long) __startcontext; ++ ++ /* The first four arguments go into registers. */ ++ regptr = &(ucp->uc_mcontext.arm_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) +diff --git a/libc/sysdeps/linux/arm/setcontext.S b/libc/sysdeps/linux/arm/setcontext.S +new file mode 100644 +index 0000000..a5c33a0 +--- /dev/null ++++ b/libc/sysdeps/linux/arm/setcontext.S +@@ -0,0 +1,76 @@ ++/* Copyright (C) 2012 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ .syntax unified ++ .text ++ ++/* int setcontext (const ucontext_t *ucp) */ ++ ++ENTRY(__setcontext) ++ mov r4, r0 ++ ++#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__ ++# ifdef __VFP_FP__ ++ /* Following instruction is vldmia r0!, {d8-d15}. */ ++ ldc p11, cr8, [r0], #64 ++ /* Restore the floating-point status register. */ ++ ldr r1, [r0], #4 ++ /* Following instruction is fmxr fpscr, r1. */ ++ mcr p10, 7, r1, cr1, cr0, 0 ++# endif ++#endif ++ ++#ifdef __IWMMXT__ ++ /* Restore the call-preserved iWMMXt registers. */ ++ /* Following instructions are wldrd wr10, [r0], #8 (etc.) */ ++ ldcl p1, cr10, [r0], #8 ++ ldcl p1, cr11, [r0], #8 ++ ldcl p1, cr12, [r0], #8 ++ ldcl p1, cr13, [r0], #8 ++ ldcl p1, cr14, [r0], #8 ++ ldcl p1, cr15, [r0], #8 ++#endif ++ ++ /* Now bring back the signal status. */ ++ mov r0, #SIG_SETMASK ++ add r1, r4, #UCONTEXT_SIGMASK ++ mov r2, #0 ++ bl PLTJMP(sigprocmask) ++ ++ /* Loading r0-r3 makes makecontext easier. */ ++ add r14, r4, #MCONTEXT_ARM_R0 ++ ldmia r14, {r0-r11} ++ ldr r13, [r14, #(MCONTEXT_ARM_SP - MCONTEXT_ARM_R0)] ++ add r14, r14, #(MCONTEXT_ARM_LR - MCONTEXT_ARM_R0) ++ ldmia r14, {r14, pc} ++ ++END(setcontext) ++weak_alias(__setcontext, setcontext) ++ ++ /* Called when a makecontext() context returns. Start the ++ context in R4 or fall through to exit(). */ ++ENTRY(__startcontext) ++ movs r0, r4 ++ bne PLTJMP(__setcontext) ++ ++ @ New context was 0 - exit ++ b PLTJMP(_exit) ++END(__startcontext) +diff --git a/libc/sysdeps/linux/arm/swapcontext.S b/libc/sysdeps/linux/arm/swapcontext.S +new file mode 100644 +index 0000000..ba6e31c +--- /dev/null ++++ b/libc/sysdeps/linux/arm/swapcontext.S +@@ -0,0 +1,63 @@ ++/* Copyright (C) 2012 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ .syntax unified ++ .text ++ ++/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */ ++ ++ENTRY(swapcontext) ++ ++ /* Have getcontext() do most of the work then fix up ++ LR afterwards. Save R3 to keep the stack aligned. */ ++ push {r0,r1,r3,r14} ++ cfi_adjust_cfa_offset (16) ++ cfi_rel_offset (r0,0) ++ cfi_rel_offset (r1,4) ++ cfi_rel_offset (r3,8) ++ cfi_rel_offset (r14,12) ++ ++ bl __getcontext ++ mov r4, r0 ++ ++ pop {r0,r1,r3,r14} ++ cfi_adjust_cfa_offset (-16) ++ cfi_restore (r0) ++ cfi_restore (r1) ++ cfi_restore (r3) ++ cfi_restore (r14) ++ ++ /* Exit if getcontext() failed. */ ++ cmp r4, #0 ++ itt ne ++ movne r0, r4 ++ RETINSTR(ne, r14) ++ ++ /* Fix up LR and the PC. */ ++ str r13,[r0, #MCONTEXT_ARM_SP] ++ str r14,[r0, #MCONTEXT_ARM_LR] ++ str r14,[r0, #MCONTEXT_ARM_PC] ++ ++ /* And swap using swapcontext(). */ ++ mov r0, r1 ++ b __setcontext ++ ++END(swapcontext) +diff --git a/libc/sysdeps/linux/arm/ucontext_i.sym b/libc/sysdeps/linux/arm/ucontext_i.sym +new file mode 100644 +index 0000000..9650322 +--- /dev/null ++++ b/libc/sysdeps/linux/arm/ucontext_i.sym +@@ -0,0 +1,30 @@ ++#include ++#include ++#include ++#include ++ ++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) ++ ++UCONTEXT_REGSPACE ucontext (uc_regspace) ++ ++MCONTEXT_TRAP_NO mcontext (trap_no) ++MCONTEXT_ERROR_CODE mcontext (error_code) ++MCONTEXT_OLDMASK mcontext (oldmask) ++MCONTEXT_ARM_R0 mcontext (arm_r0) ++MCONTEXT_ARM_R4 mcontext (arm_r4) ++MCONTEXT_ARM_SP mcontext (arm_sp) ++MCONTEXT_ARM_LR mcontext (arm_lr) ++MCONTEXT_ARM_PC mcontext (arm_pc) ++MCONTEXT_ARM_CPSR mcontext (arm_cpsr) ++MCONTEXT_FAULT_ADDRESS mcontext (fault_address) +diff --git a/libc/sysdeps/linux/i386/Makefile.arch b/libc/sysdeps/linux/i386/Makefile.arch +index a3bf32f..e7fd28e 100644 +--- a/libc/sysdeps/linux/i386/Makefile.arch ++++ b/libc/sysdeps/linux/i386/Makefile.arch +@@ -18,3 +18,7 @@ endif + ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) + SSRC += vfork.S clone.S + endif ++ ++ifeq ($(UCLIBC_HAS_CONTEXT_FUNCS),y) ++SSRC += makecontext.S setcontext.S getcontext.S swapcontext.S ++endif +diff --git a/libc/sysdeps/linux/i386/getcontext.S b/libc/sysdeps/linux/i386/getcontext.S +new file mode 100644 +index 0000000..3221b59 +--- /dev/null ++++ b/libc/sysdeps/linux/i386/getcontext.S +@@ -0,0 +1,84 @@ ++/* Save current context. ++ Copyright (C) 2001-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2001. ++ ++ 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ ++ENTRY(__getcontext) ++ /* Load address of the context data structure. */ ++ movl 4(%esp), %eax ++ ++ /* Return value of getcontext. EAX is the only register whose ++ value is not preserved. */ ++ movl $0, oEAX(%eax) ++ ++ /* Save the 32-bit register values and the return address. */ ++ movl %ecx, oECX(%eax) ++ movl %edx, oEDX(%eax) ++ movl %edi, oEDI(%eax) ++ movl %esi, oESI(%eax) ++ movl %ebp, oEBP(%eax) ++ movl (%esp), %ecx ++ movl %ecx, oEIP(%eax) ++ leal 4(%esp), %ecx /* Exclude the return address. */ ++ movl %ecx, oESP(%eax) ++ movl %ebx, oEBX(%eax) ++ ++ /* Save the FS segment register. We don't touch the GS register ++ since it is used for threads. */ ++ xorl %edx, %edx ++ movw %fs, %dx ++ movl %edx, oFS(%eax) ++ ++ /* We have separate floating-point register content memory on the ++ stack. We use the __fpregs_mem block in the context. Set the ++ links up correctly. */ ++ leal oFPREGSMEM(%eax), %ecx ++ movl %ecx, oFPREGS(%eax) ++ /* Save the floating-point context. */ ++ fnstenv (%ecx) ++ /* And load it right back since the processor changes the mask. ++ Intel thought this opcode to be used in interrupt handlers which ++ would block all exceptions. */ ++ fldenv (%ecx) ++ ++ /* Save the current signal mask. */ ++ pushl %ebx ++ cfi_adjust_cfa_offset (4) ++ cfi_rel_offset (ebx, 0) ++ leal oSIGMASK(%eax), %edx ++ xorl %ecx, %ecx ++ movl $SIG_BLOCK, %ebx ++ movl $__NR_sigprocmask, %eax ++ ENTER_KERNEL ++ popl %ebx ++ cfi_adjust_cfa_offset (-4) ++ cfi_restore (ebx) ++ cmpl $-4095, %eax /* Check %eax for error. */ ++ jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ ++ ++ /* All done, return 0 for success. */ ++ xorl %eax, %eax ++L(pseudo_end): ++ ret ++PSEUDO_END(__getcontext) ++ ++weak_alias (__getcontext, getcontext) +diff --git a/libc/sysdeps/linux/i386/makecontext.S b/libc/sysdeps/linux/i386/makecontext.S +new file mode 100644 +index 0000000..d12799d +--- /dev/null ++++ b/libc/sysdeps/linux/i386/makecontext.S +@@ -0,0 +1,123 @@ ++/* Create new context. ++ Copyright (C) 2001,2002,2005,2007,2008,2009 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2001. ++ ++ 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ ++ENTRY(__makecontext) ++ movl 4(%esp), %eax ++ ++ /* Load the address of the function we are supposed to run. */ ++ movl 8(%esp), %ecx ++ ++ /* Compute the address of the stack. The information comes from ++ to us_stack element. */ ++ movl oSS_SP(%eax), %edx ++ movl %ecx, oEIP(%eax) ++ addl oSS_SIZE(%eax), %edx ++ ++ /* Remember the number of parameters for the exit handler since ++ it has to remove them. We store the number in the EBX register ++ which the function we will call must preserve. */ ++ movl 12(%esp), %ecx ++ movl %ecx, oEBX(%eax) ++ ++ /* Make room on the new stack for the parameters. ++ Room for the arguments, return address (== L(exitcode)) and ++ oLINK pointer is needed. One of the pointer sizes is subtracted ++ after aligning the stack. */ ++ negl %ecx ++ leal -4(%edx,%ecx,4), %edx ++ negl %ecx ++ ++ /* Align the stack. */ ++ andl $0xfffffff0, %edx ++ subl $4, %edx ++ ++ /* Store the future stack pointer. */ ++ movl %edx, oESP(%eax) ++ ++ /* Put the next context on the new stack (from the uc_link ++ element). */ ++ movl oLINK(%eax), %eax ++ movl %eax, 4(%edx,%ecx,4) ++ ++ /* Copy all the parameters. */ ++ jecxz 2f ++1: movl 12(%esp,%ecx,4), %eax ++ movl %eax, (%edx,%ecx,4) ++ decl %ecx ++ jnz 1b ++2: ++ ++ /* If the function we call returns we must continue with the ++ context which is given in the uc_link element. To do this ++ set the return address for the function the user provides ++ to a little bit of helper code which does the magic (see ++ below). */ ++#ifdef __PIC__ ++ call 1f ++ cfi_adjust_cfa_offset (4) ++1: popl %ecx ++ cfi_adjust_cfa_offset (-4) ++ addl $L(exitcode)-1b, %ecx ++ movl %ecx, (%edx) ++#else ++ movl $L(exitcode), (%edx) ++#endif ++ /* 'makecontext' returns no value. */ ++L(pseudo_end): ++ ret ++ ++ /* This is the helper code which gets called if a function which ++ is registered with 'makecontext' returns. In this case we ++ have to install the context listed in the uc_link element of ++ the context 'makecontext' manipulated at the time of the ++ 'makecontext' call. If the pointer is NULL the process must ++ terminate. */ ++ cfi_endproc ++L(exitcode): ++ /* This removes the parameters passed to the function given to ++ 'makecontext' from the stack. EBX contains the number of ++ parameters (see above). */ ++ leal (%esp,%ebx,4), %esp ++ ++#ifdef __PIC__ ++ call 1f ++1: popl %ebx ++ addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx ++#endif ++ cmpl $0, (%esp) /* Check the next context. */ ++ je 2f /* If it is zero exit. */ ++ ++ call JUMPTARGET(__setcontext) ++ /* If this returns (which can happen if the syscall fails) we'll ++ exit the program with the return error value (-1). */ ++ ++ movl %eax, (%esp) ++2: call HIDDEN_JUMPTARGET(exit) ++ /* The 'exit' call should never return. In case it does cause ++ the process to terminate. */ ++ hlt ++ cfi_startproc ++END(__makecontext) ++ ++weak_alias (__makecontext, makecontext) +diff --git a/libc/sysdeps/linux/i386/setcontext.S b/libc/sysdeps/linux/i386/setcontext.S +new file mode 100644 +index 0000000..ae953cc +--- /dev/null ++++ b/libc/sysdeps/linux/i386/setcontext.S +@@ -0,0 +1,96 @@ ++/* Install given context. ++ Copyright (C) 2001-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2001. ++ ++ 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ ++ENTRY(__setcontext) ++ /* Load address of the context data structure. */ ++ movl 4(%esp), %eax ++ ++ /* Get the current signal mask. Note that we preserve EBX in case ++ the system call fails and we return from the function with an ++ error. */ ++ pushl %ebx ++ cfi_adjust_cfa_offset (4) ++ xorl %edx, %edx ++ leal oSIGMASK(%eax), %ecx ++ movl $SIG_SETMASK, %ebx ++ cfi_rel_offset (ebx, 0) ++ movl $__NR_sigprocmask, %eax ++ ENTER_KERNEL ++ popl %ebx ++ cfi_adjust_cfa_offset (-4) ++ cfi_restore (ebx) ++ cmpl $-4095, %eax /* Check %eax for error. */ ++ jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ ++ ++ /* EAX was modified, reload it. */ ++ movl 4(%esp), %eax ++ ++ /* Restore the floating-point context. Not the registers, only the ++ rest. */ ++ movl oFPREGS(%eax), %ecx ++ fldenv (%ecx) ++ ++ /* Restore the FS segment register. We don't touch the GS register ++ since it is used for threads. */ ++ movl oFS(%eax), %ecx ++ movw %cx, %fs ++ ++ /* Fetch the address to return to. */ ++ movl oEIP(%eax), %ecx ++ ++ /* Load the new stack pointer. */ ++ cfi_def_cfa (eax, 0) ++ cfi_offset (edi, oEDI) ++ cfi_offset (esi, oESI) ++ cfi_offset (ebp, oEBP) ++ cfi_offset (ebx, oEBX) ++ cfi_offset (edx, oEDX) ++ cfi_offset (ecx, oECX) ++ movl oESP(%eax), %esp ++ ++ /* Push the return address on the new stack so we can return there. */ ++ pushl %ecx ++ ++ /* Load the values of all the 32-bit registers (except ESP). ++ Since we are loading from EAX, it must be last. */ ++ movl oEDI(%eax), %edi ++ movl oESI(%eax), %esi ++ movl oEBP(%eax), %ebp ++ movl oEBX(%eax), %ebx ++ movl oEDX(%eax), %edx ++ movl oECX(%eax), %ecx ++ movl oEAX(%eax), %eax ++ ++ /* End FDE here, we fall into another context. */ ++ cfi_endproc ++ cfi_startproc ++ ++ /* The following 'ret' will pop the address of the code and jump ++ to it. */ ++ ++L(pseudo_end): ++ ret ++PSEUDO_END(__setcontext) ++ ++weak_alias (__setcontext, setcontext) +diff --git a/libc/sysdeps/linux/i386/swapcontext.S b/libc/sysdeps/linux/i386/swapcontext.S +new file mode 100644 +index 0000000..ee5d0e4 +--- /dev/null ++++ b/libc/sysdeps/linux/i386/swapcontext.S +@@ -0,0 +1,110 @@ ++/* Save current context and install the given one. ++ Copyright (C) 2001-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2001. ++ ++ 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ ++ENTRY(__swapcontext) ++ /* Load address of the context data structure we save in. */ ++ movl 4(%esp), %eax ++ ++ /* Return value of swapcontext. EAX is the only register whose ++ value is not preserved. */ ++ movl $0, oEAX(%eax) ++ ++ /* Save the 32-bit register values and the return address. */ ++ movl %ecx, oECX(%eax) ++ movl %edx, oEDX(%eax) ++ movl %edi, oEDI(%eax) ++ movl %esi, oESI(%eax) ++ movl %ebp, oEBP(%eax) ++ movl (%esp), %ecx ++ movl %ecx, oEIP(%eax) ++ leal 4(%esp), %ecx ++ movl %ecx, oESP(%eax) ++ movl %ebx, oEBX(%eax) ++ ++ /* Save the FS segment register. */ ++ xorl %edx, %edx ++ movw %fs, %dx ++ movl %edx, oFS(%eax) ++ ++ /* We have separate floating-point register content memory on the ++ stack. We use the __fpregs_mem block in the context. Set the ++ links up correctly. */ ++ leal oFPREGSMEM(%eax), %ecx ++ movl %ecx, oFPREGS(%eax) ++ /* Save the floating-point context. */ ++ fnstenv (%ecx) ++ ++ /* Load address of the context data structure we have to load. */ ++ movl 8(%esp), %ecx ++ ++ /* Save the current signal mask and install the new one. */ ++ pushl %ebx ++ leal oSIGMASK(%eax), %edx ++ leal oSIGMASK(%ecx), %ecx ++ movl $SIG_SETMASK, %ebx ++ movl $__NR_sigprocmask, %eax ++ ENTER_KERNEL ++ popl %ebx ++ cmpl $-4095, %eax /* Check %eax for error. */ ++ jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ ++ ++ /* EAX was modified, reload it. */ ++ movl 8(%esp), %eax ++ ++ /* Restore the floating-point context. Not the registers, only the ++ rest. */ ++ movl oFPREGS(%eax), %ecx ++ fldenv (%ecx) ++ ++ /* Restore the FS segment register. We don't touch the GS register ++ since it is used for threads. */ ++ movl oFS(%eax), %edx ++ movw %dx, %fs ++ ++ /* Fetch the address to return to. */ ++ movl oEIP(%eax), %ecx ++ ++ /* Load the new stack pointer. */ ++ movl oESP(%eax), %esp ++ ++ /* Push the return address on the new stack so we can return there. */ ++ pushl %ecx ++ ++ /* Load the values of all the 32-bit registers (except ESP). ++ Since we are loading from EAX, it must be last. */ ++ movl oEDI(%eax), %edi ++ movl oESI(%eax), %esi ++ movl oEBP(%eax), %ebp ++ movl oEBX(%eax), %ebx ++ movl oEDX(%eax), %edx ++ movl oECX(%eax), %ecx ++ movl oEAX(%eax), %eax ++ ++ /* The following 'ret' will pop the address of the code and jump ++ to it. */ ++L(pseudo_end): ++ ret ++PSEUDO_END(__swapcontext) ++ ++weak_alias (__swapcontext, swapcontext) +diff --git a/libc/sysdeps/linux/i386/ucontext_i.sym b/libc/sysdeps/linux/i386/ucontext_i.sym +new file mode 100644 +index 0000000..b11a550 +--- /dev/null ++++ b/libc/sysdeps/linux/i386/ucontext_i.sym +@@ -0,0 +1,30 @@ ++#include ++#include ++#include ++ ++-- ++ ++SIG_BLOCK ++SIG_SETMASK ++ ++#define ucontext(member) offsetof (ucontext_t, member) ++#define mcontext(member) ucontext (uc_mcontext.member) ++#define mreg(reg) mcontext (gregs[REG_##reg]) ++ ++oLINK ucontext (uc_link) ++oSS_SP ucontext (uc_stack.ss_sp) ++oSS_SIZE ucontext (uc_stack.ss_size) ++oGS mreg (GS) ++oFS mreg (FS) ++oEDI mreg (EDI) ++oESI mreg (ESI) ++oEBP mreg (EBP) ++oESP mreg (ESP) ++oEBX mreg (EBX) ++oEDX mreg (EDX) ++oECX mreg (ECX) ++oEAX mreg (EAX) ++oEIP mreg (EIP) ++oFPREGS mcontext (fpregs) ++oSIGMASK ucontext (uc_sigmask) ++oFPREGSMEM ucontext (__fpregs_mem) +diff --git a/libc/sysdeps/linux/mips/Makefile.arch b/libc/sysdeps/linux/mips/Makefile.arch +index fce99f8..00b9331 100644 +--- a/libc/sysdeps/linux/mips/Makefile.arch ++++ b/libc/sysdeps/linux/mips/Makefile.arch +@@ -27,3 +27,7 @@ ASFLAGS-syscall_error.S += -D_LIBC_REENTRANT + + ARCH_HEADERS := sgidefs.h + # regdef.h ++ ++ifeq ($(UCLIBC_HAS_CONTEXT_FUNCS),y) ++SSRC += makecontext.S setcontext.S getcontext.S swapcontext.S ++endif +diff --git a/libc/sysdeps/linux/mips/getcontext.S b/libc/sysdeps/linux/mips/getcontext.S +new file mode 100644 +index 0000000..c4ad081 +--- /dev/null ++++ b/libc/sysdeps/linux/mips/getcontext.S +@@ -0,0 +1,148 @@ ++/* Save current context. ++ Copyright (C) 2009 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Maciej W. Rozycki . ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ucontext_i.h" ++ ++/* int getcontext (ucontext_t *ucp) */ ++ ++ .text ++LOCALSZ = 0 ++MASK = 0x00000000 ++#ifdef __PIC__ ++LOCALSZ = 1 /* save gp */ ++# if _MIPS_SIM != _ABIO32 ++MASK = 0x10000000 ++# endif ++#endif ++FRAMESZ = ((LOCALSZ * SZREG) + ALSZ) & ALMASK ++GPOFF = FRAMESZ - (1 * SZREG) ++ ++NESTED (__getcontext, FRAMESZ, ra) ++ .mask MASK, 0 ++ .fmask 0x00000000, 0 ++ ++#ifdef __PIC__ ++ SETUP_GP ++ ++ move a2, sp ++# define _SP a2 ++ ++# if _MIPS_SIM != _ABIO32 ++ move a3, gp ++# define _GP a3 ++# endif ++ ++ PTR_ADDIU sp, -FRAMESZ ++ SETUP_GP64 (GPOFF, __getcontext) ++ SAVE_GP (GPOFF) ++ ++#else /* ! __PIC__ */ ++# define _SP sp ++# define _GP gp ++ ++#endif /* ! __PIC__ */ ++ ++#ifdef PROF ++ .set noat ++ move AT, ra ++ jal _mcount ++ .set at ++#endif ++ ++ /* Store a magic flag. */ ++ li v1, 1 ++ REG_S v1, (0 * SZREG + MCONTEXT_GREGS)(a0) /* zero */ ++ ++ REG_S s0, (16 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s1, (17 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s2, (18 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s3, (19 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s4, (20 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s5, (21 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s6, (22 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s7, (23 * SZREG + MCONTEXT_GREGS)(a0) ++#if ! defined (__PIC__) || _MIPS_SIM != _ABIO32 ++ REG_S _GP, (28 * SZREG + MCONTEXT_GREGS)(a0) ++#endif ++ REG_S _SP, (29 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S fp, (30 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S ra, (31 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S ra, MCONTEXT_PC(a0) ++ ++#ifdef __mips_hard_float ++# if _MIPS_SIM == _ABI64 ++ s.d fs0, (24 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs1, (25 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs2, (26 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs3, (27 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs5, (29 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs6, (30 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs7, (31 * SZREG + MCONTEXT_FPREGS)(a0) ++ ++# else /* _MIPS_SIM != _ABI64 */ ++ s.d fs0, (20 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs1, (22 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs2, (24 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs3, (26 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs5, (30 * SZREG + MCONTEXT_FPREGS)(a0) ++ ++# endif /* _MIPS_SIM != _ABI64 */ ++ ++ cfc1 v1, fcr31 ++ sw v1, MCONTEXT_FPC_CSR(a0) ++#endif /* __mips_hard_float */ ++ ++/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ ++ li a3, _NSIG8 ++ PTR_ADDU a2, a0, UCONTEXT_SIGMASK ++ move a1, zero ++ li a0, SIG_BLOCK ++ ++ li v0, SYS_ify (rt_sigprocmask) ++ syscall ++ bnez a3, 99f ++ ++#ifdef __PIC__ ++ RESTORE_GP64 ++ PTR_ADDIU sp, FRAMESZ ++#endif ++ move v0, zero ++ jr ra ++ ++99: ++#ifdef __PIC__ ++ PTR_LA t9, JUMPTARGET (__syscall_error) ++ RESTORE_GP64 ++ PTR_ADDIU sp, FRAMESZ ++ jr t9 ++ ++#else /* ! __PIC__ */ ++ ++ j JUMPTARGET (__syscall_error) ++#endif /* ! __PIC__ */ ++PSEUDO_END (__getcontext) ++ ++weak_alias (__getcontext, getcontext) +diff --git a/libc/sysdeps/linux/mips/kernel_rt_sigframe.h b/libc/sysdeps/linux/mips/kernel_rt_sigframe.h +new file mode 100644 +index 0000000..77ffaf6 +--- /dev/null ++++ b/libc/sysdeps/linux/mips/kernel_rt_sigframe.h +@@ -0,0 +1,10 @@ ++/* Linux kernel RT signal frame. */ ++typedef struct kernel_rt_sigframe ++ { ++ uint32_t rs_ass[4]; ++ uint32_t rs_code[2]; ++ siginfo_t rs_info; ++ struct ucontext rs_uc; ++ uint32_t rs_altcode[8] __attribute__ ((__aligned__ (1 << 7))); ++ } ++kernel_rt_sigframe_t; +diff --git a/libc/sysdeps/linux/mips/makecontext.S b/libc/sysdeps/linux/mips/makecontext.S +new file mode 100644 +index 0000000..6427339 +--- /dev/null ++++ b/libc/sysdeps/linux/mips/makecontext.S +@@ -0,0 +1,188 @@ ++/* Modify saved context. ++ Copyright (C) 2009 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Maciej W. Rozycki . ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ucontext_i.h" ++ ++/* int makecontext (ucontext_t *ucp, (void *func) (), int argc, ...) */ ++ ++ .text ++LOCALSZ = 0 ++ARGSZ = 0 ++MASK = 0x00000000 ++#ifdef __PIC__ ++LOCALSZ = 1 /* save gp */ ++#endif ++#if _MIPS_SIM != _ABIO32 ++ARGSZ = 5 /* save a3-a7 */ ++# ifdef __PIC__ ++MASK = 0x10000000 ++# endif ++#endif ++FRAMESZ = (((ARGSZ + LOCALSZ) * SZREG) + ALSZ) & ALMASK ++GPOFF = FRAMESZ - ((ARGSZ + 1) * SZREG) ++#if _MIPS_SIM != _ABIO32 ++A3OFF = FRAMESZ - (5 * SZREG) /* callee-allocated */ ++A4OFF = FRAMESZ - (4 * SZREG) ++A5OFF = FRAMESZ - (3 * SZREG) ++A6OFF = FRAMESZ - (2 * SZREG) ++A7OFF = FRAMESZ - (1 * SZREG) ++NARGREGS = 8 ++#else ++A3OFF = FRAMESZ + (3 * SZREG) /* caller-allocated */ ++NARGREGS = 4 ++#endif ++ ++NESTED (__makecontext, FRAMESZ, ra) ++ .mask MASK, -(ARGSZ * SZREG) ++ .fmask 0x00000000, 0 ++ ++98: ++#ifdef __PIC__ ++ SETUP_GP ++#endif ++ ++ PTR_ADDIU sp, -FRAMESZ ++ ++#ifdef __PIC__ ++ SETUP_GP64 (GPOFF, __makecontext) ++ SAVE_GP (GPOFF) ++#endif ++ ++#ifdef PROF ++ .set noat ++ move AT, ra ++ jal _mcount ++ .set at ++#endif ++ ++ /* Store args to be passed. */ ++ REG_S a3, A3OFF(sp) ++#if _MIPS_SIM != _ABIO32 ++ REG_S a4, A4OFF(sp) ++ REG_S a5, A5OFF(sp) ++ REG_S a6, A6OFF(sp) ++ REG_S a7, A7OFF(sp) ++#endif ++ ++ /* Store a magic flag. */ ++ li v1, 1 ++ REG_S v1, (0 * SZREG + MCONTEXT_GREGS)(a0) /* zero */ ++ ++ /* Set up the stack. */ ++ PTR_L t0, STACK_SP(a0) ++ PTR_L t2, STACK_SIZE(a0) ++ PTR_ADDIU t1, sp, A3OFF ++ PTR_ADDU t0, t2 ++ and t0, ALMASK ++ blez a2, 2f /* no arguments */ ++ ++ /* Store register arguments. */ ++ PTR_ADDIU t2, a0, MCONTEXT_GREGS + 4 * SZREG ++ move t3, zero ++0: ++ addiu t3, 1 ++ REG_L v1, (t1) ++ PTR_ADDIU t1, SZREG ++ REG_S v1, (t2) ++ PTR_ADDIU t2, SZREG ++ bgeu t3, a2, 2f /* all done */ ++ bltu t3, NARGREGS, 0b /* next */ ++ ++ /* Make room for stack arguments. */ ++ PTR_SUBU t2, a2, t3 ++ PTR_SLL t2, 3 ++ PTR_SUBU t0, t2 ++ and t0, ALMASK ++ ++ /* Store stack arguments. */ ++ move t2, t0 ++1: ++ addiu t3, 1 ++ REG_L v1, (t1) ++ PTR_ADDIU t1, SZREG ++ REG_S v1, (t2) ++ PTR_ADDIU t2, SZREG ++ bltu t3, a2, 1b /* next */ ++ ++2: ++#if _MIPS_SIM == _ABIO32 ++ /* Make room for a0-a3 storage. */ ++ PTR_ADDIU t0, -(NARGSAVE * SZREG) ++#endif ++ PTR_L v1, UCONTEXT_LINK(a0) ++#ifdef __PIC__ ++ PTR_ADDIU t9, 99f - 98b ++#else ++ PTR_LA t9, 99f ++#endif ++ REG_S t0, (29 * SZREG + MCONTEXT_GREGS)(a0) /* sp */ ++ REG_S v1, (16 * SZREG + MCONTEXT_GREGS)(a0) /* s0 */ ++#ifdef __PIC__ ++ REG_S gp, (17 * SZREG + MCONTEXT_GREGS)(a0) /* s1 */ ++#endif ++ REG_S t9, (31 * SZREG + MCONTEXT_GREGS)(a0) /* ra */ ++ REG_S a1, MCONTEXT_PC(a0) ++ ++#ifdef __PIC__ ++ RESTORE_GP64 ++ PTR_ADDIU sp, FRAMESZ ++#endif ++ jr ra ++ ++99: ++#ifdef __PIC__ ++ move gp, s1 ++#endif ++ move a0, zero ++ beqz s0, 0f ++ ++ /* setcontext (ucp) */ ++ move a0, s0 ++#ifdef __PIC__ ++ PTR_LA t9, JUMPTARGET (__setcontext) ++ jalr t9 ++# if _MIPS_SIM == _ABIO32 ++ move gp, s1 ++# endif ++#else ++ jal JUMPTARGET (__setcontext) ++#endif ++ move a0, v0 ++ ++0: ++ /* exit (a0) */ ++#ifdef __PIC__ ++ PTR_LA t9, HIDDEN_JUMPTARGET (exit) ++ jalr t9 ++#else ++ jal HIDDEN_JUMPTARGET (exit) ++#endif ++ ++ /* You don't exist, you won't feel anything. */ ++1: ++ lb zero, (zero) ++ b 1b ++PSEUDO_END (__makecontext) ++ ++weak_alias (__makecontext, makecontext) +diff --git a/libc/sysdeps/linux/mips/setcontext.S b/libc/sysdeps/linux/mips/setcontext.S +new file mode 100644 +index 0000000..d3cde0e +--- /dev/null ++++ b/libc/sysdeps/linux/mips/setcontext.S +@@ -0,0 +1,191 @@ ++/* Set current context. ++ Copyright (C) 2009 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Maciej W. Rozycki . ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ucontext_i.h" ++ ++/* int setcontext (const ucontext_t *ucp) */ ++ ++ .text ++LOCALSZ = 0 ++ARGSZ = 0 ++MASK = 0x00000000 ++#ifdef __PIC__ ++LOCALSZ = 1 /* save gp */ ++#endif ++#if _MIPS_SIM != _ABIO32 ++ARGSZ = 1 /* save a0 */ ++# ifdef __PIC__ ++MASK = 0x10000000 ++# endif ++#endif ++FRAMESZ = (((ARGSZ + LOCALSZ) * SZREG) + ALSZ) & ALMASK ++GPOFF = FRAMESZ - ((ARGSZ + 1) * SZREG) ++#if _MIPS_SIM != _ABIO32 ++A0OFF = FRAMESZ - (1 * SZREG) /* callee-allocated */ ++#else ++A0OFF = FRAMESZ + (0 * SZREG) /* caller-allocated */ ++#endif ++ ++NESTED (__setcontext, FRAMESZ, ra) ++ .mask MASK, -(ARGSZ * SZREG) ++ .fmask 0x00000000, 0 ++ ++#ifdef __PIC__ ++ SETUP_GP ++#endif ++ ++ PTR_ADDIU sp, -FRAMESZ ++ ++#ifdef __PIC__ ++ SETUP_GP64 (GPOFF, __setcontext) ++ SAVE_GP (GPOFF) ++#endif ++ ++#ifdef PROF ++ .set noat ++ move AT, ra ++ jal _mcount ++ .set at ++#endif ++ ++ /* Check for the magic flag. */ ++ li v0, 1 ++ REG_L v1, (0 * SZREG + MCONTEXT_GREGS)(a0) /* zero */ ++ bne v0, v1, 98f ++ ++ REG_S a0, A0OFF(sp) ++ ++/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */ ++ li a3, _NSIG8 ++ move a2, zero ++ PTR_ADDU a1, a0, UCONTEXT_SIGMASK ++ li a0, SIG_SETMASK ++ ++ li v0, SYS_ify (rt_sigprocmask) ++ syscall ++ bnez a3, 99f ++ ++ REG_L v0, A0OFF(sp) ++ ++#ifdef __mips_hard_float ++# if _MIPS_SIM == _ABI64 ++ l.d fs0, (24 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs1, (25 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs2, (26 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs3, (27 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs5, (29 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs6, (30 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs7, (31 * SZREG + MCONTEXT_FPREGS)(v0) ++ ++# else /* _MIPS_SIM != _ABI64 */ ++ l.d fs0, (20 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs1, (22 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs2, (24 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs3, (26 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs5, (30 * SZREG + MCONTEXT_FPREGS)(v0) ++ ++# endif /* _MIPS_SIM != _ABI64 */ ++ ++ lw v1, MCONTEXT_FPC_CSR(v0) ++ ctc1 v1, fcr31 ++#endif /* __mips_hard_float */ ++ ++ /* Note the contents of argument registers will be random ++ unless makecontext() has been called. */ ++ REG_L a0, (4 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a1, (5 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a2, (6 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a3, (7 * SZREG + MCONTEXT_GREGS)(v0) ++#if _MIPS_SIM != _ABIO32 ++ REG_L a4, (8 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a5, (9 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a6, (10 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a7, (11 * SZREG + MCONTEXT_GREGS)(v0) ++#endif ++ ++ REG_L s0, (16 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s1, (17 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s2, (18 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s3, (19 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s4, (20 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s5, (21 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s6, (22 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s7, (23 * SZREG + MCONTEXT_GREGS)(v0) ++#if ! defined (__PIC__) || _MIPS_SIM != _ABIO32 ++ REG_L gp, (28 * SZREG + MCONTEXT_GREGS)(v0) ++#endif ++ REG_L sp, (29 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L fp, (30 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L ra, (31 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L t9, MCONTEXT_PC(v0) ++ ++ move v0, zero ++ jr t9 ++ ++98: ++ /* This is a context obtained from a signal handler. ++ Perform a full restore by pushing the context ++ passed onto a simulated signal frame on the stack ++ and call the signal return syscall as if a signal ++ handler exited normally. */ ++ PTR_ADDIU sp, -((RT_SIGFRAME_SIZE + ALSZ) & ALMASK) ++ ++ /* Only ucontext is referred to from rt_sigreturn, ++ copy it. */ ++ PTR_ADDIU t1, sp, RT_SIGFRAME_UCONTEXT ++ li t3, ((UCONTEXT_SIZE + SZREG - 1) / SZREG) - 1 ++0: ++ REG_L t2, (a0) ++ PTR_ADDIU a0, SZREG ++ REG_S t2, (t1) ++ PTR_ADDIU t1, SZREG ++ .set noreorder ++ bgtz t3, 0b ++ addiu t3, -1 ++ .set reorder ++ ++/* rt_sigreturn () -- no arguments, sp points to struct rt_sigframe. */ ++ li v0, SYS_ify (rt_sigreturn) ++ syscall ++ ++ /* Restore the stack and fall through to the error ++ path. Successful rt_sigreturn never returns to ++ its calling place. */ ++ PTR_ADDIU sp, ((RT_SIGFRAME_SIZE + ALSZ) & ALMASK) ++99: ++#ifdef __PIC__ ++ PTR_LA t9, JUMPTARGET (__syscall_error) ++ RESTORE_GP64 ++ PTR_ADDIU sp, FRAMESZ ++ jr t9 ++ ++#else /* ! __PIC__ */ ++ ++ j JUMPTARGET (__syscall_error) ++#endif /* ! __PIC__ */ ++PSEUDO_END (__setcontext) ++ ++weak_alias (__setcontext, setcontext) +diff --git a/libc/sysdeps/linux/mips/swapcontext.S b/libc/sysdeps/linux/mips/swapcontext.S +new file mode 100644 +index 0000000..c7ac19b +--- /dev/null ++++ b/libc/sysdeps/linux/mips/swapcontext.S +@@ -0,0 +1,211 @@ ++/* Save and set current context. ++ Copyright (C) 2009 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Maciej W. Rozycki . ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ucontext_i.h" ++ ++/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */ ++ ++ .text ++LOCALSZ = 0 ++ARGSZ = 0 ++MASK = 0x00000000 ++#ifdef __PIC__ ++LOCALSZ = 1 /* save gp */ ++#endif ++#if _MIPS_SIM != _ABIO32 ++ARGSZ = 1 /* save a1 */ ++# ifdef __PIC__ ++MASK = 0x10000000 ++# endif ++#endif ++FRAMESZ = (((ARGSZ + LOCALSZ) * SZREG) + ALSZ) & ALMASK ++GPOFF = FRAMESZ - ((ARGSZ + 1) * SZREG) ++#if _MIPS_SIM != _ABIO32 ++A1OFF = FRAMESZ - (1 * SZREG) /* callee-allocated */ ++#else ++A1OFF = FRAMESZ + (1 * SZREG) /* caller-allocated */ ++#endif ++ ++NESTED (__swapcontext, FRAMESZ, ra) ++ .mask MASK, -(ARGSZ * SZREG) ++ .fmask 0x00000000, 0 ++ ++#ifdef __PIC__ ++ SETUP_GP ++ ++ move a2, sp ++# define _SP a2 ++ ++# if _MIPS_SIM != _ABIO32 ++ move a3, gp ++# define _GP a3 ++# endif ++ ++ PTR_ADDIU sp, -FRAMESZ ++ SETUP_GP64 (GPOFF, __swapcontext) ++ SAVE_GP (GPOFF) ++ ++#else /* ! __PIC__ */ ++# define _SP sp ++# define _GP gp ++ ++#endif /* ! __PIC__ */ ++ ++#ifdef PROF ++ .set noat ++ move AT, ra ++ jal _mcount ++ .set at ++#endif ++ ++ /* Store a magic flag. */ ++ li v1, 1 ++ REG_S v1, (0 * SZREG + MCONTEXT_GREGS)(a0) /* zero */ ++ ++ REG_S s0, (16 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s1, (17 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s2, (18 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s3, (19 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s4, (20 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s5, (21 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s6, (22 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S s7, (23 * SZREG + MCONTEXT_GREGS)(a0) ++#if ! defined (__PIC__) || _MIPS_SIM != _ABIO32 ++ REG_S _GP, (28 * SZREG + MCONTEXT_GREGS)(a0) ++#endif ++ REG_S _SP, (29 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S fp, (30 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S ra, (31 * SZREG + MCONTEXT_GREGS)(a0) ++ REG_S ra, MCONTEXT_PC(a0) ++ ++#ifdef __mips_hard_float ++# if _MIPS_SIM == _ABI64 ++ s.d fs0, (24 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs1, (25 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs2, (26 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs3, (27 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs5, (29 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs6, (30 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs7, (31 * SZREG + MCONTEXT_FPREGS)(a0) ++ ++# else /* _MIPS_SIM != _ABI64 */ ++ s.d fs0, (20 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs1, (22 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs2, (24 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs3, (26 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(a0) ++ s.d fs5, (30 * SZREG + MCONTEXT_FPREGS)(a0) ++ ++# endif /* _MIPS_SIM != _ABI64 */ ++ ++ cfc1 v1, fcr31 ++ sw v1, MCONTEXT_FPC_CSR(a0) ++#endif /* __mips_hard_float */ ++ ++ REG_S a1, A1OFF(sp) ++ ++/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, _NSIG8) */ ++ li a3, _NSIG8 ++ PTR_ADDU a2, a0, UCONTEXT_SIGMASK ++ PTR_ADDU a1, a1, UCONTEXT_SIGMASK ++ li a0, SIG_SETMASK ++ ++ li v0, SYS_ify (rt_sigprocmask) ++ syscall ++ bnez a3, 99f ++ ++ REG_L v0, A1OFF(sp) ++ ++#ifdef __mips_hard_float ++# if _MIPS_SIM == _ABI64 ++ l.d fs0, (24 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs1, (25 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs2, (26 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs3, (27 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs5, (29 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs6, (30 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs7, (31 * SZREG + MCONTEXT_FPREGS)(v0) ++ ++# else /* _MIPS_SIM != _ABI64 */ ++ l.d fs0, (20 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs1, (22 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs2, (24 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs3, (26 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs4, (28 * SZREG + MCONTEXT_FPREGS)(v0) ++ l.d fs5, (30 * SZREG + MCONTEXT_FPREGS)(v0) ++ ++# endif /* _MIPS_SIM != _ABI64 */ ++ ++ lw v1, MCONTEXT_FPC_CSR(v0) ++ ctc1 v1, fcr31 ++#endif /* __mips_hard_float */ ++ ++ /* Note the contents of argument registers will be random ++ unless makecontext() has been called. */ ++ REG_L a0, (4 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a1, (5 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a2, (6 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a3, (7 * SZREG + MCONTEXT_GREGS)(v0) ++#if _MIPS_SIM != _ABIO32 ++ REG_L a4, (8 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a5, (9 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a6, (10 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L a7, (11 * SZREG + MCONTEXT_GREGS)(v0) ++#endif ++ ++ REG_L s0, (16 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s1, (17 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s2, (18 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s3, (19 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s4, (20 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s5, (21 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s6, (22 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L s7, (23 * SZREG + MCONTEXT_GREGS)(v0) ++#if ! defined (__PIC__) || _MIPS_SIM != _ABIO32 ++ REG_L gp, (28 * SZREG + MCONTEXT_GREGS)(v0) ++#endif ++ REG_L sp, (29 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L fp, (30 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L ra, (31 * SZREG + MCONTEXT_GREGS)(v0) ++ REG_L t9, MCONTEXT_PC(v0) ++ ++ move v0, zero ++ jr t9 ++ ++99: ++#ifdef __PIC__ ++ PTR_LA t9, JUMPTARGET (__syscall_error) ++ RESTORE_GP64 ++ PTR_ADDIU sp, FRAMESZ ++ jr t9 ++ ++#else /* ! __PIC__ */ ++ ++ j JUMPTARGET (__syscall_error) ++#endif /* ! __PIC__ */ ++PSEUDO_END (__swapcontext) ++ ++weak_alias (__swapcontext, swapcontext) +diff --git a/libc/sysdeps/linux/mips/ucontext_i.sym b/libc/sysdeps/linux/mips/ucontext_i.sym +new file mode 100644 +index 0000000..f14b886 +--- /dev/null ++++ b/libc/sysdeps/linux/mips/ucontext_i.sym +@@ -0,0 +1,52 @@ ++#include ++#include ++#include ++#include ++ ++#include ++ ++-- Constants used by the rt_sigprocmask call. ++ ++SIG_BLOCK ++SIG_SETMASK ++ ++_NSIG8 (_NSIG / 8) ++ ++-- Offsets of the fields in the kernel rt_sigframe_t structure. ++#define rt_sigframe(member) offsetof (kernel_rt_sigframe_t, member) ++ ++RT_SIGFRAME_UCONTEXT rt_sigframe (rs_uc) ++ ++RT_SIGFRAME_SIZE sizeof (kernel_rt_sigframe_t) ++ ++-- Offsets of the fields in the ucontext_t structure. ++#define ucontext(member) offsetof (ucontext_t, member) ++#define stack(member) ucontext (uc_stack.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) ++ ++STACK_SP stack (ss_sp) ++STACK_SIZE stack (ss_size) ++STACK_FLAGS stack (ss_flags) ++ ++MCONTEXT_GREGS mcontext (gregs) ++MCONTEXT_FPREGS mcontext (fpregs) ++MCONTEXT_MDHI mcontext (mdhi) ++MCONTEXT_HI1 mcontext (hi1) ++MCONTEXT_HI2 mcontext (hi2) ++MCONTEXT_HI3 mcontext (hi3) ++MCONTEXT_MDLO mcontext (mdlo) ++MCONTEXT_LO1 mcontext (lo1) ++MCONTEXT_LO2 mcontext (lo2) ++MCONTEXT_LO3 mcontext (lo3) ++MCONTEXT_PC mcontext (pc) ++MCONTEXT_FPC_CSR mcontext (fpc_csr) ++MCONTEXT_USED_MATH mcontext (used_math) ++MCONTEXT_DSP mcontext (dsp) ++ ++UCONTEXT_SIZE sizeof (ucontext_t) +diff --git a/libc/sysdeps/linux/x86_64/Makefile.arch b/libc/sysdeps/linux/x86_64/Makefile.arch +index 7491d92..93b8259 100644 +--- a/libc/sysdeps/linux/x86_64/Makefile.arch ++++ b/libc/sysdeps/linux/x86_64/Makefile.arch +@@ -20,3 +20,8 @@ ifeq ($(UCLIBC_HAS_TLS),y) + SSRC += sched_getcpu.S + endif + endif ++ ++ifeq ($(UCLIBC_HAS_CONTEXT_FUNCS),y) ++CSRC += makecontext.c ++SSRC += setcontext.S getcontext.S swapcontext.S __start_context.S ++endif +diff --git a/libc/sysdeps/linux/x86_64/__start_context.S b/libc/sysdeps/linux/x86_64/__start_context.S +new file mode 100644 +index 0000000..9f2ee23 +--- /dev/null ++++ b/libc/sysdeps/linux/x86_64/__start_context.S +@@ -0,0 +1,49 @@ ++/* Copyright (C) 2002-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Andreas Jaeger , 2002. ++ ++ 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 ++ . */ ++ ++#include ++ ++/* This is the helper code which gets called if a function which is ++ registered with 'makecontext' returns. In this case we have to ++ install the context listed in the uc_link element of the context ++ 'makecontext' manipulated at the time of the 'makecontext' call. ++ If the pointer is NULL the process must terminate. */ ++ ++ ++ENTRY(__start_context) ++ /* This removes the parameters passed to the function given to ++ 'makecontext' from the stack. RBX contains the address ++ on the stack pointer for the next context. */ ++ movq %rbx, %rsp ++ ++ popq %rdi /* This is the next context. */ ++ cfi_adjust_cfa_offset(-8) ++ testq %rdi, %rdi ++ je 2f /* If it is zero exit. */ ++ ++ call JUMPTARGET(__setcontext) ++ /* If this returns (which can happen if the syscall fails) we'll ++ exit the program with the return error value (-1). */ ++ movq %rax,%rdi ++ ++2: ++ call HIDDEN_JUMPTARGET(exit) ++ /* The 'exit' call should never return. In case it does cause ++ the process to terminate. */ ++ hlt ++END(__start_context) +diff --git a/libc/sysdeps/linux/x86_64/getcontext.S b/libc/sysdeps/linux/x86_64/getcontext.S +new file mode 100644 +index 0000000..dcebc4f +--- /dev/null ++++ b/libc/sysdeps/linux/x86_64/getcontext.S +@@ -0,0 +1,88 @@ ++/* Save current context. ++ Copyright (C) 2002-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Andreas Jaeger , 2002. ++ ++ 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++/* int __getcontext (ucontext_t *ucp) ++ ++ Saves the machine context in UCP such that when it is activated, ++ it appears as if __getcontext() returned again. ++ ++ This implementation is intended to be used for *synchronous* context ++ switches only. Therefore, it does not have to save anything ++ other than the PRESERVED state. */ ++ ++ ++ENTRY(__getcontext) ++ /* Save the preserved registers, the registers used for passing ++ args, and the return address. */ ++ movq %rbx, oRBX(%rdi) ++ movq %rbp, oRBP(%rdi) ++ movq %r12, oR12(%rdi) ++ movq %r13, oR13(%rdi) ++ movq %r14, oR14(%rdi) ++ movq %r15, oR15(%rdi) ++ ++ movq %rdi, oRDI(%rdi) ++ movq %rsi, oRSI(%rdi) ++ movq %rdx, oRDX(%rdi) ++ movq %rcx, oRCX(%rdi) ++ movq %r8, oR8(%rdi) ++ movq %r9, oR9(%rdi) ++ ++ movq (%rsp), %rcx ++ movq %rcx, oRIP(%rdi) ++ leaq 8(%rsp), %rcx /* Exclude the return address. */ ++ movq %rcx, oRSP(%rdi) ++ ++ /* We have separate floating-point register content memory on the ++ stack. We use the __fpregs_mem block in the context. Set the ++ links up correctly. */ ++ ++ leaq oFPREGSMEM(%rdi), %rcx ++ movq %rcx, oFPREGS(%rdi) ++ /* Save the floating-point environment. */ ++ fnstenv (%rcx) ++ fldenv (%rcx) ++ stmxcsr oMXCSR(%rdi) ++ ++ /* Save the current signal mask with ++ rt_sigprocmask (SIG_BLOCK, NULL, set,_NSIG/8). */ ++ leaq oSIGMASK(%rdi), %rdx ++ xorl %esi,%esi ++#if SIG_BLOCK == 0 ++ xorl %edi, %edi ++#else ++ movl $SIG_BLOCK, %edi ++#endif ++ movl $_NSIG8,%r10d ++ movl $__NR_rt_sigprocmask, %eax ++ syscall ++ cmpq $-4095, %rax /* Check %rax for error. */ ++ jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ ++ ++ /* All done, return 0 for success. */ ++ xorl %eax, %eax ++L(pseudo_end): ++ ret ++PSEUDO_END(__getcontext) ++ ++weak_alias (__getcontext, getcontext) +diff --git a/libc/sysdeps/linux/x86_64/makecontext.c b/libc/sysdeps/linux/x86_64/makecontext.c +new file mode 100644 +index 0000000..5473031 +--- /dev/null ++++ b/libc/sysdeps/linux/x86_64/makecontext.c +@@ -0,0 +1,121 @@ ++/* Create new context. ++ Copyright (C) 2002, 2004, 2005, 2008 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Andreas Jaeger , 2002. ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ucontext_i.h" ++ ++/* This implementation can handle any ARGC value but only ++ normal integer parameters. ++ makecontext sets up a stack and the registers for the ++ user context. The stack looks like this: ++ +-----------------------+ ++ | next context | ++ +-----------------------+ ++ | parameter 7-n | ++ +-----------------------+ ++ | trampoline address | ++ %rsp -> +-----------------------+ ++ ++ The registers are set up like this: ++ %rdi,%rsi,%rdx,%rcx,%r8,%r9: parameter 1 to 6 ++ %rbx : address of next context ++ %rsp : stack pointer. ++*/ ++ ++/* XXX: This implementation currently only handles integer arguments. ++ To handle long int and pointer arguments the va_arg arguments needs ++ to be changed to long and also the stdlib/tst-setcontext.c file needs ++ to be changed to pass long arguments to makecontext. */ ++ ++ ++void ++__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) ++{ ++ extern void __start_context (void); ++ greg_t *sp; ++ unsigned int idx_uc_link; ++ va_list ap; ++ int i; ++ ++ /* Generate room on stack for parameter if needed and uc_link. */ ++ sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp ++ + ucp->uc_stack.ss_size); ++ sp -= (argc > 6 ? argc - 6 : 0) + 1; ++ /* Align stack and make space for trampoline address. */ ++ sp = (greg_t *) ((((uintptr_t) sp) & -16L) - 8); ++ ++ idx_uc_link = (argc > 6 ? argc - 6 : 0) + 1; ++ ++ /* Setup context ucp. */ ++ /* Address to jump to. */ ++ ucp->uc_mcontext.gregs[REG_RIP] = (uintptr_t) func; ++ /* Setup rbx.*/ ++ ucp->uc_mcontext.gregs[REG_RBX] = (uintptr_t) &sp[idx_uc_link]; ++ ucp->uc_mcontext.gregs[REG_RSP] = (uintptr_t) sp; ++ ++ /* Setup stack. */ ++ sp[0] = (uintptr_t) &__start_context; ++ sp[idx_uc_link] = (uintptr_t) ucp->uc_link; ++ ++ va_start (ap, argc); ++ /* Handle arguments. ++ ++ The standard says the parameters must all be int values. This is ++ an historic accident and would be done differently today. For ++ x86-64 all integer values are passed as 64-bit values and ++ therefore extending the API to copy 64-bit values instead of ++ 32-bit ints makes sense. It does not break existing ++ functionality and it does not violate the standard which says ++ that passing non-int values means undefined behavior. */ ++ for (i = 0; i < argc; ++i) ++ switch (i) ++ { ++ case 0: ++ ucp->uc_mcontext.gregs[REG_RDI] = va_arg (ap, greg_t); ++ break; ++ case 1: ++ ucp->uc_mcontext.gregs[REG_RSI] = va_arg (ap, greg_t); ++ break; ++ case 2: ++ ucp->uc_mcontext.gregs[REG_RDX] = va_arg (ap, greg_t); ++ break; ++ case 3: ++ ucp->uc_mcontext.gregs[REG_RCX] = va_arg (ap, greg_t); ++ break; ++ case 4: ++ ucp->uc_mcontext.gregs[REG_R8] = va_arg (ap, greg_t); ++ break; ++ case 5: ++ ucp->uc_mcontext.gregs[REG_R9] = va_arg (ap, greg_t); ++ break; ++ default: ++ /* Put value on stack. */ ++ sp[i - 5] = va_arg (ap, greg_t); ++ break; ++ } ++ va_end (ap); ++ ++} ++ ++ ++weak_alias (__makecontext, makecontext) +diff --git a/libc/sysdeps/linux/x86_64/setcontext.S b/libc/sysdeps/linux/x86_64/setcontext.S +new file mode 100644 +index 0000000..561ab9f +--- /dev/null ++++ b/libc/sysdeps/linux/x86_64/setcontext.S +@@ -0,0 +1,103 @@ ++/* Install given context. ++ Copyright (C) 2002-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Andreas Jaeger , 2002. ++ ++ 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ ++/* int __setcontext (const ucontext_t *ucp) ++ ++ Restores the machine context in UCP and thereby resumes execution ++ in that context. ++ ++ This implementation is intended to be used for *synchronous* context ++ switches only. Therefore, it does not have to restore anything ++ other than the PRESERVED state. */ ++ ++ENTRY(__setcontext) ++ /* Save argument since syscall will destroy it. */ ++ pushq %rdi ++ cfi_adjust_cfa_offset(8) ++ ++ /* Set the signal mask with ++ rt_sigprocmask (SIG_SETMASK, mask, NULL, _NSIG/8). */ ++ leaq oSIGMASK(%rdi), %rsi ++ xorl %edx, %edx ++ movl $SIG_SETMASK, %edi ++ movl $_NSIG8,%r10d ++ movl $__NR_rt_sigprocmask, %eax ++ syscall ++ popq %rdi /* Reload %rdi, adjust stack. */ ++ cfi_adjust_cfa_offset(-8) ++ cmpq $-4095, %rax /* Check %rax for error. */ ++ jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ ++ ++ /* Restore the floating-point context. Not the registers, only the ++ rest. */ ++ movq oFPREGS(%rdi), %rcx ++ fldenv (%rcx) ++ ldmxcsr oMXCSR(%rdi) ++ ++ ++ /* Load the new stack pointer, the preserved registers and ++ registers used for passing args. */ ++ cfi_def_cfa(%rdi, 0) ++ cfi_offset(%rbx,oRBX) ++ cfi_offset(%rbp,oRBP) ++ cfi_offset(%r12,oR12) ++ cfi_offset(%r13,oR13) ++ cfi_offset(%r14,oR14) ++ cfi_offset(%r15,oR15) ++ cfi_offset(%rsp,oRSP) ++ cfi_offset(%rip,oRIP) ++ ++ movq oRSP(%rdi), %rsp ++ movq oRBX(%rdi), %rbx ++ movq oRBP(%rdi), %rbp ++ movq oR12(%rdi), %r12 ++ movq oR13(%rdi), %r13 ++ movq oR14(%rdi), %r14 ++ movq oR15(%rdi), %r15 ++ ++ /* The following ret should return to the address set with ++ getcontext. Therefore push the address on the stack. */ ++ movq oRIP(%rdi), %rcx ++ pushq %rcx ++ ++ movq oRSI(%rdi), %rsi ++ movq oRDX(%rdi), %rdx ++ movq oRCX(%rdi), %rcx ++ movq oR8(%rdi), %r8 ++ movq oR9(%rdi), %r9 ++ ++ /* Setup finally %rdi. */ ++ movq oRDI(%rdi), %rdi ++ ++ /* End FDE here, we fall into another context. */ ++ cfi_endproc ++ cfi_startproc ++ ++ /* Clear rax to indicate success. */ ++ xorl %eax, %eax ++L(pseudo_end): ++ ret ++PSEUDO_END(__setcontext) ++ ++weak_alias (__setcontext, setcontext) +diff --git a/libc/sysdeps/linux/x86_64/swapcontext.S b/libc/sysdeps/linux/x86_64/swapcontext.S +new file mode 100644 +index 0000000..6d2ebb8 +--- /dev/null ++++ b/libc/sysdeps/linux/x86_64/swapcontext.S +@@ -0,0 +1,121 @@ ++/* Save current context and install the given one. ++ Copyright (C) 2002-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Andreas Jaeger , 2002. ++ ++ 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 ++ . */ ++ ++#include ++ ++#include "ucontext_i.h" ++ ++ ++/* int __swapcontext (ucontext_t *oucp, const ucontext_t *ucp); ++ ++ Saves the machine context in oucp such that when it is activated, ++ it appears as if __swapcontextt() returned again, restores the ++ machine context in ucp and thereby resumes execution in that ++ context. ++ ++ This implementation is intended to be used for *synchronous* context ++ switches only. Therefore, it does not have to save anything ++ other than the PRESERVED state. */ ++ ++ENTRY(__swapcontext) ++ /* Save the preserved registers, the registers used for passing args, ++ and the return address. */ ++ movq %rbx, oRBX(%rdi) ++ movq %rbp, oRBP(%rdi) ++ movq %r12, oR12(%rdi) ++ movq %r13, oR13(%rdi) ++ movq %r14, oR14(%rdi) ++ movq %r15, oR15(%rdi) ++ ++ movq %rdi, oRDI(%rdi) ++ movq %rsi, oRSI(%rdi) ++ movq %rdx, oRDX(%rdi) ++ movq %rcx, oRCX(%rdi) ++ movq %r8, oR8(%rdi) ++ movq %r9, oR9(%rdi) ++ ++ movq (%rsp), %rcx ++ movq %rcx, oRIP(%rdi) ++ leaq 8(%rsp), %rcx /* Exclude the return address. */ ++ movq %rcx, oRSP(%rdi) ++ ++ /* We have separate floating-point register content memory on the ++ stack. We use the __fpregs_mem block in the context. Set the ++ links up correctly. */ ++ leaq oFPREGSMEM(%rdi), %rcx ++ movq %rcx, oFPREGS(%rdi) ++ /* Save the floating-point environment. */ ++ fnstenv (%rcx) ++ stmxcsr oMXCSR(%rdi) ++ ++ ++ /* The syscall destroys some registers, save them. */ ++ movq %rsi, %r12 ++ ++ /* Save the current signal mask and install the new one with ++ rt_sigprocmask (SIG_BLOCK, newset, oldset,_NSIG/8). */ ++ leaq oSIGMASK(%rdi), %rdx ++ leaq oSIGMASK(%rsi), %rsi ++ movl $SIG_SETMASK, %edi ++ movl $_NSIG8,%r10d ++ movl $__NR_rt_sigprocmask, %eax ++ syscall ++ cmpq $-4095, %rax /* Check %rax for error. */ ++ jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */ ++ ++ /* Restore destroyed registers. */ ++ movq %r12, %rsi ++ ++ /* Restore the floating-point context. Not the registers, only the ++ rest. */ ++ movq oFPREGS(%rsi), %rcx ++ fldenv (%rcx) ++ ldmxcsr oMXCSR(%rsi) ++ ++ /* Load the new stack pointer and the preserved registers. */ ++ movq oRSP(%rsi), %rsp ++ movq oRBX(%rsi), %rbx ++ movq oRBP(%rsi), %rbp ++ movq oR12(%rsi), %r12 ++ movq oR13(%rsi), %r13 ++ movq oR14(%rsi), %r14 ++ movq oR15(%rsi), %r15 ++ ++ /* The following ret should return to the address set with ++ getcontext. Therefore push the address on the stack. */ ++ movq oRIP(%rsi), %rcx ++ pushq %rcx ++ ++ /* Setup registers used for passing args. */ ++ movq oRDI(%rsi), %rdi ++ movq oRDX(%rsi), %rdx ++ movq oRCX(%rsi), %rcx ++ movq oR8(%rsi), %r8 ++ movq oR9(%rsi), %r9 ++ ++ /* Setup finally %rsi. */ ++ movq oRSI(%rsi), %rsi ++ ++ /* Clear rax to indicate success. */ ++ xorl %eax, %eax ++L(pseudo_end): ++ ret ++PSEUDO_END(__swapcontext) ++ ++weak_alias (__swapcontext, swapcontext) +diff --git a/libc/sysdeps/linux/x86_64/ucontext_i.sym b/libc/sysdeps/linux/x86_64/ucontext_i.sym +new file mode 100644 +index 0000000..af3e0e5 +--- /dev/null ++++ b/libc/sysdeps/linux/x86_64/ucontext_i.sym +@@ -0,0 +1,37 @@ ++#include ++#include ++#include ++ ++-- ++ ++SIG_BLOCK ++SIG_SETMASK ++ ++_NSIG8 (_NSIG / 8) ++ ++#define ucontext(member) offsetof (ucontext_t, member) ++#define mcontext(member) ucontext (uc_mcontext.member) ++#define mreg(reg) mcontext (gregs[REG_##reg]) ++ ++oRBP mreg (RBP) ++oRSP mreg (RSP) ++oRBX mreg (RBX) ++oR8 mreg (R8) ++oR9 mreg (R9) ++oR10 mreg (R10) ++oR11 mreg (R11) ++oR12 mreg (R12) ++oR13 mreg (R13) ++oR14 mreg (R14) ++oR15 mreg (R15) ++oRDI mreg (RDI) ++oRSI mreg (RSI) ++oRDX mreg (RDX) ++oRAX mreg (RAX) ++oRCX mreg (RCX) ++oRIP mreg (RIP) ++oEFL mreg (EFL) ++oFPREGS mcontext (fpregs) ++oSIGMASK ucontext (uc_sigmask) ++oFPREGSMEM ucontext (__fpregs_mem) ++oMXCSR ucontext (__fpregs_mem.mxcsr) +diff --git a/libpthread/nptl/sysdeps/Makefile.commonarch b/libpthread/nptl/sysdeps/Makefile.commonarch +index 0c19216..8f5d61d 100644 +--- a/libpthread/nptl/sysdeps/Makefile.commonarch ++++ b/libpthread/nptl/sysdeps/Makefile.commonarch +@@ -47,9 +47,8 @@ $(libpthread_arch_OUT)/gen_tcb-offsets.c: $(libpthread_arch_DIR)/tcb-offsets.sym + $(libpthread_arch_OUT)/gen_tcb-offsets.s: $(libpthread_arch_OUT)/gen_tcb-offsets.c | headers + $(compile.c) + libpthread-generated-y += $(libpthread_arch_OUT)/gen_tcb-offsets.s +-PTHREAD_TCB_OFFSET_MANGLE ?= -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*\$$/\#define \1 \2/p" + $(libpthread_arch_OUT)/tcb-offsets.h: $(libpthread_arch_OUT)/gen_tcb-offsets.s +- $(do_sed) $(PTHREAD_TCB_OFFSET_MANGLE) $< > $@ ++ $(do_sed) $(PTHREAD_GENERATE_MANGLE) $< > $@ + @if test ! -s $@ ; then rm -f $@ ; false ; fi + + pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(libpthread_arch_OUT)/tcb-offsets.h +diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.commonarch b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.commonarch +index 477fb1a..3372214 100644 +--- a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.commonarch ++++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.commonarch +@@ -177,8 +177,6 @@ CFLAGS-gen_pthread-pi-defines.c = -S + CFLAGS-gen_structsem.c = -S + CFLAGS-gen_unwindbuf.c = -S + +-PTHREAD_GENERATE_MANGLE ?= -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*\$$/\#define \1 \2/p" +- + PTHREAD_LINUX_SYM := $(notdir $(wildcard $(libpthread_linux_DIR)/*.sym)) + PTHREAD_LINUX_SYM_C := $(addprefix $(libpthread_linux_OUT)/gen_,$(PTHREAD_LINUX_SYM:.sym=.c)) + PTHREAD_LINUX_SYM_S := $(PTHREAD_LINUX_SYM_C:.c=.s) +-- +cgit v0.9.1 diff --git a/toolchain/uClibc/uClibc-0.9.33.config b/toolchain/uClibc/uClibc-0.9.33.config index eb39df6..4b3f4f0 100644 --- a/toolchain/uClibc/uClibc-0.9.33.config +++ b/toolchain/uClibc/uClibc-0.9.33.config @@ -81,6 +81,7 @@ HAVE_DOT_CONFIG=y # # HAVE_NO_PIC is not set DOPIC=y +# ARCH_HAS_UCONTEXT is not set # ARCH_HAS_NO_SHARED is not set # ARCH_HAS_NO_LDSO is not set HAVE_SHARED=y @@ -113,6 +114,7 @@ MALLOC_GLIBC_COMPAT=y UCLIBC_DYNAMIC_ATEXIT=y # COMPAT_ATEXIT is not set UCLIBC_SUSV3_LEGACY=y +# UCLIBC_HAS_CONTEXT_FUNCS is not set # UCLIBC_SUSV3_LEGACY_MACROS is not set UCLIBC_SUSV4_LEGACY=y # UCLIBC_STRICT_HEADERS is not set diff --git a/toolchain/uClibc/uclibc.mk b/toolchain/uClibc/uclibc.mk index d4f1d4c..f2bcfca 100644 --- a/toolchain/uClibc/uclibc.mk +++ b/toolchain/uClibc/uclibc.mk @@ -122,6 +122,7 @@ ifeq ($(UCLIBC_TARGET_ARCH),arm) /bin/echo "# CONFIG_ARM_XSCALE is not set"; \ /bin/echo "# CONFIG_ARM_IWMMXT is not set"; \ ) >> $(UCLIBC_DIR)/.oldconfig + $(SED) 's/# \(UCLIBC_HAS_CONTEXT_FUNCS\).*/\1=y/' $(UCLIBC_DIR)/.oldconfig $(SED) 's/^\(CONFIG_[^_]*[_]*ARM[^=]*\)=.*/# \1 is not set/g' \ $(UCLIBC_DIR)/.oldconfig $(SED) 's/^.*$(UCLIBC_ARM_TYPE).*/$(UCLIBC_ARM_TYPE)=y/g' $(UCLIBC_DIR)/.oldconfig @@ -152,6 +153,7 @@ ifeq ($(UCLIBC_TARGET_ARCH),mips) /bin/echo "# CONFIG_MIPS_ISA_MIPS32R2 is not set"; \ /bin/echo "# CONFIG_MIPS_ISA_MIPS64 is not set"; \ ) >> $(UCLIBC_DIR)/.oldconfig + $(SED) 's/# \(UCLIBC_HAS_CONTEXT_FUNCS\).*/\1=y/' $(UCLIBC_DIR)/.oldconfig ifeq ($(BR2_MIPS_OABI32),y) $(SED) 's/.*\(CONFIG_MIPS_O32_ABI\).*/\1=y/' $(UCLIBC_DIR)/.oldconfig endif @@ -342,6 +344,7 @@ ifeq ("$(KERNEL_ARCH)","i386") /bin/echo "# CONFIG_WINCHIP2 is not set" >> $(UCLIBC_DIR)/.oldconfig /bin/echo "# CONFIG_CYRIXIII is not set" >> $(UCLIBC_DIR)/.oldconfig /bin/echo "# CONFIG_NEHEMIAH is not set" >> $(UCLIBC_DIR)/.oldconfig + $(SED) 's/# (UCLIBC_HAS_CONTEXT_FUNCS\).*/\1=y/' $(UCLIBC_DIR)/.oldconfig ifeq ($(BR2_x86_i386),y) $(SED) 's,# CONFIG_386 is not set,CONFIG_386=y,g' $(UCLIBC_DIR)/.oldconfig endif