commit 70a04a287a2875c82e6822c36e071afba5b63a62
Author: Waldemar Brodkorb <wbx@openadk.org>
Date:   Wed Jan 29 18:58:56 2014 +0100

    libc: mips: Fix setjmp/longjmp for MIPS64 N64 ABI
    
    When booting a Linux system with qemu-system-mips64 the execution
    of $(pwd) in the ash shell triggers a segmentation fault. Ash uses
    setjmp/longjmp for exception handling.
    
    After looking at the glibc implementation,
    I found some differences, with this patch tries to resolve.
    Now the system boots up fine and no segmentation faults occur.
    
    The global pointer should be restored and the types for the
    register values should be wide enough.
    
    See:
    http://www.cygwin.com/ml/libc-alpha/2003-03/msg00363.html
    
    Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
    Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>

--- a/libc/sysdeps/linux/mips/bits/setjmp.h
+++ b/libc/sysdeps/linux/mips/bits/setjmp.h
@@ -26,13 +26,19 @@
 
 #include <sgidefs.h>
 
+#if _MIPS_SIM == _MIPS_SIM_ABI32
+#define ptrsize void *
+#else
+#define ptrsize long long
+#endif
+
 typedef struct
   {
     /* Program counter.  */
-    void * __pc;
+    ptrsize __pc;
 
     /* Stack pointer.  */
-    void * __sp;
+    ptrsize __sp;
 
     /* Callee-saved registers s0 through s7.  */
 #if _MIPS_SIM == _MIPS_SIM_ABI32
@@ -42,10 +48,10 @@ typedef struct
 #endif
 
     /* The frame pointer.  */
-    void * __fp;
+    ptrsize __fp;
 
     /* The global pointer.  */
-    void * __gp;
+    ptrsize __gp;
 
     /* Floating point status register.  */
     int __fpc_csr;
--- a/libc/sysdeps/linux/mips/setjmp.S
+++ b/libc/sysdeps/linux/mips/setjmp.S
@@ -53,6 +53,7 @@ __sigsetjmp:
 	PTR_LA	t9, __sigsetjmp_aux
 #if _MIPS_SIM != _MIPS_SIM_ABI32
 	.cpreturn
+	move 	a4, gp
 #endif
 	jr	t9
 #else
--- a/libc/sysdeps/linux/mips/setjmp_aux.c
+++ b/libc/sysdeps/linux/mips/setjmp_aux.c
@@ -31,7 +31,7 @@ extern int __sigjmp_save (sigjmp_buf, in
 
 int
 #if _MIPS_SIM == _MIPS_SIM_ABI64
-__sigsetjmp_aux (jmp_buf env, int savemask, long sp, long fp)
+__sigsetjmp_aux (jmp_buf env, int savemask, long long sp, long long fp, long long gp)
 #else /* O32 || N32 */
 __sigsetjmp_aux (jmp_buf env, int savemask, int sp, int fp)
 #endif /* O32 || N32 */
@@ -65,14 +65,14 @@ __sigsetjmp_aux (jmp_buf env, int savema
 #endif
 
   /* .. and the stack pointer;  */
-  env[0].__jmpbuf[0].__sp = (void *) sp;
+  env[0].__jmpbuf[0].__sp = (ptrsize) sp;
 
   /* .. and the FP; it'll be in s8. */
-  env[0].__jmpbuf[0].__fp = (void *) fp;
+  env[0].__jmpbuf[0].__fp = (ptrsize) fp;
 
   /* .. and the GP; */
 #if _MIPS_SIM == _MIPS_SIM_ABI64
-  __asm__ __volatile__ ("sd $gp, %0" : : "m" (env[0].__jmpbuf[0].__gp));
+  env[0].__jmpbuf[0].__gp = (ptrsize) gp;
 #else
   __asm__ __volatile__ ("sw $gp, %0" : : "m" (env[0].__jmpbuf[0].__gp));
 #endif
