diff --git a/README.md b/README.md index 2195df0..7a8e817 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,4 @@ Right now these archs are supported and should work on bare metal: These archs require kernel assistance and use a syscall (the only assembly is the trampoline): * ppc + * ppc64 (ELFv2 ABI spec only, ELFv1 not supported) diff --git a/arch/ppc64/defs.h b/arch/ppc64/defs.h index 247ee10..e31d735 100644 --- a/arch/ppc64/defs.h +++ b/arch/ppc64/defs.h @@ -56,7 +56,10 @@ /* nip register is actually %srr0 (r32) */ #define REG_NIP REG_R32 -/* lnk register is actually r32 */ +/* entry register is actually %r12 */ +#define REG_ENTRY REG_R12 + +/* lnk register is actually %r36 */ #define REG_LNK REG_R36 #endif diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c index 96ed477..9d6b998 100644 --- a/arch/ppc64/makecontext.c +++ b/arch/ppc64/makecontext.c @@ -39,10 +39,11 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) sp -= (uc_link + 1); 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; - ucp->uc_mcontext.gp_regs[REG_R31] = (uintptr_t) ucp->uc_link; - ucp->uc_mcontext.gp_regs[REG_SP] = (uintptr_t) sp; + ucp->uc_mcontext.gp_regs[REG_NIP] = (uintptr_t) func; + ucp->uc_mcontext.gp_regs[REG_LNK] = (uintptr_t) &__start_context; + ucp->uc_mcontext.gp_regs[REG_SP] = (uintptr_t) sp; + 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[uc_link] = (uintptr_t) ucp->uc_link; diff --git a/arch/ppc64/startcontext.S b/arch/ppc64/startcontext.S index 5abf43c..d8b8b13 100644 --- a/arch/ppc64/startcontext.S +++ b/arch/ppc64/startcontext.S @@ -13,12 +13,19 @@ .globl __start_context; .hidden __start_context; __start_context: - /* get the proper context into position and test for NULL */ - mr. 3,31 - beq hosed - bl __setcontext - nop + cmpdi 31,0 /* test if ucontext link pointer is null */ + beq do_exit /* if it is, exit */ -hosed: + /* now, call SYS_swapcontext */ + mr 4,31 /* ucp is in r31 */ + li 3,0 /* don't care about restoring, set oucp to NULL */ + li 5,1696 /* sizeof(ucontext_t) */ + li 0,249 /* SYS_swapcontext */ + sc + + /* we should not wind back up here, if we do, exit with -1 */ + li 3,-1 + +do_exit: b exit@GOT nop