[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