summaryrefslogtreecommitdiff
path: root/system/libucontext/powerpc.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/libucontext/powerpc.patch')
-rw-r--r--system/libucontext/powerpc.patch1121
1 files changed, 1121 insertions, 0 deletions
diff --git a/system/libucontext/powerpc.patch b/system/libucontext/powerpc.patch
new file mode 100644
index 000000000..ed7604d7b
--- /dev/null
+++ b/system/libucontext/powerpc.patch
@@ -0,0 +1,1121 @@
+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")));