[ARM] *context routines

David Gilbert david.gilbert@linaro.org
Fri Dec 30 21:09:00 GMT 2011


On 23 December 2011 17:42, Dr. David Alan Gilbert
<david.gilbert@linaro.org> wrote:
> 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.

The only failures I got comparing my older version against the same old
refernece run was checkplt pointing out _exit - I use that in setcontext.S - am
I using it correctly?

For the SVN version it seems good, although I didn't have a reference run of
that prior to my patch (globtest and ftwtest have failed but both of those
look like cross test issues rather than anything context specific and
tst-backtrace6
is failing only having found 3 entries - but it uses longjmp not the
context routines.

> 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.

I am now not really able to run more tests, so please reply anyway
to this thread if you spot any problems with the patch and I'll
keep an eye out and someone else in Linaro will pick it up.

Dave

>
> 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



More information about the Libc-ports mailing list