This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[ARM] *context routines


This is an implementation of getcontext, makecontext, setcontext and
swapcontext for ARM Linux.

While they are deprecated, a few things (primarily coroutine libraries,
and in particular the one in QEMU) use them.

I've run the context tests in stdlib/ on them, and the one in nptl,
I've also run the coroutine test in QEMU, and booted an image on QEMU
using it.    I'll leave a full eglibc test run going over the next
day or two.

One question I have is whether the offset definition header
that I've created in ports/sysdeps/unix/sysv/linux/arm/sys/ucontext_offsets.h
for inclusion in the asm is in the right place, and if there is a good
way to do a build time test that the offsets haven't changed.

Dave
P.S. I'm finishing up with my Linaro assignment in a few days; I'll
try and make sure the tests are done, and monitor the replies and
see what I can do, or make sure it gets cleanly handed over.

2011-12-23 Dr. David Alan Gilbert <david.gilbert@linaro.org>
    * sysdeps/unix/sysv/linux/arm/eabi/getcontext.S: New file
    * sysdeps/unix/sysv/linux/arm/eabi/makecontext.c: New file
    * sysdeps/unix/sysv/linux/arm/eabi/setcontext.S: New file
    * sysdeps/unix/sysv/linux/arm/eabi/swapcontext.S: New file
    * sysdeps/unix/sysv/linux/arm/sys/ucontext_offsets.h: New file

diff -urN ports/sysdeps/unix/sysv/linux/arm/eabi/getcontext.S ports/sysdeps/unix/sysv/linux/arm/eabi/getcontext.S
--- ports/sysdeps/unix/sysv/linux/arm/eabi/getcontext.S	1970-01-01 01:00:00.000000000 +0100
+++ ports/sysdeps/unix/sysv/linux/arm/eabi/getcontext.S	2011-12-23 15:50:40.514729628 +0000
@@ -0,0 +1,126 @@
+/* Copyright (C) 2011 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _ASM
+#include <sysdep.h>
+#include <sys/ucontext_offsets.h>
+#include <rtld-global-offsets.h>
+
+#define SIG_BLOCK 0
+
+	.syntax unified
+	.text
+
+@ It's useful to remember that *context functions are functions and therefor
+@ They don't have to preserve registers which a function can corrupt
+@ According to the ABI that means r4-8, r10,r11, sp (13) and possibly r9
+@ have to be preserved.
+@ For FP s16-31/d8-15/q4-q7 (all the same) have to be preserved
+
+@ r0 is ucontext_t* - context to populate
+@ Returns r0 containing 0
+@ Also returns after the setcontext that returns here
+
+ENTRY(__getcontext)
+	add	r1, r0, #(UCONTEXT_T_OFFSET_MCONTEXT+SIGCONTEXT_OFFSET_ARM_R0+4*4)
+	stmia   r1, {r4-r11}       @ Store most of the state
+	sub	r1, r1, #4*4
+	str     r13, [r1,#13*4]       @ R13 separately (Thumb can't stm it)
+	str     r14, [r1,#14*4]
+
+	@ Set the restored PC to be a return to the r14 we have
+	str     r14, [r1,#15*4]
+
+	@ Zero the stored r0 - when it returns it makes us return with 0
+	mov     r4, #0
+	str     r4, [r1, #0]
+
+	mov     r4, r0   @ Stash our ucontext_t* so we can do some calls
+
+	@ Store signal status - using a call to __sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask))
+	mov     r0, #SIG_BLOCK
+	mov     r1, #0
+	add     r2, r4, #UCONTEXT_T_OFFSET_SIGMASK
+	bl      PLTJMP(__sigprocmask)
+	
+	@ Store FP regs
+	@ Much of the FP code is copied from arm/eabi/setjmp.S
+
+#ifdef PIC
+        ldr     r2, 1f
+        ldr     r1, Lrtld_global_ro
+0:      add     r2, pc, r2
+        ldr     r2, [r2, r1]
+        ldr     r2, [r2, #RTLD_GLOBAL_RO_DL_HWCAP_OFFSET]
+#else  
+        ldr     r2, Lhwcap
+        ldr     r2, [r2, #0]
+#endif
+
+	add	r0, r4, #UCONTEXT_T_OFFSET_REGSPACE
+
+        tst     r2, #HWCAP_ARM_VFP
+        beq     Lno_vfp
+
+        /* Store the VFP registers.
+           Don't use VFP instructions directly because this code
+           is used in non-VFP multilibs.  */
+        /* Following instruction is vstmia r0!, {d8-d15}.  */
+        stc     p11, cr8, [r0], #64
+        /* Store the floating-point status register.  */
+        /* Following instruction is vmrs r1, fpscr.  */
+        mrc     p10, 7, r1, cr1, cr0, 0
+        str     r1, [r0], #4
+Lno_vfp:
+
+        tst     r2, #HWCAP_ARM_IWMMXT
+        beq     Lno_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
+Lno_iwmmxt:
+
+	@ Now restore GPRs that __sigprocmask may have overwritten
+	add	r1, r4, #(UCONTEXT_T_OFFSET_MCONTEXT+SIGCONTEXT_OFFSET_ARM_R0+4*4)
+	ldmia	r1!,{r4-r11}
+	ldr	r13, [r1, #4]
+	ldr	r14, [r1, #8]
+
+	mov	r0, #0
+
+	DO_RET(r14)
+
+END(__getcontext)
+
+#ifdef PIC
+1:      .long   _GLOBAL_OFFSET_TABLE_ - 0b - 8
+Lrtld_global_ro:
+        .long   C_SYMBOL_NAME(_rtld_global_ro)(GOT)
+#else
+Lhwcap:
+        .long   C_SYMBOL_NAME(_dl_hwcap)
+#endif
+
+
+weak_alias(__getcontext, getcontext)
diff -urN ports/sysdeps/unix/sysv/linux/arm/eabi/makecontext.c ports/sysdeps/unix/sysv/linux/arm/eabi/makecontext.c
--- ports/sysdeps/unix/sysv/linux/arm/eabi/makecontext.c	1970-01-01 01:00:00.000000000 +0100
+++ ports/sysdeps/unix/sysv/linux/arm/eabi/makecontext.c	2011-12-23 16:26:31.262494329 +0000
@@ -0,0 +1,82 @@
+/* Copyright (C) 2011
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <ucontext.h>
+
+extern void __setcontext_orexit_r4(void);
+
+/* makecontext fiddles with a context that was previously prepared by
+  getcontext to get it to call a func with a given set of args, it doesn't
+  have a way to say the type of args so we have to assume they are ints
+  (same as long on ARM).
+
+  When the func returns it setcontexts to a link or exits if the link
+  as null; we leave that to __setcontext_orexit_r4 in setcontext.S */
+void
+makecontext (ucontext_t *ucp, void (*func)(void), int argc, ...)
+{
+  unsigned long* funcstack;
+  va_list vl;
+  unsigned long* regptr;
+  unsigned int reg;
+  int misalign;
+
+  /* Just off the top of the stack we've been given */
+  funcstack = (unsigned long*)(ucp->uc_stack.ss_sp +
+                ucp->uc_stack.ss_size);
+
+  /* If the number of arguments on the stack is going to
+   cause misalignment, EOR the stack already being misaligned
+   by 1 word then realign. */
+  misalign = ((unsigned long)funcstack & 4) != 0;
+  if ((argc > 4) && (argc & 1))
+    misalign ^= 1;
+
+  if (misalign)
+    funcstack -= 1;
+
+  va_start (vl, argc);
+
+  /* arguments after 4 need to go on the stack, so make some space */
+  /* Note that makecontext is void, so we can't return an error if there
+     isn't enough space (I guess we could set up the context to point
+     to an error causing func). */
+  if (argc>4)
+    funcstack -= (argc-4);
+
+  /* R4 of the context points to the link context, and ends up being passed
+     to __setcontext_orexit_r4 where it ends up either calling setcontext or
+     if 0 ends up as the conveniently correct param to exit() */
+  ucp->uc_mcontext.arm_r4 = (unsigned long)ucp->uc_link;
+  ucp->uc_mcontext.arm_sp = (unsigned long)funcstack;
+  ucp->uc_mcontext.arm_lr = (unsigned long)__setcontext_orexit_r4;
+  ucp->uc_mcontext.arm_pc = (unsigned long)func;
+
+  /* But first 4 args go into registers */
+  regptr = &(ucp->uc_mcontext.arm_r0);
+  for(reg=0; argc && (reg<4); argc--, regptr++, reg++)
+    *regptr = va_arg (vl, unsigned long);
+
+  /* and what's left goes on the stack */
+  for(; argc-- ; funcstack++)
+      *funcstack = va_arg (vl, unsigned long);
+
+  va_end (vl);
+}
diff -urN ports/sysdeps/unix/sysv/linux/arm/eabi/setcontext.S ports/sysdeps/unix/sysv/linux/arm/eabi/setcontext.S
--- ports/sysdeps/unix/sysv/linux/arm/eabi/setcontext.S	1970-01-01 01:00:00.000000000 +0100
+++ ports/sysdeps/unix/sysv/linux/arm/eabi/setcontext.S	2011-12-23 15:44:24.490640681 +0000
@@ -0,0 +1,108 @@
+/* Copyright (C) 2011 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _ASM
+#include <sysdep.h>
+#include <sys/ucontext_offsets.h>
+#include <rtld-global-offsets.h>
+
+#define SIG_SETMASK 2
+
+	.syntax unified
+	.text
+
+@ See getcontext.S for general comments on context stuff
+
+@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+@ r0 is const ucontext_t* - context to restore
+@ Should not return (-1 on error with errno)
+ENTRY(__setcontext)
+	mov	r4, r0
+	add	r0, r0, #UCONTEXT_T_OFFSET_REGSPACE
+
+	@ Copied from arm/eabi/__longjmp.S
+        /* Restore the VFP registers.  */
+#ifdef PIC
+        ldr     r2, 1f
+        ldr     r1, Lrtld_global_ro
+0:      add     r2, pc, r2
+        ldr     r2, [r2, r1]
+        ldr     r2, [r2, #RTLD_GLOBAL_RO_DL_HWCAP_OFFSET]
+#else
+        ldr     r2, Lhwcap
+        ldr     r2, [r2, #0]
+#endif
+
+        tst     r2, #HWCAP_ARM_VFP
+        beq     Lno_vfp_sc
+
+        /* 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
+Lno_vfp_sc:
+        tst     r2, #HWCAP_ARM_IWMMXT
+        beq     Lno_iwmmxt_sc
+
+        /* 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
+Lno_iwmmxt_sc:
+
+	@ Now bring back the signal status
+	mov	r0, # SIG_SETMASK
+	add	r1, r4, #UCONTEXT_T_OFFSET_SIGMASK
+	mov	r2, #0  @ Don't need the current mask
+	bl	PLTJMP(__sigprocmask)
+
+        @ Load all the registers - loading r0-r3 makes makecontext easier
+        add     r14, r4, #UCONTEXT_T_OFFSET_MCONTEXT+SIGCONTEXT_OFFSET_ARM_R0
+        ldmia   r14, {r0-r12}
+        ldr     r13, [r14,#13*4]
+        add     r14, r14, #14*4
+        ldmia   r14, {r14, pc}
+END(setcontext)
+
+        @ The function called via a setcontext on a context that makecontext
+        @ tweeked returns here (by it's LR), R4 should hold the context we're
+        @ supposed to run next, if 0 we exit
+ENTRY(__setcontext_orexit_r4)
+        movs    r0,r4
+        bne     PLTJMP(__setcontext)
+
+        @ New context was 0 - exit
+        b       PLTJMP(_exit)
+END(__setcontext_orexit_r4)
+
+#ifdef PIC
+1:      .long   _GLOBAL_OFFSET_TABLE_ - 0b - 8
+Lrtld_global_ro:
+        .long   C_SYMBOL_NAME(_rtld_global_ro)(GOT)
+#else
+Lhwcap:
+        .long   C_SYMBOL_NAME(_dl_hwcap)
+#endif
+
+weak_alias(__setcontext, setcontext)
diff -urN ports/sysdeps/unix/sysv/linux/arm/eabi/swapcontext.S ports/sysdeps/unix/sysv/linux/arm/eabi/swapcontext.S
--- ports/sysdeps/unix/sysv/linux/arm/eabi/swapcontext.S	1970-01-01 01:00:00.000000000 +0100
+++ ports/sysdeps/unix/sysv/linux/arm/eabi/swapcontext.S	2011-12-23 10:35:45.794003753 +0000
@@ -0,0 +1,74 @@
+/* Copyright (C) 2011 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <sys/ucontext_offsets.h>
+
+	.syntax unified
+	.text
+
+@ See getcontext.S for general comments on context stuff
+
+@ r0 is ucontext_t *oucp - stores old context in here
+@ r1 is ucontext_t *ucp - context to return to
+@ Should not return directly, but can come back via *oucp
+ENTRY(swapcontext)
+	@ We'll get getcontext to do most of the work - but we'll have
+	@ to fix a couple of things up.
+	@ Need to preserve R0, R1, and R14 before we branch to getcontext
+	@ I think the only place we can do this is on the current stack
+	@ We'll have to fix it up though so it gets restored correctly
+	push	{r0,r1,r3,r14}  @ r3 just to keep alignment
+	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)
+
+	@ Fill out *oucp
+	bl	__getcontext
+
+	mov	r4, r0
+
+	@ OK, now we need to fix up the sp & r14 in oucp and recover the other
+	@ stashed regs
+	pop	{r0,r1,r3,r14}
+	cfi_adjust_cfa_offset (-16)
+	cfi_restore (r0)
+	cfi_restore (r1)
+	cfi_restore (r3)
+	cfi_restore (r14)
+
+	@ If getcontext failed, exit
+	cmp 	r4, #-1
+	itt	eq
+	moveq	r0,r4
+	RETINSTR(eq, r14)
+	
+	@ r13,r14 is now back to original entry value, and the values that
+	@ should be in the context
+	add	r3, r0, #UCONTEXT_T_OFFSET_MCONTEXT+SIGCONTEXT_OFFSET_ARM_R0+13*4
+	str	r13,[r3,#0]
+	str	r14,[r3,#4]
+	str	r14,[r3,#8]	@ Also overwrite return PC
+
+	@ Now exit with a setcontext into the new context currently in r1
+	mov	r0, r1
+	b	__setcontext
+
+END(swapcontext)
diff -urN ports/sysdeps/unix/sysv/linux/arm/sys/ucontext_offsets.h ports/sysdeps/unix/sysv/linux/arm/sys/ucontext_offsets.h
--- ports/sysdeps/unix/sysv/linux/arm/sys/ucontext_offsets.h	1970-01-01 01:00:00.000000000 +0100
+++ ports/sysdeps/unix/sysv/linux/arm/sys/ucontext_offsets.h	2011-12-23 15:52:34.222003794 +0000
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* The contents of this file **MUST** match the defs in ucontext.h and
+   the structures it includes, they're used by the *context.S source.
+   It's only for internal use within libc. */
+
+/* Offsets into ucontext_t as defined in sys/ucontext.h */
+#define UCONTEXT_T_OFFSET_FLAGS		  0
+#define UCONTEXT_T_OFFSET_LINK		  4
+
+/* This is a stack_t */
+#define UCONTEXT_T_OFFSET_STACK		  8
+
+/* This is a mcontext_t aka struct sigcontext */
+#define UCONTEXT_T_OFFSET_MCONTEXT	 20
+
+/* This is a __sigset_t */
+#define UCONTEXT_T_OFFSET_SIGMASK	104
+
+/* This is a unsigned long uc_regspace[128] aligned on 8 bytes */
+#define UCONTEXT_T_OFFSET_REGSPACE	232
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+@ Offsets into struct sigcontext (add to UCONTEXT_T_OFFSET_MCONTEXT)
+  Note many of these are designed for signals - which we aren't
+  dealing with */
+#define SIGCONTEXT_OFFSET_TRAP_NO	 0
+#define SIGCONTEXT_OFFSET_ERROR_CODE	 4
+#define SIGCONTEXT_OFFSET_OLDMASK	 8
+/* All the other GPRs follow on from R0 (including R15/PC) */
+#define SIGCONTEXT_OFFSET_ARM_R0	12
+#define SIGCONTEXT_OFFSET_ARM_CPSR	76
+#define SIGCONTEXT_OFFSET_FAULT_ADDRESS	80


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]