diff --git a/arch/mips64/defs.h b/arch/mips64/defs.h new file mode 100644 index 0000000..3a9685d --- /dev/null +++ b/arch/mips64/defs.h @@ -0,0 +1,100 @@ +#ifndef __ARCH_MIPS64_DEFS_H +#define __ARCH_MIPS64_DEFS_H + +#define REG_SZ (8) + +#define REG_R0 (0) +#define REG_R1 (1) +#define REG_R2 (2) +#define REG_R3 (3) +#define REG_R4 (4) +#define REG_R5 (5) +#define REG_R6 (6) +#define REG_R7 (7) +#define REG_R8 (8) +#define REG_R9 (9) +#define REG_R10 (10) +#define REG_R11 (11) +#define REG_R12 (12) +#define REG_R13 (13) +#define REG_R14 (14) +#define REG_R15 (15) +#define REG_R16 (16) +#define REG_R17 (17) +#define REG_R18 (18) +#define REG_R19 (19) +#define REG_R20 (20) +#define REG_R21 (21) +#define REG_R22 (22) +#define REG_R23 (23) +#define REG_R24 (24) +#define REG_R25 (25) +#define REG_R26 (26) +#define REG_R27 (27) +#define REG_R28 (28) +#define REG_R29 (29) +#define REG_R30 (30) +#define REG_R31 (31) + +/* $a0 is $4 */ +#define REG_A0 (4) + +/* stack pointer is actually $29 */ +#define REG_SP (29) + +/* frame pointer is actually $30 */ +#define REG_FP (30) + +/* $s0 ($16) is used as link register */ +#define REG_LNK (16) + +/* $t9 ($25) is used as entry */ +#define REG_ENTRY (25) + +/* offset to mc_gregs in ucontext_t */ +#define MCONTEXT_GREGS (40) + +/* offset to PC in ucontext_t */ +#define MCONTEXT_PC (MCONTEXT_GREGS + 576) + +/* offset to uc_link in ucontext_t */ +#define UCONTEXT_UC_LINK (8) + +/* offset to uc_stack.ss_sp in ucontext_t */ +#define UCONTEXT_STACK_PTR (16) + +/* offset to uc_stack.ss_size in ucontext_t */ +#define UCONTEXT_STACK_SIZE (24) + +/* setup frame, from MIPS N32/N64 calling convention manual */ +#define ALSZ 15 +#define ALMASK ~15 +#define FRAMESZ (((LOCALSZ * REG_SZ) + ALSZ) & ALMASK) // 16 +#define GPOFF (FRAMESZ - (LOCALSZ * REG_SZ)) // [16 - 16] + +#define SETUP_FRAME(__proc) \ + .frame $sp, FRAMESZ, $ra; \ + .mask 0x10000000, 0; \ + .fmask 0x00000000, 0; + +#define PUSH_FRAME(__proc) \ + daddiu $sp, -FRAMESZ; \ + .cpsetup $25, GPOFF, __proc; + +#define POP_FRAME(__proc) \ + .cpreturn; \ + daddiu $sp, FRAMESZ + +#define FUNC(__proc) \ + .globl __proc; \ + .align 2; \ + .type __proc, @function; \ + .ent __proc, 0; \ +__proc: \ + SETUP_FRAME(__proc) + +#define END(__proc) \ + .end __proc; \ + .size __proc,.-__proc; + +#endif diff --git a/arch/mips64/getcontext.S b/arch/mips64/getcontext.S new file mode 100644 index 0000000..5540cc5 --- /dev/null +++ b/arch/mips64/getcontext.S @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * 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. + */ + +LOCALSZ = 1 + +#include "defs.h" + +FUNC(__getcontext) + /* copy $gp, $sp, $fp to temporary registers so we don't clobber them */ + move $a2, $gp + move $a3, $sp + move $a4, $fp + + PUSH_FRAME(__getcontext) + + /* set the magic flag */ + li $v0, 1 + sd $v0, ((0 * REG_SZ) + MCONTEXT_GREGS)($a0) + + /* set registers */ + sd $s0, ((16 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s1, ((17 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s2, ((18 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s3, ((19 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s4, ((20 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s5, ((21 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s6, ((22 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s7, ((23 * REG_SZ) + MCONTEXT_GREGS)($a0) + + sd $a2, ((28 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $a3, ((29 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $a4, ((30 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $ra, ((31 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $ra, (MCONTEXT_PC)($a0) + + POP_FRAME(__getcontext) + + jr $ra +END(__getcontext) + +.weak getcontext; +getcontext = __getcontext; diff --git a/arch/mips64/makecontext.S b/arch/mips64/makecontext.S new file mode 100644 index 0000000..63050bf --- /dev/null +++ b/arch/mips64/makecontext.S @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * 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. + */ + +/* $gp + 5 args */ +LOCALSZ = 6 + +#include "defs.h" + +A3_OFF = FRAMESZ - (5 * REG_SZ) +A4_OFF = FRAMESZ - (4 * REG_SZ) +A5_OFF = FRAMESZ - (3 * REG_SZ) +A6_OFF = FRAMESZ - (2 * REG_SZ) +A7_OFF = FRAMESZ - (1 * REG_SZ) + +/* + * Because we have to fiddle with $gp, we have to implement this in + * assembly rather than C. Annoying, that... + */ + +FUNC(__makecontext) + PUSH_FRAME(__makecontext) + + /* store $a3 through $a7 to the stack frame. */ + sd $a3, A3_OFF($sp) + sd $a4, A4_OFF($sp) + sd $a5, A5_OFF($sp) + sd $a6, A6_OFF($sp) + sd $a7, A7_OFF($sp) + + /* set $zero in the mcontext to 1. */ + li $v0, 1 + sd $v0, ((0 * REG_SZ) + MCONTEXT_GREGS)($a0) + + /* ensure the stack is aligned on a quad-word boundary. */ + ld $t0, UCONTEXT_STACK_PTR($a0) + ld $t2, UCONTEXT_STACK_SIZE($a0) + daddiu $t1, $sp, A3_OFF + daddu $t0, $t2 + and $t0, ALMASK + blez $a2, no_more_arguments + + /* store register arguments. */ + daddiu $t2, $a0, MCONTEXT_GREGS + (4 * REG_SZ) + move $t3, $zero + +store_register_arg: + daddiu $t3, 1 + ld $v1, ($t1) + daddiu $t1, REG_SZ + sd $v1, ($t2) + daddiu $t2, REG_SZ + bgeu $t3, $a2, no_more_arguments + bltu $t3, 8, store_register_arg + + /* make room for stack arguments. */ + dsubu $t2, $a2, $t3 + dsll $t2, 3 + dsubu $t0, $t2 + and $t0, ALMASK + + /* store stack arguments. */ + move $t2, $t0 + +store_stack_arg: + daddiu $t3, 1 + ld $v1, ($t1) + daddiu $t1, REG_SZ + sd $v1, ($t2) + daddiu $t2, REG_SZ + bltu $t3, $a2, store_stack_arg + +no_more_arguments: + /* trampoline setup. */ + dla $t9, __start_context + + /* copy link pointer as $s0... */ + ld $v1, UCONTEXT_UC_LINK($a0) + sd $v1, ((16 * REG_SZ) + MCONTEXT_GREGS)($a0) + + /* set our $sp */ + sd $t0, ((29 * REG_SZ) + MCONTEXT_GREGS)($a0) + + /* $gp is copied as $s1 */ + sd $gp, ((17 * REG_SZ) + MCONTEXT_GREGS)($a0) + + /* set our $ra */ + sd $t9, ((31 * REG_SZ) + MCONTEXT_GREGS)($a0) + + /* set our $pc */ + sd $a1, MCONTEXT_PC($a0) + + POP_FRAME(__makecontext) + + jr $ra +END(__makecontext) + + +.weak makecontext +makecontext = __makecontext; diff --git a/arch/mips64/setcontext.S b/arch/mips64/setcontext.S new file mode 100644 index 0000000..d6bb1cb --- /dev/null +++ b/arch/mips64/setcontext.S @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * 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. + */ + +LOCALSZ = 1 + +#include "defs.h" + +FUNC(__setcontext) + PUSH_FRAME(__setcontext) + + /* check for the magic flag. */ + li $v0, 1 + dla $v1, ((0 * REG_SZ) + MCONTEXT_GREGS)($a0) + bne $v0, $v1, fail + + /* move the context to $v0 */ + move $v0, $a0 + + /* load the registers */ + ld $a0, ((4 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a1, ((5 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a2, ((6 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a3, ((7 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a4, ((8 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a5, ((9 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a6, ((10 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a7, ((11 * REG_SZ) + MCONTEXT_GREGS)($v0) + + ld $s0, ((16 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s1, ((17 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s2, ((18 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s3, ((19 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s4, ((20 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s5, ((21 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s6, ((22 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s7, ((23 * REG_SZ) + MCONTEXT_GREGS)($v0) + + ld $gp, ((28 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $sp, ((29 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $fp, ((30 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $ra, ((31 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $t9, (MCONTEXT_PC)($v0) + + move $v0, $zero + jr $t9 + +fail: + dla $t9, exit + + POP_FRAME(__setcontext) + + jalr $t9 +END(__setcontext) + +.weak setcontext; +setcontext = __setcontext; diff --git a/arch/mips64/startcontext.S b/arch/mips64/startcontext.S new file mode 100644 index 0000000..e933709 --- /dev/null +++ b/arch/mips64/startcontext.S @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * 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. + */ + +LOCALSZ = 1 + +#include "defs.h" + +FUNC(__start_context) + move $gp, $s1 + + /* we receive our initial ucontext in $s0, so if $s0 is nil, bail */ + beqz $s0, no_linked_context + + /* call setcontext */ + move $a0, $s0 + dla $t9, __setcontext + + jalr $t9 + +no_linked_context: + move $a0, $zero + dla $t9, exit + jalr $t9 + nop +END(__start_context) diff --git a/arch/mips64/swapcontext.S b/arch/mips64/swapcontext.S new file mode 100644 index 0000000..82fb17c --- /dev/null +++ b/arch/mips64/swapcontext.S @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * 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. + */ + +LOCALSZ = 2 + +#include "defs.h" + +A1_OFFSET = FRAMESZ - (1 * REG_SZ) + +FUNC(__swapcontext) + /* copy $gp, $sp, $fp to temporary registers so we don't clobber them */ + move $a2, $gp + move $a3, $sp + move $a4, $fp + + PUSH_FRAME(__swapcontext) + + /* set the magic flag */ + li $v0, 1 + sd $v0, ((0 * REG_SZ) + MCONTEXT_GREGS)($a0) + + /* set registers */ + sd $s0, ((16 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s1, ((17 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s2, ((18 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s3, ((19 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s4, ((20 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s5, ((21 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s6, ((22 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $s7, ((23 * REG_SZ) + MCONTEXT_GREGS)($a0) + + sd $a2, ((28 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $a3, ((29 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $a4, ((30 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $ra, ((31 * REG_SZ) + MCONTEXT_GREGS)($a0) + sd $ra, (MCONTEXT_PC)($a0) + + /* copy new context address in $a1 to stack */ + sd $a1, A1_OFFSET($sp) + + /* load new context address into $v0 */ + ld $v0, A1_OFFSET($sp) + + /* load the registers */ + ld $a0, ((4 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a1, ((5 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a2, ((6 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a3, ((7 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a4, ((8 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a5, ((9 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a6, ((10 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $a7, ((11 * REG_SZ) + MCONTEXT_GREGS)($v0) + + ld $s0, ((16 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s1, ((17 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s2, ((18 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s3, ((19 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s4, ((20 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s5, ((21 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s6, ((22 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $s7, ((23 * REG_SZ) + MCONTEXT_GREGS)($v0) + + ld $gp, ((28 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $sp, ((29 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $fp, ((30 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $ra, ((31 * REG_SZ) + MCONTEXT_GREGS)($v0) + ld $t9, (MCONTEXT_PC)($v0) + + move $v0, $zero + jr $t9 + +fail: + dla $t9, exit + + POP_FRAME(__swapcontext) + + move $v0, $zero + jalr $t9 +END(__swapcontext) + +.weak swapcontext; +swapcontext = __swapcontext;