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