076f82
commit c6f9085ee4e913a0b8260340ac7b75c426b780ce
076f82
Author: John David Anglin <danglin@gcc.gnu.org>
076f82
Date:   Fri Feb 18 20:38:25 2022 +0000
076f82
076f82
    hppa: Fix swapcontext
076f82
    
076f82
    This change fixes the failure of stdlib/tst-setcontext2 and
076f82
    stdlib/tst-setcontext7 on hppa.  The implementation of swapcontext
076f82
    in C is broken.  C saves the return pointer (rp) and any non
076f82
    call-clobbered registers (in this case r3, r4 and r5) on the
076f82
    stack.  However, the setcontext call in swapcontext pops the
076f82
    stack and subsequent calls clobber the saved registers.  When
076f82
    the context in oucp is restored, both tests fault.
076f82
    
076f82
    Here we rewrite swapcontext in assembly code to avoid using
076f82
    the stack for register values that need to be used after
076f82
    restoration.  The getcontext and setcontext routines are
076f82
    revised to save and restore register ret1 for normal returns.
076f82
    We copy the oucp pointer to ret1.  This allows access to
076f82
    the old context after calling getcontext and setcontext.
076f82
    
076f82
    (cherry picked from commit 71b108d7eb33b2bf3e61d5e92d2a47f74c1f7d96)
076f82
076f82
diff --git a/sysdeps/unix/sysv/linux/hppa/getcontext.S b/sysdeps/unix/sysv/linux/hppa/getcontext.S
076f82
index 1405b42819c38993..c8b690aab8ecc47c 100644
076f82
--- a/sysdeps/unix/sysv/linux/hppa/getcontext.S
076f82
+++ b/sysdeps/unix/sysv/linux/hppa/getcontext.S
076f82
@@ -138,6 +138,8 @@ ENTRY(__getcontext)
076f82
 	stw	%r19, -32(%sp)
076f82
 	.cfi_offset 19, 32
076f82
 #endif
076f82
+	stw	%ret1, -60(%sp)
076f82
+	.cfi_offset 29, 4
076f82
 
076f82
 	/* Set up the trampoline registers.
076f82
 	   r20, r23, r24, r25, r26 and r2 are clobbered
076f82
@@ -168,6 +170,7 @@ ENTRY(__getcontext)
076f82
 #ifdef PIC
076f82
 	ldw	-32(%sp), %r19
076f82
 #endif
076f82
+	ldw	-60(%sp), %ret1
076f82
 	bv	%r0(%r2)
076f82
 	ldwm	-64(%sp), %r4
076f82
 END(__getcontext)
076f82
diff --git a/sysdeps/unix/sysv/linux/hppa/setcontext.S b/sysdeps/unix/sysv/linux/hppa/setcontext.S
076f82
index 8fc5f5e56cb31f51..e1ae3aefcaac198d 100644
076f82
--- a/sysdeps/unix/sysv/linux/hppa/setcontext.S
076f82
+++ b/sysdeps/unix/sysv/linux/hppa/setcontext.S
076f82
@@ -34,6 +34,8 @@ ENTRY(__setcontext)
076f82
 	stw	%r19, -32(%sp)
076f82
 	.cfi_offset 19, 32
076f82
 #endif
076f82
+	stw	%ret1, -60(%sp)
076f82
+	.cfi_offset 29, 4
076f82
 
076f82
 	/* Save ucp.  */
076f82
 	copy	%r26, %r3
076f82
@@ -155,6 +157,7 @@ ENTRY(__setcontext)
076f82
 #ifdef PIC
076f82
 	ldw	-32(%r30), %r19
076f82
 #endif
076f82
+	ldw	-60(%r30), %ret1
076f82
 	bv	%r0(%r2)
076f82
 	ldwm	-64(%r30), %r3
076f82
 L(pseudo_end):
076f82
diff --git a/sysdeps/unix/sysv/linux/hppa/swapcontext.c b/sysdeps/unix/sysv/linux/hppa/swapcontext.c
076f82
index f9a8207543c164cb..562f00ff0546177d 100644
076f82
--- a/sysdeps/unix/sysv/linux/hppa/swapcontext.c
076f82
+++ b/sysdeps/unix/sysv/linux/hppa/swapcontext.c
076f82
@@ -18,6 +18,7 @@
076f82
    <https://www.gnu.org/licenses/>.  */
076f82
 
076f82
 #include <ucontext.h>
076f82
+#include "ucontext_i.h"
076f82
 
076f82
 extern int __getcontext (ucontext_t *ucp);
076f82
 extern int __setcontext (const ucontext_t *ucp);
076f82
@@ -25,17 +26,61 @@ extern int __setcontext (const ucontext_t *ucp);
076f82
 int
076f82
 __swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
076f82
 {
076f82
+  /* Save ucp in stack argument slot.  */
076f82
+  asm ("stw %r25,-40(%sp)");
076f82
+  asm (".cfi_offset 25, -40");
076f82
+
076f82
+  /* Save rp for debugger.  */
076f82
+  asm ("stw %rp,-20(%sp)");
076f82
+  asm (".cfi_offset 2, -20");
076f82
+
076f82
+  /* Copy rp to ret0 (r28).  */
076f82
+  asm ("copy %rp,%ret0");
076f82
+
076f82
+  /* Create a frame.  */
076f82
+  asm ("ldo 64(%sp),%sp");
076f82
+  asm (".cfi_def_cfa_offset -64");
076f82
+
076f82
   /* Save the current machine context to oucp.  */
076f82
-  __getcontext (oucp);
076f82
+  asm ("bl __getcontext,%rp");
076f82
+
076f82
+  /* Copy oucp to register ret1 (r29).  __getcontext saves and restores it
076f82
+     on a normal return.  It is restored from oR29 on reactivation.  */
076f82
+  asm ("copy %r26,%ret1");
076f82
+
076f82
+  /* Pop frame.  */
076f82
+  asm ("ldo -64(%sp),%sp");
076f82
+  asm (".cfi_def_cfa_offset 0");
076f82
+
076f82
+  /* Load return pointer from oR28.  */
076f82
+  asm ("ldw %0(%%ret1),%%rp" : : "i" (oR28));
076f82
+
076f82
+  /* Return if error.  */
076f82
+  asm ("or,= %r0,%ret0,%r0");
076f82
+  asm ("bv,n %r0(%rp)");
076f82
+
076f82
+  /* Load sc_sar flag.  */
076f82
+  asm ("ldw %0(%%ret1),%%r20" : : "i" (oSAR));
076f82
+
076f82
+  /* Return if oucp context has been reactivated.  */
076f82
+  asm ("or,= %r0,%r20,%r0");
076f82
+  asm ("bv,n %r0(%rp)");
076f82
+
076f82
+  /* Mark sc_sar flag.  */
076f82
+  asm ("1: ldi 1,%r20");
076f82
+  asm ("stw %%r20,%0(%%ret1)" : : "i" (oSAR));
076f82
+
076f82
+  /* Activate the machine context in ucp.  */
076f82
+  asm ("bl __setcontext,%rp");
076f82
+  asm ("ldw -40(%sp),%r26");
076f82
 
076f82
-  /* mark sc_sar flag to skip the setcontext call on reactivation.  */
076f82
-  if (oucp->uc_mcontext.sc_sar == 0) {
076f82
-	oucp->uc_mcontext.sc_sar++;
076f82
+  /* Load return pointer.  */
076f82
+  asm ("ldw %0(%%ret1),%%rp" : : "i" (oR28));
076f82
 
076f82
-	/* Restore the machine context in ucp.  */
076f82
-	__setcontext (ucp);
076f82
-  }
076f82
+  /* A successful call to setcontext does not return.  */
076f82
+  asm ("bv,n %r0(%rp)");
076f82
 
076f82
+  /* Make gcc happy.  */
076f82
   return 0;
076f82
 }
076f82