This patch adds support for {get,set,swap,make}context to the ARM
architecture. These routines currently do not support saving and
restoring the FPU registers (neither VFP, nor Maverick, nor IWMMX) for
now. Files are imported from glibc.

Signed-off-by: Timon ter Braak <timonterbr...@gmail.com>
Signed-off-by: Florian Fainelli <flor...@openwrt.org>
---
 extra/Configs/Config.arm              |    1 +
 libc/sysdeps/linux/arm/Makefile.arch  |    5 +++
 libc/sysdeps/linux/arm/getcontext.S   |   58 ++++++++++++++++++++++++++
 libc/sysdeps/linux/arm/makecontext.c  |   73 +++++++++++++++++++++++++++++++++
 libc/sysdeps/linux/arm/setcontext.S   |   54 ++++++++++++++++++++++++
 libc/sysdeps/linux/arm/swapcontext.S  |   63 ++++++++++++++++++++++++++++
 libc/sysdeps/linux/arm/ucontext_i.sym |   30 ++++++++++++++
 7 files changed, 284 insertions(+)
 create mode 100644 libc/sysdeps/linux/arm/getcontext.S
 create mode 100644 libc/sysdeps/linux/arm/makecontext.c
 create mode 100644 libc/sysdeps/linux/arm/setcontext.S
 create mode 100644 libc/sysdeps/linux/arm/swapcontext.S
 create mode 100644 libc/sysdeps/linux/arm/ucontext_i.sym

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/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..9502212
--- /dev/null
+++ b/libc/sysdeps/linux/arm/getcontext.S
@@ -0,0 +1,58 @@
+/* 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#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)
+
+       /* 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <ucontext.h>
+
+/* 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..ca70fbd
--- /dev/null
+++ b/libc/sysdeps/linux/arm/setcontext.S
@@ -0,0 +1,54 @@
+/* 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+       .syntax unified
+       .text
+
+/* int setcontext (const ucontext_t *ucp) */
+
+ENTRY(__setcontext)
+       mov     r4, r0
+
+       /* 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..09492d0
--- /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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#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 <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_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)
-- 
1.7.10.4

_______________________________________________
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Reply via email to