/* sgi.s -- assembly code for MIPS architecture using the SGI N32 ABI */ /* * Copyright (c) 1999 David Choong * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Modified jul99/gmt for inclusion in SR. * I don't claim to understand this; I just removed the O32 section. */ /* * DEVELOPER NOTES (READ!!!) : Because of the build infrastructure * in mpd one cannot include system * headers that contain any C code for * assembly context switching. * This is because this code is passed * directly to as by -E. As a result, * I have defined the required * _MIPS_SIM definitions that are located * in sgidefs.h. This is not the correct * thing to do however, this is a quick * hack that will allow for multiple * versions of the SGI abi. * * A MIPS context array is laid out like this: * * saved sp register ------------------------------| * magic word for checking integrity | * unused stack space | * saved registers, including $31 (return addr) <--- saved sp points here * older stack data * * Both regular and floating point registers are saved. As of 7/91 the * current Dec and SGI compilers don't seem to utilize f.p. temporaries, * but gcc does. * * _IncrDev Nov 10, 1988 by David Choong (choong@cs.ualberta.ca) * * Notes: - Supports the n32 abi from SGI * - now must define the abi that you * want to build with * - I hope to find some time and do * a n64 abi version. * */ #define MAGIC 61407 /* an unlikely integer. This is used to check that the context array is not clobbered */ #define ASIZE 32 /* space for callee to save 4 arguments (8 bytes/arg x 4) */ #define RSIZE 128 /* space for 10 saved registers and 6 FP regs (8 bytes/register x 10 + 8 bytes/fpregister x 6) */ #define MPD_REG_SIZE_IN_BYTES 8 /* the size in bytes of the registers */ .text .align 2 /* mpd_build_context(code,context,stksize,arg1,arg2,arg3,arg4) * * args passed in: $4 $5 $6 $7 $8 .. $11 * * code entry point of the code to be executed in the context * context buffer for holding the context array * stksize size of this buffer * arg1..arg4 four int-sized arguments to be passed to the code * * All we need to do is set up a context that will execute the startup * code, below, when activated for the first time. */ .globl mpd_build_context /* make the function extern */ .ent mpd_build_context /* for debugging purposes */ mpd_build_context: /* function label */ .frame $sp, 0, $31 dli $3, MAGIC /* Save the MAGIC num in register $3 */ sd $3, MPD_REG_SIZE_IN_BYTES($5) /* Store a doubleword (64 bits) from register $3 to the address that is contained in register $5 with an offset of MPD_REG_SIZE_IN_BYTES */ add $2, $5, $6 /* Add the address in register $5 (the context buffer pointer) to register $6 (the size of the context buffer) to get the max address of the buffer and put it in register $2 */ sub $2, ASIZE+RSIZE /* Subtract (ASIZE+RSIZE) from register $2 and put the result in register $2. The address that register $2 contains will be put into the first 8 bytes starting at the address contained in register $5. This is for later use so that the context switch can find the saved registers */ sd $2, 0($5) /* copy the saved address pointer to the first MPD_REG_SIZE_IN_BYTES bytes of memory that register $5 points to which is the context array for the thread */ sd $7, 48($2) /* save first arg into the context array in $16 slot */ sd $8, 56($2) /* save second arg into the context array in $17 slot */ sd $9, 64($2) /* save third arg into the context array in $18 slot */ sd $10, 72($2) /* save fourth arg into the context array in $19 slot */ sd $4, 80($2) /* save entry point into the context array in $20 slot */ la $3, startup /* load register $3 with the address of startup in memory */ sd $3, 120($2) /* save startup address in $31 slot */ j $31 /* return */ startup: move $4,$16 /* load arg registers for first-time call */ move $5,$17 move $6,$18 move $7,$19 la $31,under /* detect underflow if called code returns */ move $25,$20 /* MIPS ABI requires $25 for indirect call */ j $25 /* jump to entry point */ .end mpd_build_context /* mpd_chg_context (newctx, oldctx) -- switch to the specified context * * args passed in: $4 $5 */ .globl mpd_chg_context .ent mpd_chg_context mpd_chg_context: sub $sp, RSIZE /* make room on stack for saving registers */ .frame $sp, RSIZE, $31 beq $5, 0, savedone /* don't use oldctx if 0 */ dli $12, MAGIC /* magic constant. Renumbered 13 to the first temp register which is 12 */ ld $13, 8($5) /* old magic word. Register $9 was a temp register under the o32 abi but, it is now a function parameter register so it was changed to the second temp register */ ble $sp, $5, over /* if stack is currently overflowing */ ld $14, MPD_REG_SIZE_IN_BYTES($4) /* new magic word. Register $10 was a temp register under the o32 abi but, it is now a function parameter register so it was changed to the third temp register */ bne $13, $12, over /* if it overflowed before & clobbered magic */ bne $14, $12, bad /* if new context isn't intact */ .mask 0xC0FF0000, -4 sd $sp, 0($5) /* save stack pointer, then registers */ sd $31, 120($sp) /* save the return address (value of $31) */ sd $23, 104($sp) sd $22, 96($sp) sd $21, 88($sp) sd $20, 80($sp) sd $19, 72($sp) sd $18, 64($sp) sd $17, 56($sp) sd $16, 48($sp) .fmask 0xFFF00000, -4 s.d $f30, 40($sp) /* save floating-point registers */ s.d $f28, 32($sp) s.d $f26, 24($sp) s.d $f24, 16($sp) s.d $f22, 8($sp) s.d $f20, 0($sp) savedone: ld $sp, 0($4) /* load new stack pointer, then registers */ ld $31, 120($sp) ld $23, 104($sp) ld $22, 96($sp) ld $21, 88($sp) ld $20, 80($sp) ld $19, 72($sp) ld $18, 64($sp) ld $17, 56($sp) ld $16, 48($sp) l.d $f30, 40($sp) /* load new floating-point registers */ l.d $f28, 32($sp) l.d $f26, 24($sp) l.d $f24, 16($sp) l.d $f22, 8($sp) l.d $f20, 0($sp) add $sp, RSIZE /* adjust stack pointer to remove reg area */ j $31 /* return into new context */ .end mpd_chg_context /* mpd_check_stk(ctx) -- check that the stack is not overflowing */ .globl mpd_check_stk .ent mpd_check_stk mpd_check_stk: .frame $sp, 0, $31 ble $sp, $4, over /* check that we haven't grown beyond bounds */ j $31 /* return */ /* stack problem handlers (these calls do not return) */ over: jal mpd_stk_overflow under: jal mpd_stk_underflow bad: jal mpd_stk_corrupted .end mpd_check_stk