Blob Blame History Raw
From f60b86bddcf964f1a97df7a33aa36bc0160dba38 Mon Sep 17 00:00:00 2001
From: Andreas Krebbel <krebbel@linux.ibm.com>
Date: Mon, 23 Mar 2020 09:09:17 +0100
Subject: [PATCH 4/4] IBM Z: Fix fcontext routines

---
 src/asm/jump_s390x_sysv_elf_gas.S  | 257 +++++++++++++++++------------
 src/asm/make_s390x_sysv_elf_gas.S  | 176 ++++++++++----------
 src/asm/ontop_s390x_sysv_elf_gas.S | 238 ++++++++++++++------------
 3 files changed, 374 insertions(+), 297 deletions(-)

diff --git a/src/asm/jump_s390x_sysv_elf_gas.S b/src/asm/jump_s390x_sysv_elf_gas.S
index b2163cc..c2a578b 100644
--- a/libs/context/src/asm/jump_s390x_sysv_elf_gas.S
+++ b/libs/context/src/asm/jump_s390x_sysv_elf_gas.S
@@ -1,117 +1,156 @@
 /*******************************************************
-*                                                     *
-*  -------------------------------------------------  *
-*  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  *
-*  -------------------------------------------------  *
-*  |     0     |     8     |    16     |     24    |  *
-*  -------------------------------------------------  *
-*  |    R6     |    R7     |    R8     |    R9     |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  8  |  9  |  10 |  11 |  12 |  13 |  14 |  15 |  *
-*  -------------------------------------------------  *
-*  |     32    |    40     |     48    |     56    |  *
-*  -------------------------------------------------  *
-*  |    R10    |    R11    |     R12   |     R13   |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23 |  *
-*  -------------------------------------------------  *
-*  |     64    |    72     |     80    |     88    |  *
-*  -------------------------------------------------  *
-*  |   R14/LR  |    R15    |     F1    |     F3    |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  24 |  25 |  26 |  27 |  28 | 29  |           |  *
-*  -------------------------------------------------  *
-*  |     96    |    104    |    112    |    120    |  *
-*  -------------------------------------------------  *
-*  |    F5     |    F7     |     PC    |           |  *
-*  -------------------------------------------------  *
-* *****************************************************/
-
-.file  "jump_s390x_sysv_elf_gas.S"
+ *  -------------------------------------------------  *
+ *  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  *
+ *  -------------------------------------------------  *
+ *  |     0     |     8     |    16     |    24     |  *
+ *  -------------------------------------------------  *
+ *  |   t.fctx  |   t.data  |    r2     |    r6     |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  8  |  9  |  10 |  11 |  12 |  13 |  14 |  15 |  *
+ *  -------------------------------------------------  *
+ *  |     32    |    40     |     48    |     56    |  *
+ *  -------------------------------------------------  *
+ *  |     r7    |     r8    |     r9    |    r10    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23 |  *
+ *  -------------------------------------------------  *
+ *  |     64    |     72    |     80    |     88    |  *
+ *  -------------------------------------------------  *
+ *  |    r11    |    r12    |    r13    |    r14    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  24 |  25 |  26 |  27 |  28 | 29  |  30 |  31 |  *
+ *  -------------------------------------------------  *
+ *  |     96    |    104    |    112    |    120    |  *
+ *  -------------------------------------------------  *
+ *  |     f8    |     f9    |    f10    |    f11    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  32 |  33 |  34 |  35 |  36 |  37 |  38 |  39 |  *
+ *  -------------------------------------------------  *
+ *  |    128    |    136    |    144    |    152    |  *
+ *  -------------------------------------------------  *
+ *  |    f12    |    f13    |    f14    |    f15    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  40 |  41 |  42 |  43 |  44 |  45 |  46 |  47 |  *
+ *  -------------------------------------------------  *
+ *  |    160    |    168    |    176    |           |  *
+ *  -------------------------------------------------  *
+ *  |    fpc    |     pc    |           |           |  *
+ *  -------------------------------------------------  *
+ *******************************************************/
+
 .text
-.align  4 # According to the sample code in the ELF ABI docs
-.global jump_fcontext
-.type   jump_fcontext, @function
-
-#define GR_OFFSET	0
-#define LR_OFFSET	64
-#define SP_OFFSET	72
-#define FP_OFFSET	80
-#define PC_OFFSET	112
-#define L_CTX		120
-#define L_STACKFRAME	120
+.align	8
+.global	jump_fcontext
+.type	jump_fcontext, @function
+
+#define ARG_OFFSET         0
+#define GR_OFFSET	   16
+#define FP_OFFSET	   96
+#define FPC_OFFSET	   160
+#define PC_OFFSET	   168
+#define CONTEXT_SIZE	   176
+
+#define REG_SAVE_AREA_SIZE 160
+
+/*
+
+typedef void*   fcontext_t;
+
+struct transfer_t {
+   fcontext_t  fctx;
+   void    *   data;
+};
+
+transfer_t jump_fcontext( fcontext_t const to,
+			  void * data);
+
+Incoming args
+r2 - Hidden argument to the location where the return transfer_t needs to be returned
+r3 - Context we want to switch to
+r4 - Data pointer
+
+*/
 
 jump_fcontext:
-    
-    # Reserved the space for stack to store the data of current context
-    # before we jump to the new context.
-    aghi %r15,-L_STACKFRAME
-
-    # save the registers to the stack
-    stmg %r6, %r15, GR_OFFSET(%r15)
-
-    # save the floating point registers
-    std  %f0,FP_OFFSET(%r15)
-    std  %f3,FP_OFFSET+8(%r15)
-    std  %f5,FP_OFFSET+16(%r15)
-    std  %f7,FP_OFFSET+24(%r15)
-
-    # Save LR as PC
-    stg  %r14,PC_OFFSET(%r15)
-
-    # Store the SP pointing to the old context-data into R0
-    lgr	 %r0,%r15
-
-    # Get the SP pointing to the new context-data
-    # Note: Since the return type of the jump_fcontext is struct whose
-    # size is more than 8. The compiler automatically passes the 
-    # address of the transfer_t where the data needs to store into R2.
-
-    # Hence the first param passed to the jump_fcontext which represent
-    # the fctx we want to switch to is present in R3
-    # R2 --> Address of the return transfer_t struct
-    # R3 --> Context we want to switch to
-    # R4 --> Data
-    lgr	%r15,%r3
-
-    # Load the registers with the data present in context-data of the
-    # context we are going to switch to
-    lmg	%r6, %r14, GR_OFFSET(%r15)
-
-    # Restore Floating point registers
-    ld	 %f1,FP_OFFSET(%r15)
-    ld	 %f3,FP_OFFSET+8(%r15)
-    ld	 %f5,FP_OFFSET+16(%r15)
-    ld	 %f7,FP_OFFSET+24(%r15)
-
-    # Load PC
-    lg   %r1,PC_OFFSET(%r15)
-
-    # Adjust the stack 
-    aghi %r15,120
-
-    # R2 --> Address where the return transfer_t is stored
-    # R0 --> FCTX
-    # R4 --> DATA
-
-    # Store the elements to return transfer_t
-    stg %r15, 0(%r2)
-    stg %r4, 8(%r2)
-
-    # Note: The address in R2 points to the place where the return
-    # transfer_t is stored. Since context_function take transfer_t
-    # as first parameter. And R2 is the register which holds the
-    # first parameter value.
-
-    #jump to context
-    br  %r1
+	.machine "z10"
+	/* Reserve stack space to store the current context.  */
+	aghi	%r15,-CONTEXT_SIZE
 
-.size   jump_fcontext,.-jump_fcontext
-# Mark that we don't need executable stack.
-.section .note.GNU-stack,"",%progbits
+	/* Save the argument register holding the location of the return value.  */
+	stg	%r2,GR_OFFSET(%r15)
+
+	/* Save the call-saved general purpose registers.  */
+	stmg	%r6,%r14,GR_OFFSET+8(%r15)
+
+	/* Save call-saved floating point registers.  */
+	std	%f8,FP_OFFSET(%r15)
+	std	%f9,FP_OFFSET+8(%r15)
+	std	%f10,FP_OFFSET+16(%r15)
+	std	%f11,FP_OFFSET+24(%r15)
+	std	%f12,FP_OFFSET+32(%r15)
+	std	%f13,FP_OFFSET+40(%r15)
+	std	%f14,FP_OFFSET+48(%r15)
+	std	%f15,FP_OFFSET+56(%r15)
+
+	/* Save the return address as current pc.  */
+	stg	%r14,PC_OFFSET(%r15)
 
+	/* Save the floating point control register.  */
+	stfpc	FPC_OFFSET(%r15)
 
+	/* Backup the stack pointer pointing to the old context-data into r1.  */
+	lgr	 %r1,%r15
 
+	/* Load the new context pointer as stack pointer.  */
+	lgr	%r15,%r3
+
+	/* Restore the call-saved GPRs from the new context.  */
+	lmg	%r6,%r14,GR_OFFSET+8(%r15)
+
+	/* Restore call-saved floating point registers.  */
+	ld	%f8,FP_OFFSET(%r15)
+	ld	%f9,FP_OFFSET+8(%r15)
+	ld	%f10,FP_OFFSET+16(%r15)
+	ld	%f11,FP_OFFSET+24(%r15)
+	ld	%f12,FP_OFFSET+32(%r15)
+	ld	%f13,FP_OFFSET+40(%r15)
+	ld	%f14,FP_OFFSET+48(%r15)
+	ld	%f15,FP_OFFSET+56(%r15)
+
+	/* Load the floating point control register.  */
+	lfpc	FPC_OFFSET(%r15)
+
+	/* Restore PC - the location where we will jump to at the end.  */
+	lg	%r5,PC_OFFSET(%r15)
+
+	ltg	%r2,GR_OFFSET(%r15)
+	jnz	use_return_slot
+
+	/* We restore a make_fcontext context.  Use the function
+	   argument slot in the context we just saved and allocate the
+	   register save area for the target function.  */
+	la	%r2,ARG_OFFSET(%r1)
+	aghi	%r15,-REG_SAVE_AREA_SIZE
+
+use_return_slot:
+	/* Save the two fields in transfer_t.  When calling a
+	   make_fcontext function this becomes the function argument of
+	   the target function, otherwise it will be the return value of
+	   jump_fcontext.  */
+	stg	%r1,0(%r2)
+	stg	%r4,8(%r2)
+
+	/* Free the restored context.  */
+	aghi	%r15,CONTEXT_SIZE
+
+	/* Jump to the PC loaded from the new context.  */
+	br	%r5
+
+
+.size   jump_fcontext,.-jump_fcontext
+.section .note.GNU-stack,"",%progbits
diff --git a/src/asm/make_s390x_sysv_elf_gas.S b/src/asm/make_s390x_sysv_elf_gas.S
index d02856c..e7e2d5f 100644
--- a/libs/context/src/asm/make_s390x_sysv_elf_gas.S
+++ b/libs/context/src/asm/make_s390x_sysv_elf_gas.S
@@ -1,104 +1,108 @@
 /*******************************************************
-*                                                     *
-*  -------------------------------------------------  *
-*  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  *
-*  -------------------------------------------------  *
-*  |     0     |     8     |    16     |     24    |  *
-*  -------------------------------------------------  *
-*  |    R6     |    R7     |    R8     |    R9     |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  8  |  9  |  10 |  11 |  12 |  13 |  14 |  15 |  *
-*  -------------------------------------------------  *
-*  |     32    |    40     |     48    |     56    |  *
-*  -------------------------------------------------  *
-*  |    R10    |    R11    |     R12   |     R13   |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23 |  *
-*  -------------------------------------------------  *
-*  |     64    |    72     |     80    |     88    |  *
-*  -------------------------------------------------  *
-*  |   R14/LR  |    R15    |     F1    |     F3    |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  24 |  25 |  26 |  27 |  28 | 29  |           |  *
-*  -------------------------------------------------  *
-*  |     96    |    104    |    112    |    120    |  *
-*  -------------------------------------------------  *
-*  |    F5     |    F7     |     PC    |           |  *
-*  -------------------------------------------------  *
-* *****************************************************/
-
-.file  "make_s390x_sysv_elf_gas.S"
+ *  -------------------------------------------------  *
+ *  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  *
+ *  -------------------------------------------------  *
+ *  |     0     |     8     |    16     |    24     |  *
+ *  -------------------------------------------------  *
+ *  |   t.fctx  |   t.data  |    r2     |    r6     |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  8  |  9  |  10 |  11 |  12 |  13 |  14 |  15 |  *
+ *  -------------------------------------------------  *
+ *  |     32    |    40     |     48    |     56    |  *
+ *  -------------------------------------------------  *
+ *  |     r7    |     r8    |     r9    |    r10    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23 |  *
+ *  -------------------------------------------------  *
+ *  |     64    |     72    |     80    |     88    |  *
+ *  -------------------------------------------------  *
+ *  |    r11    |    r12    |    r13    |    r14    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  24 |  25 |  26 |  27 |  28 | 29  |  30 |  31 |  *
+ *  -------------------------------------------------  *
+ *  |     96    |    104    |    112    |    120    |  *
+ *  -------------------------------------------------  *
+ *  |     f8    |     f9    |    f10    |    f11    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  32 |  33 |  34 |  35 |  36 |  37 |  38 |  39 |  *
+ *  -------------------------------------------------  *
+ *  |    128    |    136    |    144    |    152    |  *
+ *  -------------------------------------------------  *
+ *  |    f12    |    f13    |    f14    |    f15    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  40 |  41 |  42 |  43 |  44 |  45 |  46 |  47 |  *
+ *  -------------------------------------------------  *
+ *  |    160    |    168    |    176    |           |  *
+ *  -------------------------------------------------  *
+ *  |    fpc    |     pc    |           |           |  *
+ *  -------------------------------------------------  *
+ *******************************************************/
+
 .text
-.align  4 # According to the sample code in the ELF ABI docs
-.global make_fcontext
-.type 	 make_fcontext, @function
-
-#define GR_OFFSET	0
-#define LR_OFFSET	64
-#define SP_OFFSET	72
-#define FP_OFFSET	80
-#define PC_OFFSET	112
-#define L_CTX		120
-#define L_STACKFRAME	120
+.align	8
+.global	make_fcontext
+.type	make_fcontext, @function
 
-make_fcontext:
+#define ARG_OFFSET         0
+#define GR_OFFSET	   16
+#define R14_OFFSET	   88
+#define FP_OFFSET	   96
+#define FPC_OFFSET	   160
+#define PC_OFFSET	   168
+#define CONTEXT_SIZE	   176
 
-		# make_fcontext takes in 3 arguments
-		# arg1 --> The address where the context needs to be made
-		# arg2 --> The size of the context
-		# arg3 --> The address of the context function
+/*
 
-		# According to the ELF ABI, the register R2 holds the first arg.
-		# R2 also acts as the register which holds return value
-		# Register R3 holds the second, R4 the third so on.
+fcontext_t make_fcontext( void * sp, std::size_t size, void (* fn)( transfer_t) );
 
-		# Shift the address in R2 to a lower 8 byte boundary
+Create and return a context below SP to call FN.
 
-		# This is done because according to the ELF ABI Doc, the stack needs
-		# to be 8 byte aligned.
-		# In order to do so, we need to make sure that the address is divisible
-		# by 8. We can check this, by checking if the the last 3 bits of the
-		# address is zero or not. If not AND it with `-8`. 
+Incoming args
+r2 - The stack location where to create the context
+r3 - The size of the context
+r4 - The address of the context function
 
-		# Here we AND the lower 16 bits of the memory address present in the 
-		# R2 with the bits 1111 1111 1111 1000 
-		nill    %r2,0xfff0
+*/
 
-		# Reserve space for context-data on context-stack.
-		# This is done by shifting the SP/address by 112 bytes.
-		aghi	%r2,-L_CTX
+make_fcontext:
+	.machine "z10"
+	/* Align the stack to an 8 byte boundary.  */
+	nill    %r2,0xfff0
 
-		# third arg of make_fcontext() == address of the context-function
-		# Store the address as a PC to jump in, whenever we call the 
-		# make_fcontext.
-		stg 	%r4,PC_OFFSET(%r2)
+	/* Allocate stack space for the context.  */
+	aghi	%r2,-CONTEXT_SIZE
 
-		# Save the address of finish as return-address for context-function
-		# This will be entered after context-function return
-		# The address of finish will be saved in Link register, this register
-		# specifies where we need to jump after the function executes
-		# completely.
-		larl 	%r1,finish
-		stg  	%r1,LR_OFFSET(%r2)
+	/* Set the r2 save slot to zero.  This indicates jump_fcontext
+	   that this is a special context.  */
+	mvghi	GR_OFFSET(%r2),0
 
-		# Return pointer to context data
-		# R14 acts as the link register
-		# R2 holds the address of the context stack. When we return from the
-		# make_fcontext, R2 is passed back.
-		br 	%r14 
+	/* Save the floating point control register.  */
+	stfpc	FPC_OFFSET(%r2)
 
-	finish:
+	/* Store the address of the target function as new pc.  */
+	stg	%r4,PC_OFFSET(%r2)
 
-		# In finish tasks, you load the exit code and exit the make_fcontext
-		# This is called when the context-function is entirely executed
+	/* Store a pointer to the finish routine as r14. If a function
+	   called via context routines just returns that value will be
+	   loaded and used as return address.  Hence the program will
+	   just exit.  */
+	larl	%r1,finish
+	stg	%r1,R14_OFFSET(%r2)
 
-		lghi 	%r2,0
-		brasl 	%r14,_exit@PLT
+	/* Return as usual with the new context returned in r2.  */
+	br	%r14
+
+finish:
+	/* In finish tasks, you load the exit code and exit the
+	   make_fcontext This is called when the context-function is
+	   entirely executed.  */
+	lghi	%r2,0
+	brasl	%r14,_exit@PLT
 
 .size   make_fcontext,.-make_fcontext
-# Mark that we don't need executable stack.
 .section .note.GNU-stack,"",%progbits
-
diff --git a/src/asm/ontop_s390x_sysv_elf_gas.S b/src/asm/ontop_s390x_sysv_elf_gas.S
index 4488654..709b3d6 100644
--- a/libs/context/src/asm/ontop_s390x_sysv_elf_gas.S
+++ b/libs/context/src/asm/ontop_s390x_sysv_elf_gas.S
@@ -1,112 +1,146 @@
 /*******************************************************
-*                                                     *
-*  -------------------------------------------------  *
-*  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  *
-*  -------------------------------------------------  *
-*  |     0     |     8     |    16     |     24    |  *
-*  -------------------------------------------------  *
-*  |    R6     |    R7     |    R8     |    R9     |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  8  |  9  |  10 |  11 |  12 |  13 |  14 |  15 |  *
-*  -------------------------------------------------  *
-*  |     32    |    40     |     48    |     56    |  *
-*  -------------------------------------------------  *
-*  |    R10    |    R11    |     R12   |     R13   |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23 |  *
-*  -------------------------------------------------  *
-*  |     64    |    72     |     80    |     88    |  *
-*  -------------------------------------------------  *
-*  |   R14/LR  |    R15    |     F1    |     F3    |  *
-*  -------------------------------------------------  *
-*  -------------------------------------------------  *
-*  |  24 |  25 |  26 |  27 |  28 | 29  |           |  *
-*  -------------------------------------------------  *
-*  |     96    |    104    |    112    |    120    |  *
-*  -------------------------------------------------  *
-*  |    F5     |    F7     |     PC    |           |  *
-*  -------------------------------------------------  *
-* *****************************************************/
-
-.file  "ontop_s390x_sysv_elf_gas.S"
+ *  -------------------------------------------------  *
+ *  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  *
+ *  -------------------------------------------------  *
+ *  |     0     |     8     |    16     |    24     |  *
+ *  -------------------------------------------------  *
+ *  |   t.fctx  |   t.data  |    r2     |    r6     |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  8  |  9  |  10 |  11 |  12 |  13 |  14 |  15 |  *
+ *  -------------------------------------------------  *
+ *  |     32    |    40     |     48    |     56    |  *
+ *  -------------------------------------------------  *
+ *  |     r7    |     r8    |     r9    |    r10    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  16 |  17 |  18 |  19 |  20 |  21 |  22 |  23 |  *
+ *  -------------------------------------------------  *
+ *  |     64    |     72    |     80    |     88    |  *
+ *  -------------------------------------------------  *
+ *  |    r11    |    r12    |    r13    |    r14    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  24 |  25 |  26 |  27 |  28 | 29  |  30 |  31 |  *
+ *  -------------------------------------------------  *
+ *  |     96    |    104    |    112    |    120    |  *
+ *  -------------------------------------------------  *
+ *  |     f8    |     f9    |    f10    |    f11    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  32 |  33 |  34 |  35 |  36 |  37 |  38 |  39 |  *
+ *  -------------------------------------------------  *
+ *  |    128    |    136    |    144    |    152    |  *
+ *  -------------------------------------------------  *
+ *  |    f12    |    f13    |    f14    |    f15    |  *
+ *  -------------------------------------------------  *
+ *  -------------------------------------------------  *
+ *  |  40 |  41 |  42 |  43 |  44 |  45 |  46 |  47 |  *
+ *  -------------------------------------------------  *
+ *  |    160    |    168    |    176    |           |  *
+ *  -------------------------------------------------  *
+ *  |    fpc    |     pc    |           |           |  *
+ *  -------------------------------------------------  *
+ *******************************************************/
+
 .text
-.align  4 # According to the sample code in the ELF ABI docs
+.align  8
 .global ontop_fcontext
 .type   ontop_fcontext, @function
 
-#define GR_OFFSET	0
-#define LR_OFFSET	64
-#define SP_OFFSET	72
-#define FP_OFFSET	80
-#define PC_OFFSET	112
-#define L_CTX		120
+#define ARG_OFFSET         0
+#define GR_OFFSET	   16
+#define R14_OFFSET	   88
+#define FP_OFFSET	   96
+#define FPC_OFFSET	   160
+#define PC_OFFSET	   168
+#define CONTEXT_SIZE	   176
+
+
+/*
+
+typedef void*   fcontext_t;
+
+struct transfer_t {
+   fcontext_t  fctx;
+   void    *   data;
+};
+
+transfer_t ontop_fcontext( fcontext_t const to,
+			   void * vp,
+			   transfer_t (* fn)( transfer_t) );
+
+Incoming args
+r2 - Hidden argument to the location where the return transfer_t needs to be returned
+r3 - Target context
+r4 - Data pointer
+r5 - Function to be executed
+
+This implementation assumes that ontop_fcontext will never be called with target contexts
+created via make_fcontext.
+
+*/
 
 ontop_fcontext:
-    
-    # Reserved the space for stack to store the data of current context
-    # before we jump to the new context.
-    aghi %r15,-L_CTX
-
-    # save the registers to the stack
-    stmg %r6, %r15, GR_OFFSET(%r15)
-
-    # save the floating point registers
-    std  %f0,FP_OFFSET(%r15)
-    std  %f3,FP_OFFSET+8(%r15)
-    std  %f5,FP_OFFSET+16(%r15)
-    std  %f7,FP_OFFSET+24(%r15)
-    # Save LR as PC
-    stg  %r14,PC_OFFSET(%r15)
-
-    # Store the SP pointing to the old context-data into R0
-    lgr  %r0,%r15
-
-    # Get the SP pointing to the new context-data
-    # Note: Since the return type of the jump_fcontext is struct whose
-    # size is more than 8. The compiler automatically passes the 
-    # address of the transfer_t where the data needs to store into R2.
-
-    # Hence the first param passed to the jump_fcontext which represent
-    # the fctx we want to switch to is present in R3
-    # R2 --> Address of the return transfer_t struct
-    # R3 --> Context we want to switch to
-    # R4 --> Data
-    lgr  %r15,%r3
-
-    # Load the registers with the data present in context-data of the
-    # context we are going to switch to
-    lmg  %r6,%r15,GR_OFFSET(%r15)
-
-    # Restore Floating point registers
-    ld	 %f1,FP_OFFSET(%r15)
-    ld	 %f3,FP_OFFSET+8(%r15)
-    ld	 %f5,FP_OFFSET+16(%r15)
-    ld	 %f7,FP_OFFSET+24(%r15)
-
-    # Skip PC
-
-    # Adjust the stack
-    aghi %r15,L_CTX
-
-    # R2 --> Address where the return transfer_t is stored
-    # R0 --> FCTX
-    # R4 --> DATA
-    # R5 --> Context function
-
-    # Store the elements to return transfer_t
-    stg  %r15, 0(%r2)
-    stg  %r4, 8(%r2)
-
-    # Note: The address in R2 points to the place where the return
-    # transfer_t is stored. Since context_function take transfer_t
-    # as first parameter. And R2 is the register which holds the
-    # first parameter value.
-
-    #jump to context function
-    br 	%r5
+	/* Reserve stack space to store the current context.  */
+	aghi	%r15,-CONTEXT_SIZE
+
+	/* Save the argument register holding the location of the return value.  */
+	stg	%r2,GR_OFFSET(%r15)
+
+	/* Save the call-saved general purpose registers.  */
+	stmg	%r6,%r14,GR_OFFSET+8(%r15)
+
+	/* Save call-saved floating point registers.  */
+	std	%f8,FP_OFFSET(%r15)
+	std	%f9,FP_OFFSET+8(%r15)
+	std	%f10,FP_OFFSET+16(%r15)
+	std	%f11,FP_OFFSET+24(%r15)
+	std	%f12,FP_OFFSET+32(%r15)
+	std	%f13,FP_OFFSET+40(%r15)
+	std	%f14,FP_OFFSET+48(%r15)
+	std	%f15,FP_OFFSET+56(%r15)
+
+	/* Save the return address as current pc.  */
+	stg	%r14,PC_OFFSET(%r15)
+
+	/* Save the floating point control register.  */
+	stfpc   FPC_OFFSET(%r15)
+
+	/* Backup the stack pointer pointing to the old context-data into r1.  */
+	lgr	%r1,%r15
+
+	/* Load the new context pointer as stack pointer.  */
+	lgr	%r15,%r3
+
+	/* Restore the call-saved GPRs from the new context.  */
+	lmg	%r6,%r14,GR_OFFSET+8(%r15)
+
+	/* Restore call-saved floating point registers.  */
+	ld	%f8,FP_OFFSET(%r15)
+	ld	%f9,FP_OFFSET+8(%r15)
+	ld	%f10,FP_OFFSET+16(%r15)
+	ld	%f11,FP_OFFSET+24(%r15)
+	ld	%f12,FP_OFFSET+32(%r15)
+	ld	%f13,FP_OFFSET+40(%r15)
+	ld	%f14,FP_OFFSET+48(%r15)
+	ld	%f15,FP_OFFSET+56(%r15)
+
+	/* Load the floating point control register.  */
+	lfpc   FPC_OFFSET(%r15)
+
+	/* Store the transfer_t values located in the saved context.  */
+	stg	%r1,0(%r1)	       /* transfer_t.fctx = old context */
+	stg	%r4,8(%r1)             /* transfer_t.data = data */
+
+	/* Set up the arguments for the target function.  */
+	lg	%r2,GR_OFFSET(%r15)
+	lgr	%r3,%r1
+
+	/* Deallocate the context.  */
+	aghi	%r15,CONTEXT_SIZE
+
+	br	%r5
 
 .size   ontop_fcontext,.-ontop_fcontext
-# Mark that we don't need executable stack.
 .section .note.GNU-stack,"",%progbits
-- 
2.18.1