libc: add getcontext, setcontext, makecontext and swapcontext on x86_64
authorMarkus Pfeiffer <markus.pfeiffer@morphism.de>
Wed, 25 Jan 2012 13:11:23 +0000 (13:11 +0000)
committerSascha Wildner <saw@online.de>
Thu, 26 Jan 2012 21:18:10 +0000 (22:18 +0100)
The *context functions are not part of the POSIX standard anymore, but
are still used by quite some packages.

lib/libc/x86_64/gen/Makefile.inc
lib/libc/x86_64/gen/makecontext.c [new file with mode: 0644]
lib/libc/x86_64/sys/Makefile.inc
lib/libc/x86_64/sys/getcontext.S [new file with mode: 0644]
sys/sys/ucontext.h

index adfbeb1..f379caa 100644 (file)
@@ -5,6 +5,6 @@ SRCS+=  _setjmp.S rfork_thread.S setjmp.S sigsetjmp.S \
        fabs.S modf.S mcontext.S\
        fpclassifyl.c nanf.c signbitl.c flt_rounds.c \
        infinityl.c isinfl.c isfinitel.c isnanl.c \
-       ldexp.c \
+       ldexp.c makecontext.c \
        fpgetmask.S fpsetmask.S fpgetround.S fpsetround.S \
        fpgetsticky.S fpsetsticky.S
diff --git a/lib/libc/x86_64/gen/makecontext.c b/lib/libc/x86_64/gen/makecontext.c
new file mode 100644 (file)
index 0000000..3e57f90
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2001 Daniel M. Eischen <deischen@freebsd.org>
+ * All rights reserved.
+ * Copyright (c) 2007 Matthew Dillon <dillon@backplane.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Neither the name of the author nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/i386/gen/makecontext.c,v 1.5 2004/12/05 21:22:08 deischen Exp $
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/ucontext.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
+
+/* Prototypes */
+static void makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args);
+
+__weak_reference(_makecontext, makecontext);
+
+/*
+ * makecontext() associates a stack with a user thread context and sets
+ * up to call the start function when switched to.  The start function
+ * returns to _ctx_start which then calls _ctx_done to terminate the
+ * context.
+ */
+void
+_makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
+{
+       va_list         ap;
+       uint64_t        *stack_top;
+       uint64_t        *argp;
+       int             i;
+
+       if (ucp == NULL)
+               return;
+
+       /*
+        * Invalidate a context which did not have a stack associated with
+        * it or for which the stack was too small.  The stack check is
+        * kinda silly, though, since we have no control over the stack
+        * usage of the code being set up to run.
+        */
+       if ((ucp->uc_stack.ss_sp == NULL) ||
+           (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
+               ucp->uc_mcontext.mc_len = 0;
+       }
+       if (argc < 0 || argc > NCARGS)
+               ucp->uc_mcontext.mc_len = 0;
+
+       if (ucp->uc_mcontext.mc_len == sizeof(mcontext_t)) {
+               /*
+                */
+               stack_top = (uint64_t *)(ucp->uc_stack.ss_sp +
+                                         ucp->uc_stack.ss_size);
+               stack_top = (uint64_t *)((uint64_t)(stack_top) & ~15UL);
+
+               argp = stack_top - 6;
+               stack_top -= 7;
+
+               /* Add all the arguments: */
+               va_start(ap, argc);
+               for (i = 0; i < argc; i++) {
+                       argp[i] = va_arg(ap, uint64_t);
+               }
+               va_end(ap);
+               for(i = argc; i < 6; i++) {
+                       argp[i] = 0;
+               }
+
+               /*
+                * Set the machine context to point to the top of the
+                * stack and the program counter to the context start
+                * wrapper.  Note that setcontext() pushes the return
+                * address onto the top of the stack, so allow for this
+                * by adjusting the stack downward 1 slot.  Also set
+                * %rbp to point to the base of the stack where ucp
+                * is stored.
+                */
+               ucp->uc_mcontext.mc_rdi = (register_t)ucp;
+               ucp->uc_mcontext.mc_rsi = (register_t)start;
+               ucp->uc_mcontext.mc_rdx = (register_t)argp;
+               ucp->uc_mcontext.mc_rbp = 0;
+               ucp->uc_mcontext.mc_rbx = (register_t)stack_top;
+               ucp->uc_mcontext.mc_rsp = (register_t)stack_top;
+               ucp->uc_mcontext.mc_rip = (register_t)makectx_wrapper;
+       }
+}
+
+/* */
+static void
+makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args)
+{
+       (*func)(args[0], args[1], args[2], args[3], args[4], args[5]);
+       if(ucp->uc_link == NULL)
+               exit(0);
+
+       setcontext((const ucontext_t *)ucp->uc_link);
+
+       /* should never reach this */
+       abort();
+}
index 5145e76..4ba301a 100644 (file)
@@ -3,7 +3,7 @@
 
 SRCS+= amd64_get_fsbase.c amd64_get_gsbase.c amd64_set_fsbase.c amd64_set_gsbase.c
 
-MDASM= vfork.S brk.S cerror.S exect.S pipe.S ptrace.S \
+MDASM= vfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \
        reboot.S sbrk.S setlogin.S sigreturn.S
 
 # Don't generate default code for these syscalls:
diff --git a/lib/libc/x86_64/sys/getcontext.S b/lib/libc/x86_64/sys/getcontext.S
new file mode 100644 (file)
index 0000000..516e8fc
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ * 
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#include <machine/asm.h>
+#include <asmcontext.h>
+
+       /*
+        * This function is special-cased because the context it saves
+        * includes a stale stack context (because it returns before the
+        * caller presumably makes the call to setcontext()).  
+        */
+       .weak   getcontext
+       .set    getcontext,_getcontext
+ENTRY(_getcontext)
+       /*
+        * Retrieve the current signal mask and save it in &ucp->uc_sigmask.
+        */
+       pushq   %rdi                    /* save ucontext_t pointer passed */
+       movq    %rdi,%rdx
+       addq    $UC_SIGMASK,%rdx        /* pointer to signal mask */
+       movq    $0,%rsi
+       movq    $SIG_BLOCK,%rdi
+       call    PIC_PLT(CNAME(_sigprocmask))
+       /*
+        * Save what we need because our stack context is going stale.
+        */
+       popq    %rdi
+       movq    %rdi,%r9
+       movq    (%rsp),%r8              /* save return PC in %r9 */
+       addq    $UC_MCONTEXT,%rdi
+       call    PIC_PLT(CNAME(get_mcontext))    /* returns non-zero on resume */
+       cmpl    $0,%eax                         /* return type is int */
+       je      2f
+       /*
+        * On resume, resave the stale return pc and restore the signal
+        * mask (signals are blocked right now from the setcontext call).
+        */
+       movq    %r8,(%rsp)              /* re-save the return PC */
+       movq    %r9,%rsi 
+       addq    $UC_SIGMASK,%rsi
+        movq    $0,%rdx
+       movq    $SIG_SETMASK,%rdi
+       call    PIC_PLT(CNAME(_sigprocmask))    /* retrieve & save signal mask */
+2:
+       movl    $0,%eax                 /* return success */
+       ret
+1:
+       pushq   %rsi
+#ifdef PIC
+       movq    PIC_GOT(HIDENAME(cerror)),%rdx
+       jmp     *%rdx
+#else
+       jmp     HIDENAME(cerror)
+#endif
+END(_getcontext)
index b4e55ab..fa31f42 100644 (file)
@@ -58,14 +58,11 @@ typedef struct __ucontext {
 __BEGIN_DECLS
   
 #if __BSD_VISIBLE || __POSIX_VISIBLE < 200809
-#ifdef __i386__
-/* XXX not fully implemented yet on x86_64 */
 int    getcontext(ucontext_t *);
 int    setcontext(const ucontext_t *);
 void   makecontext(ucontext_t *, void (*)(void), int, ...);
 int    swapcontext(ucontext_t *, const ucontext_t *);
 #endif
-#endif
    
 __END_DECLS