From 94216c60c43a30e39fbc4f347450768699c6c77c Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Mon, 1 Apr 2019 23:02:12 -0500
Subject: [PATCH] test ability to pass 10 args through makecontext

---
 test_libucontext.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/test_libucontext.c b/test_libucontext.c
index 121cc3e..e5eac83 100644
--- a/test_libucontext.c
+++ b/test_libucontext.c
@@ -6,13 +6,32 @@
 #include <stdio.h>
 #include <ucontext.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 
 static ucontext_t ctx[3];
 
 
-static void f1 (void) {
+static void check_arg(int actual, int expected) {
+	if (actual == expected) return;
+	fprintf(stderr, "argument has wrong value.  got %d, expected %d.\n", actual, expected);
+	abort();
+}
+
+
+static void f1 (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
+	check_arg(a, 1);
+	check_arg(b, 2);
+	check_arg(c, 3);
+	check_arg(d, 4);
+	check_arg(e, 5);
+	check_arg(f, 6);
+	check_arg(g, 7);
+	check_arg(h, 8);
+	check_arg(i, 9);
+	check_arg(j, 10);
+
 	printf("start f1\n");
 	swapcontext(&ctx[1], &ctx[2]);
 	printf("finish f1\n");
@@ -40,7 +59,7 @@ int main (int argc, const char *argv[]) {
 	ctx[1].uc_stack.ss_sp = st1;
 	ctx[1].uc_stack.ss_size = sizeof st1;
 	ctx[1].uc_link = &ctx[0];
-	makecontext(&ctx[1], f1, 0);
+	makecontext(&ctx[1], f1, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
 
 
 	getcontext(&ctx[2]);
From cb59e7ee957b389578a3f973484ae3198f6cfed1 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Mon, 1 Apr 2019 23:03:21 -0500
Subject: [PATCH] test calls to getcontext without makecontext

---
 test_libucontext.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/test_libucontext.c b/test_libucontext.c
index e5eac83..a4a9b4c 100644
--- a/test_libucontext.c
+++ b/test_libucontext.c
@@ -48,6 +48,7 @@ static void f2 (void) {
 int main (int argc, const char *argv[]) {
 	char st1[8192];
 	char st2[8192];
+	volatile int done = 0;
 
 
 	/* poison each coroutine's stack memory for debugging purposes */
@@ -70,5 +71,16 @@ int main (int argc, const char *argv[]) {
 
 
 	swapcontext(&ctx[0], &ctx[2]);
+
+
+	/* test ability to use getcontext/setcontext without makecontext */
+	getcontext(&ctx[1]);
+	printf("done = %d\n", done);
+	if (done++ == 0) setcontext(&ctx[1]);
+	if (done != 2) {
+		fprintf(stderr, "wrong value for done.  got %d, expected 2\n", done);
+		abort();
+	}
+
 	return 0;
 }
From b6a9b5e279123f16569e0fd9f8ff14ff04bed7a3 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 13:32:03 -0500
Subject: [PATCH] ppc32: fix stack alignment

The stack should be 16-byte aligned, not 8 mod 16.
---
 arch/ppc/makecontext.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/ppc/makecontext.c b/arch/ppc/makecontext.c
index c562ea5..1b9efdf 100644
--- a/arch/ppc/makecontext.c
+++ b/arch/ppc/makecontext.c
@@ -37,7 +37,7 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 
 	sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
 	sp -= (uc_link + 1);
-	sp = (greg_t *) (((uintptr_t) sp & -16L) - 8);
+	sp = (greg_t *) ((uintptr_t) sp & -16L);
 
 	ucp->uc_mcontext.gregs[REG_NIP]  = (uintptr_t) func;
 	ucp->uc_mcontext.gregs[REG_LNK]  = (uintptr_t) &__start_context;
From b9bd4045fb34f060d6cf37fc7da7ab13b91462de Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 13:35:00 -0500
Subject: [PATCH] ppc32/64: fix back chain pointer

The ABI states that sp[0] should point to the previous stack frame, or be
zero if there is no previous stack frame.  makecontext previously set this
slot to point to the __start_context function, rather than to a valid
stack frame.
---
 arch/ppc/makecontext.c   | 2 +-
 arch/ppc64/makecontext.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/ppc/makecontext.c b/arch/ppc/makecontext.c
index 1b9efdf..729f465 100644
--- a/arch/ppc/makecontext.c
+++ b/arch/ppc/makecontext.c
@@ -44,7 +44,7 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	ucp->uc_mcontext.gregs[REG_R31]  = (uintptr_t) ucp->uc_link;
 	ucp->uc_mcontext.gregs[REG_SP]   = (uintptr_t) sp;
 
-	sp[0] = (uintptr_t) &__start_context;
+	sp[0] = 0;
 	sp[uc_link] = (uintptr_t) ucp->uc_link;
 	argp = &sp[2];
 
diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index 9d6b998..91fb579 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -45,7 +45,7 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	ucp->uc_mcontext.gp_regs[REG_ENTRY] = (uintptr_t) func;
 	ucp->uc_mcontext.gp_regs[REG_R31]   = (uintptr_t) ucp->uc_link;
 
-	sp[0] = (uintptr_t) &__start_context;
+	sp[0] = 0;
 	sp[uc_link] = (uintptr_t) ucp->uc_link;
 	argp = &sp[2];
 
From b500b054c7cf412a6042496afa08b4302f7ed929 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 13:38:36 -0500
Subject: [PATCH] ppc32/64: don't store uc_link on the stack

This was previously stored either in the CR (ppc64) or LR (ppc32) save
area of the stack, or to one of the parameter save slots.

In either case, the saved value was unused.  This value is also passed
to __start_context via r31, so there's no need to pass it on the stack.
---
 arch/ppc/makecontext.c   | 6 ++----
 arch/ppc64/makecontext.c | 6 ++----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/arch/ppc/makecontext.c b/arch/ppc/makecontext.c
index 729f465..2b7ea67 100644
--- a/arch/ppc/makecontext.c
+++ b/arch/ppc/makecontext.c
@@ -30,13 +30,12 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	greg_t *sp, *argp;
 	va_list va;
 	int i;
-	unsigned int uc_link, stack_args;
+	unsigned int stack_args;
 
 	stack_args = argc > 8 ? argc - 8 : 0;
-	uc_link = stack_args + 1;
 
 	sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
-	sp -= (uc_link + 1);
+	sp -= stack_args + 2;
 	sp = (greg_t *) ((uintptr_t) sp & -16L);
 
 	ucp->uc_mcontext.gregs[REG_NIP]  = (uintptr_t) func;
@@ -45,7 +44,6 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	ucp->uc_mcontext.gregs[REG_SP]   = (uintptr_t) sp;
 
 	sp[0] = 0;
-	sp[uc_link] = (uintptr_t) ucp->uc_link;
 	argp = &sp[2];
 
 	va_start(va, argc);
diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index 91fb579..b060371 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -30,13 +30,12 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	greg_t *sp, *argp;
 	va_list va;
 	int i;
-	unsigned int uc_link, stack_args;
+	unsigned int stack_args;
 
 	stack_args = argc > 8 ? argc - 8 : 0;
-	uc_link = stack_args + 1;
 
 	sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
-	sp -= (uc_link + 1);
+	sp -= stack_args + 2;
 	sp = (greg_t *) (((uintptr_t) sp & -16L));
 
 	ucp->uc_mcontext.gp_regs[REG_NIP]   = (uintptr_t) func;
@@ -46,7 +45,6 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	ucp->uc_mcontext.gp_regs[REG_R31]   = (uintptr_t) ucp->uc_link;
 
 	sp[0] = 0;
-	sp[uc_link] = (uintptr_t) ucp->uc_link;
 	argp = &sp[2];
 
 	va_start(va, argc);
From 55168fcb1809dde45c99450f1f3be27716c473db Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 13:57:53 -0500
Subject: [PATCH] ppc32/64: simplify storage of stack parameters

The switch statement is simpler as an if/else, and removing the argp
variable makes the code more symmetric between the register and stack
parameter cases.
---
 arch/ppc/makecontext.c   | 24 ++++++------------------
 arch/ppc64/makecontext.c | 24 ++++++------------------
 2 files changed, 12 insertions(+), 36 deletions(-)

diff --git a/arch/ppc/makecontext.c b/arch/ppc/makecontext.c
index 2b7ea67..4a404a4 100644
--- a/arch/ppc/makecontext.c
+++ b/arch/ppc/makecontext.c
@@ -27,7 +27,7 @@ extern void __start_context(void);
 void
 __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 {
-	greg_t *sp, *argp;
+	greg_t *sp;
 	va_list va;
 	int i;
 	unsigned int stack_args;
@@ -44,27 +44,15 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	ucp->uc_mcontext.gregs[REG_SP]   = (uintptr_t) sp;
 
 	sp[0] = 0;
-	argp = &sp[2];
 
 	va_start(va, argc);
 
-	for (i = 0; i < argc; i++)
-		switch (i)
-		{
-		case 0:
-		case 1:
-		case 2:
-		case 3:
-		case 4:
-		case 5:
-		case 6:
-		case 7:
+	for (i = 0; i < argc; i++) {
+		if (i < 8)
 			ucp->uc_mcontext.gregs[i + 3] = va_arg (va, greg_t);
-			break;
-		default:
-			*argp++ = va_arg (va, greg_t);
-			break;
-		}
+		else
+			sp[i-8 + 2] = va_arg (va, greg_t);
+	}
 
 	va_end(va);
 }
diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index b060371..962f98a 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -27,7 +27,7 @@ extern void __start_context(void);
 void
 __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 {
-	greg_t *sp, *argp;
+	greg_t *sp;
 	va_list va;
 	int i;
 	unsigned int stack_args;
@@ -45,27 +45,15 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	ucp->uc_mcontext.gp_regs[REG_R31]   = (uintptr_t) ucp->uc_link;
 
 	sp[0] = 0;
-	argp = &sp[2];
 
 	va_start(va, argc);
 
-	for (i = 0; i < argc; i++)
-		switch (i)
-		{
-		case 0:
-		case 1:
-		case 2:
-		case 3:
-		case 4:
-		case 5:
-		case 6:
-		case 7:
+	for (i = 0; i < argc; i++) {
+		if (i < 8)
 			ucp->uc_mcontext.gp_regs[i + 3] = va_arg (va, greg_t);
-			break;
-		default:
-			*argp++ = va_arg (va, greg_t);
-			break;
-		}
+		else
+			sp[i-8 + 2] = va_arg (va, greg_t);
+	}
 
 	va_end(va);
 }
From 8ea5f548b9146ffeea2074a33a06bbbd07a74402 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 14:01:10 -0500
Subject: [PATCH] ppc64: fix makecontext with more than 8 parameters

The ELFv2 ABI used on PPC64 differs from the ELFv1 ABI used on PPC32 here.
On PPC64, once there are any parameters that need to be passed on the
stack, space needs to be reserved on the stack to pass all parameters.
Parameters 0-7 are still only passed by register, but if the callee needs
to spill them, it can use the stack space reserved for the corresponding
parameter to do so.
---
 arch/ppc64/makecontext.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index 962f98a..ea980e9 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -32,7 +32,7 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	int i;
 	unsigned int stack_args;
 
-	stack_args = argc > 8 ? argc - 8 : 0;
+	stack_args = argc > 8 ? argc : 0;
 
 	sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
 	sp -= stack_args + 2;
@@ -52,7 +52,7 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 		if (i < 8)
 			ucp->uc_mcontext.gp_regs[i + 3] = va_arg (va, greg_t);
 		else
-			sp[i-8 + 2] = va_arg (va, greg_t);
+			sp[i + 2] = va_arg (va, greg_t);
 	}
 
 	va_end(va);
From a00a05ce2950ca3b306f8ccc3e817ea8cd675015 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 14:03:47 -0500
Subject: [PATCH] ppc64: fix incorrect position of parameters within stack
 frame

On PPC64, there are 4 register-sized stack slots below the parameter save
area, which is different from the 2 stack slots on PPC32.
---
 arch/ppc64/makecontext.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index ea980e9..a4c1bf9 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -35,7 +35,7 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 	stack_args = argc > 8 ? argc : 0;
 
 	sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
-	sp -= stack_args + 2;
+	sp -= stack_args + 4;
 	sp = (greg_t *) (((uintptr_t) sp & -16L));
 
 	ucp->uc_mcontext.gp_regs[REG_NIP]   = (uintptr_t) func;
@@ -52,7 +52,7 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
 		if (i < 8)
 			ucp->uc_mcontext.gp_regs[i + 3] = va_arg (va, greg_t);
 		else
-			sp[i + 2] = va_arg (va, greg_t);
+			sp[i + 4] = va_arg (va, greg_t);
 	}
 
 	va_end(va);
From 40d07758a5677e8869d7a62a499236bb6ed01897 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 14:09:25 -0500
Subject: [PATCH] ppc32/64: correct signature of function parameter to
 makecontext

Because makecontext can pass a set of integer arguments to the provided
function, it is incorrect to require that this function accept no
parameters.
---
 arch/ppc/makecontext.c   | 2 +-
 arch/ppc64/makecontext.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/ppc/makecontext.c b/arch/ppc/makecontext.c
index 4a404a4..0633c0f 100644
--- a/arch/ppc/makecontext.c
+++ b/arch/ppc/makecontext.c
@@ -25,7 +25,7 @@ extern void __start_context(void);
 
 
 void
-__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
+__makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
 {
 	greg_t *sp;
 	va_list va;
diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index a4c1bf9..8a293b5 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -25,7 +25,7 @@ extern void __start_context(void);
 
 
 void
-__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
+__makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
 {
 	greg_t *sp;
 	va_list va;
From edf69879eadaec0c72ba7ef5e7d2389946c6644b Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 14:09:39 -0500
Subject: [PATCH] ppc64: remove unnecessary parentheses

---
 arch/ppc64/makecontext.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index 8a293b5..84d390a 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -36,7 +36,7 @@ __makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
 
 	sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
 	sp -= stack_args + 4;
-	sp = (greg_t *) (((uintptr_t) sp & -16L));
+	sp = (greg_t *) ((uintptr_t) sp & -16L);
 
 	ucp->uc_mcontext.gp_regs[REG_NIP]   = (uintptr_t) func;
 	ucp->uc_mcontext.gp_regs[REG_LNK]   = (uintptr_t) &__start_context;
From 29eac4259adfd85e0f4946a1080bb9e3f8c0cc2e Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 14:10:28 -0500
Subject: [PATCH] ppc32/64: remove unused includes

---
 arch/ppc/makecontext.c   | 2 --
 arch/ppc64/makecontext.c | 2 --
 2 files changed, 4 deletions(-)

diff --git a/arch/ppc/makecontext.c b/arch/ppc/makecontext.c
index 0633c0f..7214a40 100644
--- a/arch/ppc/makecontext.c
+++ b/arch/ppc/makecontext.c
@@ -11,10 +11,8 @@
  */
 
 #define _GNU_SOURCE
-#include <stddef.h>
 #include <stdarg.h>
 #include <signal.h>
-#include <string.h>
 #include <stdint.h>
 
 
diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index 84d390a..2650f56 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -11,10 +11,8 @@
  */
 
 #define _GNU_SOURCE
-#include <stddef.h>
 #include <stdarg.h>
 #include <signal.h>
-#include <string.h>
 #include <stdint.h>
 
 
From 90ff6330e62c8f836016668c9f769af365b257cb Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 5 Apr 2019 14:11:21 -0500
Subject: [PATCH] ppc32/64: update copyright

---
 arch/ppc/makecontext.c   | 1 +
 arch/ppc64/makecontext.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/ppc/makecontext.c b/arch/ppc/makecontext.c
index 7214a40..51c492f 100644
--- a/arch/ppc/makecontext.c
+++ b/arch/ppc/makecontext.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c
index 2650f56..43da557 100644
--- a/arch/ppc64/makecontext.c
+++ b/arch/ppc64/makecontext.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
From 2610c7faa7b9c4114d53bb659264a6be238cd2a3 Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Sat, 23 Feb 2019 17:12:37 -0600
Subject: [PATCH] ppc32/64: rewrite get/set/swapcontext in assembly

getcontext cannot be correctly implemented in C.

If this calls another function, as it does to call syscall, it needs to
first spill its return address to the stack.  If, after getcontext returns,
its caller then calls other functions, this saved return address can be
clobbered.  When the context saved by getcontext is later restored, the
(now clobbered) return address will be reloaded from the stack, and the
second return from getcontext will return to the wrong location.

Because the powerpc swapcontext syscall allows either the old context or
new context pointers to be null, it is usable for implementing all of
get/set/swapcontext.

We therefore rewrite swapcontext in assembly, and get/setcontext as simple
assembly function wrappers around swapcontext.

The one piece we keep in C is the code to check the return value of the
system call and to set errno.  This code was actually unnecessary before --
libc does this within syscall.  However, now that the system call is made
directly in assembly, bypassing libc, it is truly necessary.  Because errno
is thread-local and the details of how to set it can vary by libc, this
code remains written in C.
---
 Makefile                                      | 10 +----
 README.md                                     |  2 +-
 arch/ppc/getcontext.S                         | 20 +++++++++
 arch/ppc/{getcontext.c => retfromsyscall.c}   | 30 +++----------
 arch/ppc/setcontext.S                         | 21 +++++++++
 arch/ppc/setcontext.c                         | 45 -------------------
 arch/ppc/swapcontext.S                        | 23 ++++++++++
 arch/ppc/swapcontext.c                        | 45 -------------------
 arch/ppc64/getcontext.S                       | 25 +++++++++++
 arch/ppc64/{getcontext.c => retfromsyscall.c} | 30 +++----------
 arch/ppc64/setcontext.S                       | 26 +++++++++++
 arch/ppc64/setcontext.c                       | 45 -------------------
 arch/ppc64/swapcontext.S                      | 28 ++++++++++++
 arch/ppc64/swapcontext.c                      | 45 -------------------
 14 files changed, 156 insertions(+), 239 deletions(-)
 create mode 100644 arch/ppc/getcontext.S
 rename arch/ppc/{getcontext.c => retfromsyscall.c} (53%)
 create mode 100644 arch/ppc/setcontext.S
 delete mode 100644 arch/ppc/setcontext.c
 create mode 100644 arch/ppc/swapcontext.S
 delete mode 100644 arch/ppc/swapcontext.c
 create mode 100644 arch/ppc64/getcontext.S
 rename arch/ppc64/{getcontext.c => retfromsyscall.c} (53%)
 create mode 100644 arch/ppc64/setcontext.S
 delete mode 100644 arch/ppc64/setcontext.c
 create mode 100644 arch/ppc64/swapcontext.S
 delete mode 100644 arch/ppc64/swapcontext.c

diff --git a/Makefile b/Makefile
index 51365a3..d6ff1b0 100644
--- a/Makefile
+++ b/Makefile
@@ -2,14 +2,8 @@ ARCH := $(shell uname -m)
 
 CFLAGS = -ggdb3 -O2 -Wall -Iarch/${ARCH}
 
-LIBUCONTEXT_C_SRC = \
-	arch/${ARCH}/makecontext.c
-
-LIBUCONTEXT_S_SRC = \
-	arch/${ARCH}/getcontext.S \
-	arch/${ARCH}/setcontext.S \
-	arch/${ARCH}/swapcontext.S \
-	arch/${ARCH}/startcontext.S
+LIBUCONTEXT_C_SRC = $(wildcard arch/${ARCH}/*.c)
+LIBUCONTEXT_S_SRC = $(wildcard arch/${ARCH}/*.S)
 
 LIBUCONTEXT_OBJ = ${LIBUCONTEXT_C_SRC:.c=.o} ${LIBUCONTEXT_S_SRC:.S=.o}
 LIBUCONTEXT_SOVERSION = 0
diff --git a/README.md b/README.md
index 6bd4493..27d3d0b 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ Right now these archs are supported and should work on bare metal:
  * aarch64
  * s390x
 
-These archs require kernel assistance and use a syscall (the only assembly is the trampoline):
+These archs require kernel assistance and use a syscall:
 
  * ppc
  * ppc64 (ELFv2 ABI spec only, ELFv1 not supported)
diff --git a/arch/ppc/getcontext.S b/arch/ppc/getcontext.S
new file mode 100644
index 0000000..beffaf5
--- /dev/null
+++ b/arch/ppc/getcontext.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied.  In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+.global __getcontext
+.hidden __swapcontext
+__getcontext:
+	li 4, 0
+	b __swapcontext@local
+
+.weak getcontext
+getcontext = __getcontext
diff --git a/arch/ppc/getcontext.c b/arch/ppc/retfromsyscall.c
similarity index 53%
rename from arch/ppc/getcontext.c
rename to arch/ppc/retfromsyscall.c
index 5da9dfb..3ad43c0 100644
--- a/arch/ppc/getcontext.c
+++ b/arch/ppc/retfromsyscall.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -10,36 +11,15 @@
  * from the use of this software.
  */
 
-#define _GNU_SOURCE
-#include <stddef.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <string.h>
-#include <stdint.h>
 #include <errno.h>
-#include <unistd.h>
-#include <sys/syscall.h>
 
-
-int
-__getcontext(ucontext_t *ucp)
+__attribute__ ((visibility ("hidden")))
+int __retfromsyscall(long retval)
 {
-#ifdef SYS_swapcontext
-	int r;
-
-	r = syscall(SYS_swapcontext, ucp, NULL, sizeof(ucontext_t));
-	if (r < 0)
-	{
-		errno = -r;
+	if (retval < 0) {
+		errno = -retval;
 		return -1;
 	}
-
 	return 0;
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
 }
 
-
-extern __typeof(__getcontext) getcontext __attribute__((weak, __alias__("__getcontext")));
diff --git a/arch/ppc/setcontext.S b/arch/ppc/setcontext.S
new file mode 100644
index 0000000..89e6de0
--- /dev/null
+++ b/arch/ppc/setcontext.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied.  In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+.global __setcontext
+.hidden __swapcontext
+__setcontext:
+	mr 4, 3
+	li 3, 0
+	b __swapcontext@local
+
+.weak setcontext
+setcontext = __setcontext
diff --git a/arch/ppc/setcontext.c b/arch/ppc/setcontext.c
deleted file mode 100644
index 59c65b4..0000000
--- a/arch/ppc/setcontext.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * This software is provided 'as is' and without any warranty, express or
- * implied.  In no event shall the authors be liable for any damages arising
- * from the use of this software.
- */
-
-#define _GNU_SOURCE
-#include <stddef.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-
-
-int
-__setcontext(const ucontext_t *ucp)
-{
-#ifdef SYS_swapcontext
-	int r;
-
-	r = syscall(SYS_swapcontext, NULL, (void *) ucp, sizeof(ucontext_t));
-	if (r < 0)
-	{
-		errno = -r;
-		return -1;
-	}
-
-	return r;
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-
-extern __typeof(__setcontext) setcontext __attribute__((weak, __alias__("__setcontext")));
diff --git a/arch/ppc/swapcontext.S b/arch/ppc/swapcontext.S
new file mode 100644
index 0000000..24b6655
--- /dev/null
+++ b/arch/ppc/swapcontext.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied.  In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+.global __swapcontext
+__swapcontext:
+	li 0, 249     # SYS_swapcontext
+	li 5, 1184    # sizeof(ucontext_t)
+	sc
+
+.hidden __retfromsyscall
+	b __retfromsyscall@local
+
+.weak swapcontext
+swapcontext = __swapcontext
diff --git a/arch/ppc/swapcontext.c b/arch/ppc/swapcontext.c
deleted file mode 100644
index af14bc2..0000000
--- a/arch/ppc/swapcontext.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * This software is provided 'as is' and without any warranty, express or
- * implied.  In no event shall the authors be liable for any damages arising
- * from the use of this software.
- */
-
-#define _GNU_SOURCE
-#include <stddef.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-
-
-int
-__swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
-{
-#ifdef SYS_swapcontext
-	int r;
-
-	r = syscall(SYS_swapcontext, oucp, ucp, sizeof(ucontext_t));
-	if (r < 0)
-	{
-		errno = -r;
-		return -1;
-	}
-
-	return r;
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-
-extern __typeof(__swapcontext) swapcontext __attribute__((weak, __alias__("__swapcontext")));
diff --git a/arch/ppc64/getcontext.S b/arch/ppc64/getcontext.S
new file mode 100644
index 0000000..935edd2
--- /dev/null
+++ b/arch/ppc64/getcontext.S
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied.  In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+.global __getcontext
+.hidden __swapcontext
+__getcontext:
+	addis 2, 12, .TOC.-__getcontext@ha
+	addi  2, 12, .TOC.-__getcontext@l
+
+	.localentry __getcontext,.-__getcontext
+
+	li 4, 0
+	b __swapcontext
+
+.weak getcontext
+getcontext = __getcontext
diff --git a/arch/ppc64/getcontext.c b/arch/ppc64/retfromsyscall.c
similarity index 53%
rename from arch/ppc64/getcontext.c
rename to arch/ppc64/retfromsyscall.c
index 5da9dfb..3ad43c0 100644
--- a/arch/ppc64/getcontext.c
+++ b/arch/ppc64/retfromsyscall.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -10,36 +11,15 @@
  * from the use of this software.
  */
 
-#define _GNU_SOURCE
-#include <stddef.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <string.h>
-#include <stdint.h>
 #include <errno.h>
-#include <unistd.h>
-#include <sys/syscall.h>
 
-
-int
-__getcontext(ucontext_t *ucp)
+__attribute__ ((visibility ("hidden")))
+int __retfromsyscall(long retval)
 {
-#ifdef SYS_swapcontext
-	int r;
-
-	r = syscall(SYS_swapcontext, ucp, NULL, sizeof(ucontext_t));
-	if (r < 0)
-	{
-		errno = -r;
+	if (retval < 0) {
+		errno = -retval;
 		return -1;
 	}
-
 	return 0;
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
 }
 
-
-extern __typeof(__getcontext) getcontext __attribute__((weak, __alias__("__getcontext")));
diff --git a/arch/ppc64/setcontext.S b/arch/ppc64/setcontext.S
new file mode 100644
index 0000000..5a0cde3
--- /dev/null
+++ b/arch/ppc64/setcontext.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied.  In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+.global __setcontext
+.hidden __swapcontext
+__setcontext:
+	addis 2, 12, .TOC.-__setcontext@ha
+	addi  2, 12, .TOC.-__setcontext@l
+
+	.localentry __setcontext,.-__setcontext
+
+	mr 4, 3
+	li 3, 0
+	b __swapcontext
+
+.weak setcontext
+setcontext = __setcontext
diff --git a/arch/ppc64/setcontext.c b/arch/ppc64/setcontext.c
deleted file mode 100644
index 59c65b4..0000000
--- a/arch/ppc64/setcontext.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * This software is provided 'as is' and without any warranty, express or
- * implied.  In no event shall the authors be liable for any damages arising
- * from the use of this software.
- */
-
-#define _GNU_SOURCE
-#include <stddef.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-
-
-int
-__setcontext(const ucontext_t *ucp)
-{
-#ifdef SYS_swapcontext
-	int r;
-
-	r = syscall(SYS_swapcontext, NULL, (void *) ucp, sizeof(ucontext_t));
-	if (r < 0)
-	{
-		errno = -r;
-		return -1;
-	}
-
-	return r;
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-
-extern __typeof(__setcontext) setcontext __attribute__((weak, __alias__("__setcontext")));
diff --git a/arch/ppc64/swapcontext.S b/arch/ppc64/swapcontext.S
new file mode 100644
index 0000000..982537a
--- /dev/null
+++ b/arch/ppc64/swapcontext.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied.  In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+.global __swapcontext
+__swapcontext:
+	addis 2, 12, .TOC.-__swapcontext@ha
+	addi  2, 12, .TOC.-__swapcontext@l
+
+	.localentry __swapcontext,.-__swapcontext
+
+	li 0, 249     # SYS_swapcontext
+	li 5, 1696    # sizeof(ucontext_t)
+	sc
+
+.hidden __retfromsyscall
+	b __retfromsyscall
+
+.weak swapcontext
+swapcontext = __swapcontext
diff --git a/arch/ppc64/swapcontext.c b/arch/ppc64/swapcontext.c
deleted file mode 100644
index af14bc2..0000000
--- a/arch/ppc64/swapcontext.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018 William Pitcock <nenolod@dereferenced.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * This software is provided 'as is' and without any warranty, express or
- * implied.  In no event shall the authors be liable for any damages arising
- * from the use of this software.
- */
-
-#define _GNU_SOURCE
-#include <stddef.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-
-
-int
-__swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
-{
-#ifdef SYS_swapcontext
-	int r;
-
-	r = syscall(SYS_swapcontext, oucp, ucp, sizeof(ucontext_t));
-	if (r < 0)
-	{
-		errno = -r;
-		return -1;
-	}
-
-	return r;
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-
-extern __typeof(__swapcontext) swapcontext __attribute__((weak, __alias__("__swapcontext")));