diff options
Diffstat (limited to 'coroutine/ppc64le')
| -rw-r--r-- | coroutine/ppc64le/Context.S | 91 | ||||
| -rw-r--r-- | coroutine/ppc64le/Context.h | 57 |
2 files changed, 148 insertions, 0 deletions
diff --git a/coroutine/ppc64le/Context.S b/coroutine/ppc64le/Context.S new file mode 100644 index 0000000000..819264c245 --- /dev/null +++ b/coroutine/ppc64le/Context.S @@ -0,0 +1,91 @@ +#define TOKEN_PASTE(x,y) x##y + +.abiversion 2 +.text +.align 2 + +.globl PREFIXED_SYMBOL(coroutine_transfer) +.type PREFIXED_SYMBOL(coroutine_transfer), @function +PREFIXED_SYMBOL(coroutine_transfer): + # Global entry: set up TOC pointer (r2) from r12. + # Required by ELFv2 ABI when this function is reached via the PLT. + addis 2, 12, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@ha + addi 2, 2, .TOC. - PREFIXED_SYMBOL(coroutine_transfer)@l + .localentry PREFIXED_SYMBOL(coroutine_transfer), .-PREFIXED_SYMBOL(coroutine_transfer) + + # Make space on the stack for caller registers + addi 1,1,-160 + + # Save caller registers + std 14,0(1) + std 15,8(1) + std 16,16(1) + std 17,24(1) + std 18,32(1) + std 19,40(1) + std 20,48(1) + std 21,56(1) + std 22,64(1) + std 23,72(1) + std 24,80(1) + std 25,88(1) + std 26,96(1) + std 27,104(1) + std 28,112(1) + std 29,120(1) + std 30,128(1) + std 31,136(1) + + # Save return address + mflr 0 + std 0,144(1) + + # Save caller special register + mfcr 0 + std 0, 152(1) + + # Save stack pointer to first argument + std 1,0(3) + + # Load stack pointer from second argument + ld 1,0(4) + + # Restore caller registers + ld 14,0(1) + ld 15,8(1) + ld 16,16(1) + ld 17,24(1) + ld 18,32(1) + ld 19,40(1) + ld 20,48(1) + ld 21,56(1) + ld 22,64(1) + ld 23,72(1) + ld 24,80(1) + ld 25,88(1) + ld 26,96(1) + ld 27,104(1) + ld 28,112(1) + ld 29,120(1) + ld 30,128(1) + ld 31,136(1) + + # Load return address + ld 0,144(1) + mtlr 0 + + # Load special registers + ld 0,152(1) + # Restore cr register cr2, cr3 and cr4 (field index 3,4,5) + # (field index is 1-based, field 1 = cr0) using a mask (32|16|8 = 56) + mtcrf 56,0 + + # Pop stack frame + addi 1,1,160 + + # Jump to return address + blr + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/coroutine/ppc64le/Context.h b/coroutine/ppc64le/Context.h new file mode 100644 index 0000000000..63ea9f19ff --- /dev/null +++ b/coroutine/ppc64le/Context.h @@ -0,0 +1,57 @@ +#ifndef COROUTINE_PPC64LE_CONTEXT_H +#define COROUTINE_PPC64LE_CONTEXT_H 1 + +#pragma once + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#define COROUTINE __attribute__((noreturn)) void + +enum { + COROUTINE_REGISTERS = + 20 /* 18 general purpose registers (r14-r31), 1 special register (cr) and 1 return address */ + + 4 /* space for fiber_entry() to store the link register */ +}; + +struct coroutine_context +{ + void **stack_pointer; + void *argument; +}; + +typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self); + +static inline void coroutine_initialize_main(struct coroutine_context * context) { + context->stack_pointer = NULL; +} + +static inline void coroutine_initialize( + struct coroutine_context *context, + coroutine_start start, + void *stack, + size_t size +) { + assert(start && stack && size >= 1024); + + // Stack grows down. Force 16-byte alignment. + char * top = (char*)stack + size; + context->stack_pointer = (void**)((uintptr_t)top & ~0xF); + + context->stack_pointer -= COROUTINE_REGISTERS; + memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS); + + /* Skip a global prologue that sets the TOC register */ + context->stack_pointer[18] = ((char*)start) + 8; +} + +struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target); + +static inline void coroutine_destroy(struct coroutine_context * context) +{ + context->stack_pointer = NULL; +} + +#endif /* COROUTINE_PPC64LE_CONTEXT_H */ |
