[PATCH 5/9] libc: add {get,set,swap,make}context to ARM

Florian Fainelli florian at openwrt.org
Mon Dec 31 14:38:28 UTC 2012


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 <timonterbraak at gmail.com>
Signed-off-by: Florian Fainelli <florian at 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



More information about the uClibc mailing list