diff --git a/arch/s390x/defs.h b/arch/s390x/defs.h new file mode 100644 index 0000000..1b2c9e7 --- /dev/null +++ b/arch/s390x/defs.h @@ -0,0 +1,8 @@ +#ifndef __ARCH_S390X_DEFS_H +#define __ARCH_S390X_DEFS_H + +#define OFFSET_GREGS (56) +#define OFFSET_AREGS (184) +#define OFFSET_FPREGS (248) + +#endif diff --git a/arch/s390x/getcontext.S b/arch/s390x/getcontext.S new file mode 100644 index 0000000..2987f43 --- /dev/null +++ b/arch/s390x/getcontext.S @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 William Pitcock + * + * 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. + */ + +#include "defs.h" + + +.globl __getcontext; +__getcontext: + lgr %r1, %r2 /* use %r1 as our working register */ + la %r2, 0 /* we will return 0 */ + + stam %a0, %a15, OFFSET_AREGS(%r1) /* store access registers */ + stmg %r0, %r15, OFFSET_GREGS(%r1) /* store general-purpose registers */ + + br %r14 /* return to where we came from */ + + +.weak getcontext; +getcontext = __getcontext; diff --git a/arch/s390x/makecontext.c b/arch/s390x/makecontext.c new file mode 100644 index 0000000..c5c8bc6 --- /dev/null +++ b/arch/s390x/makecontext.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018 William Pitcock + * + * 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 +#include +#include +#include +#include + + +#include "defs.h" + + +extern void __start_context(void); +extern int __setcontext(const ucontext_t *ucp); + + +void +__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) +{ + greg_t *sp, *argp; + va_list va; + int i; + unsigned int stack_args; + + stack_args = argc > 5 ? argc - 5 : 0; + + sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); + sp -= stack_args; // maybe +1 + sp = (greg_t *) (((uintptr_t) sp & -16L)); + + ucp->uc_mcontext.gregs[7] = (uintptr_t) func; + ucp->uc_mcontext.gregs[8] = (uintptr_t) ucp->uc_link; + ucp->uc_mcontext.gregs[9] = (uintptr_t) &__setcontext; + ucp->uc_mcontext.gregs[14] = (uintptr_t) &__start_context; + + argp = sp; + + va_start(va, argc); + + for (i = 0; i < argc; i++) + switch (i) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + ucp->uc_mcontext.gregs[i + 2] = va_arg (va, greg_t); + break; + default: + *argp++ = va_arg (va, greg_t); + break; + } + + va_end(va); + + /* make room for backchain / register save area */ + sp -= 20; + *sp = 0; + + /* set up %r15 as sp */ + ucp->uc_mcontext.gregs[15] = (uintptr_t) sp; +} + + +extern __typeof(__makecontext) makecontext __attribute__((weak, __alias__("__makecontext"))); diff --git a/arch/s390x/setcontext.S b/arch/s390x/setcontext.S new file mode 100644 index 0000000..ea8e4ff --- /dev/null +++ b/arch/s390x/setcontext.S @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018 William Pitcock + * + * 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. + */ + +#include "defs.h" + + +.globl __setcontext; +__setcontext: + lgr %r1, %r2 /* use %r1 as our working register */ + + lam %a2, %a15, OFFSET_AREGS+8(%r1) /* load access registers, but skip %a0 and %a1 which are for TLS */ + lmg %r0, %r15, OFFSET_GREGS(%r1) /* store general-purpose registers */ + + br %r14 /* return to new link register address */ + + +.weak setcontext; +setcontext = __setcontext; diff --git a/arch/s390x/startcontext.S b/arch/s390x/startcontext.S new file mode 100644 index 0000000..e29e946 --- /dev/null +++ b/arch/s390x/startcontext.S @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 William Pitcock + * + * 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. + */ + +#include "defs.h" + + +.globl __start_context; +__start_context: + basr %r14, %r7 /* run function pointer (%r7) and return here */ + ltgr %r8, %r8 /* check to see if uc_link (%r8) is null */ + + jz no_linked_context /* if we have no linked context, prepare to exit */ + + lgr %r2, %r8 /* copy the uc_link structure address to %r2 */ + br %r9 /* call setcontext */ + +no_linked_context: + la %r2, 0 /* return 0 */ + brasl %r14, exit@plt /* call exit */ + + j .+2 /* crash if exit returns */ diff --git a/arch/s390x/swapcontext.S b/arch/s390x/swapcontext.S new file mode 100644 index 0000000..251f5fe --- /dev/null +++ b/arch/s390x/swapcontext.S @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 William Pitcock + * + * 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. + */ + +#include "defs.h" + + +.globl __swapcontext; +__swapcontext: + lgr %r1, %r2 /* use %r1 to save current context to */ + lgr %r0, %r3 /* use %r0 for source context */ + + stam %a0, %a15, OFFSET_AREGS(%r1) /* store access registers */ + stmg %r0, %r15, OFFSET_GREGS(%r1) /* store general-purpose registers */ + + lgr %r2, %r0 /* swap %r0 to %r2 (XXX: figure out why it hates loading from %r0) */ + lam %a2, %a15, OFFSET_AREGS+8(%r2) /* load access registers, but skip %a0 and %a1 which are for TLS */ + lmg %r0, %r15, OFFSET_GREGS(%r2) /* load general-purpose registers */ + + br %r14 /* return to new link register address */ + + +.weak swapcontext; +swapcontext = __swapcontext;