Files
2015-04-16 09:16:48 +02:00

1740 lines
46 KiB
C

#define _KERNEL
#include "ixemul.h"
#include <exec/memory.h>
#include <signal.h>
#include <unistd.h>
#include "kprintf.h"
#ifdef TRACK_ALLOCS
#undef AllocMem
#undef FreeMem
#define AllocMem(x,y) debug_AllocMem("stack",x,y)
#define FreeMem(x,y) debug_FreeMem(x,y)
#endif
#define GUARD 0xabababab
#define HIT (*(long*)0 = 0)
/*
* Signal routines may want to benefit from stackextension too -
* so make all the stack handling functions atomic.
* FIXME: This seems to have the potential to break a Forbid() ?!?
*/
void atomic_on(sigset_t *old)
{
usetup;
*old = u.p_sigmask;
u.p_sigmask = ~0;
/* sigset_t fill;
sigfillset(&fill);
sigprocmask(SIG_SETMASK, &fill, &old);*/
}
void atomic_off(sigset_t old)
{
usetup;
u.p_sigmask = old;
// sigprocmask(SIG_SETMASK, &old, NULL);
}
#ifdef NATIVE_MORPHOS
#define STK_UPPER_PPC \
(u.u_ppc_stk_used != NULL ? u.u_ppc_stk_used->upper : u.u_ppc_org_upper)
#define STK_LOWER_PPC \
(u.u_ppc_stk_used != NULL ? (void *)(u.u_ppc_stk_used + 1) : u.u_ppc_org_lower)
#define STK_UPPER_68K \
(u.u_68k_stk_used != NULL ? u.u_68k_stk_used->upper : u.u_68k_org_upper)
#define STK_LOWER_68K \
(u.u_68k_stk_used != NULL ? (void *)(u.u_68k_stk_used + 1) : u.u_68k_org_lower)
#define stk_safezone_68k 6144 /* into ixprefs? */
#define stk_minframe_68k 32768
#define stk_safezone_ppc 16000 /* into ixprefs? */
#define stk_minframe_ppc 200000
static void popframes_ppc(struct stackframe *sf, struct StackSwapStruct *sss);
static void popframes_68k(struct stackframe *sf, struct StackSwapStruct *sss);
static void pushframe_ppc(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old, int startup);
static void pushframe_68k(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old, int startup);
void __stkrst_f(void);
void __stkovf(void);
void __stkovf68k(void);
#define SAVE_68K_REGS \
LONG old_d0 = REG_D0; \
LONG old_d1 = REG_D1; \
LONG old_d2 = REG_D2; \
LONG old_d3 = REG_D3; \
LONG old_d4 = REG_D4; \
LONG old_d5 = REG_D5; \
LONG old_d6 = REG_D6; \
LONG old_d7 = REG_D7; \
LONG old_a0 = REG_A0; \
LONG old_a1 = REG_A1; \
LONG old_a2 = REG_A2; \
LONG old_a3 = REG_A3; \
LONG old_a4 = REG_A4; \
LONG old_a5 = REG_A5; \
LONG old_a6 = REG_A6;
#define RESTORE_68K_REGS \
REG_D0 = old_d0; \
REG_D1 = old_d1; \
REG_D2 = old_d2; \
REG_D3 = old_d3; \
REG_D4 = old_d4; \
REG_D5 = old_d5; \
REG_D6 = old_d6; \
REG_D7 = old_d7; \
REG_A0 = old_a0; \
REG_A1 = old_a1; \
REG_A2 = old_a2; \
REG_A3 = old_a3; \
REG_A4 = old_a4; \
REG_A5 = old_a5; \
REG_A6 = old_a6;
static int get_68k_stack_size(struct Process *proc, int stack)//seem not use on 68k
{
struct CommandLineInterface *CLI;
if (stack < STACKSIZE)
stack = STACKSIZE;
/* NOTE: This is the most appropriate place for future support of
user-specified, process-specific stacksizes. */
CLI = BTOCPTR (proc->pr_CLI);
if (stack <= (CLI ? CLI->cli_DefaultStack * 4 : proc->pr_StackSize))
return 0;
KPRINTF(("get_stack_size() = %ld\n", stack));
return stack;
}
static int get_ppc_stack_size(struct Task *task, int stack)
{
/*char *tmp;*/
char buf[80];
if (stack < STACKSIZE * 3)
stack = STACKSIZE * 3;
/* Don't use our getenv here, because u_environ is not
* initialized yet. */
/*if (tmp = getenv ("IXPPCSTACK"))
{
int stack_size = atoi (tmp);
if (stack < stack_size)
stack = stack_size;
}*/
if (GetVar("IXPPCSTACK", buf, sizeof(buf), 0) >= 0)
{
int stack_size = atoi (buf);
if (stack < stack_size)
stack = stack_size;
}
if (stack <= (int)task->tc_ETask->PPCSPUpper - (int)task->tc_ETask->PPCSPLower)
return 0;
KPRINTF(("get_stack_size() = %ld\n", stack));
return stack;
}
void *stkrst(void *sp, void *callsp, void *d0)
{
int cpsize = (char *)callsp - (char *)sp;
struct stackframe *sf1, *sf2;
struct StackSwapStruct sss;
struct Task *me = SysBase->ThisTask;
usetup;
if (d0 >= STK_LOWER_PPC && d0 < STK_UPPER_PPC)
return sp;
KPRINTF(("stkrst(%lx, %lx, %lx, %lx)\n", sp, callsp, u.u_ppc_stk_used, d0));
sf1 = u.u_ppc_stk_used;
if (sf1 == NULL)
return sp;
if (*(unsigned *)me->tc_ETask->PPCSPLower != GUARD)
{
dprintf("**************** Stack overflow detected ********************\n");
HIT;
}
for (;;)
{
sf2 = sf1->next;
if (sf2 == NULL)
{
if (d0 < u.u_ppc_org_lower || d0 >= u.u_ppc_org_upper)
return sp;
break;
}
if (d0 >= (void *)(sf2 + 1) && d0 < sf2->upper) /* This stackframe fits */
break;
sf1 = sf2;
}
popframes_ppc(sf1, &sss);
sss.stk_Pointer = (char *)d0 - cpsize;
CopyMem(sp, sss.stk_Pointer, cpsize);
*(int *)(sss.stk_Pointer + cpsize + 4) = *(int *)(callsp + 4);
me->tc_ETask->PPCSPUpper = (void*)sss.stk_Upper;
me->tc_ETask->PPCSPLower = sss.stk_Lower;
KPRINTF(("new r1 = %lx, upper = %lx, lower = %lx, used = %lx\n", sss.stk_Pointer, sss.stk_Upper, sss.stk_Lower, u.u_ppc_stk_used));
return sss.stk_Pointer;
}
/*
* return to last stackframe
*/
void *stkrst_f(char *callsp, char *endsp)
{
int cpsize = endsp - callsp;
struct StackSwapStruct sss;
struct Task *me = SysBase->ThisTask;
unsigned long *p = (void *)callsp;
usetup;
KPRINTF(("stkrst_f(%lx, %lx, %lx)\n", callsp, endsp, u.u_ppc_stk_used));
KPRINTF(("stack %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]));
KPRINTF(("stack %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]));
if (*(unsigned *)me->tc_ETask->PPCSPLower != GUARD)
{
dprintf("**************** Stack overflow detected ********************\n");
HIT;
}
sss.stk_Pointer = (char *)u.u_ppc_stk_used->savesp - cpsize;
CopyMem(callsp, sss.stk_Pointer, cpsize);
popframes_ppc(u.u_ppc_stk_used, &sss);
me->tc_ETask->PPCSPUpper = (void*)sss.stk_Upper;
me->tc_ETask->PPCSPLower = sss.stk_Lower;
KPRINTF(("new r1 = %lx, upper = %lx, lower = %lx, used = %lx\n", sss.stk_Pointer, sss.stk_Upper, sss.stk_Lower, u.u_ppc_stk_used));
p = (void *)sss.stk_Pointer;
KPRINTF(("stack %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]));
KPRINTF(("stack %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]));
return sss.stk_Pointer;
}
void *stkext_startup_ppc(int stack0, char *sp, sigset_t *old, int ret_offset)
{
char *argtop;
int cpsize;
int stack;
struct StackSwapStruct sss;
struct Task *me = SysBase->ThisTask;
usetup;
KPRINTF(("stkext_startup_ppc(%ld, %lx)\n", stack0, sp));
KPRINTF(("sp = %lx, upper = %lx, lower = %lx, limit = %lx\n",
sp, u.u_ppc_tc_spupper, u.u_ppc_tc_splower, u.u_ppc_stk_limit ? *u.u_ppc_stk_limit : NULL));
if (!(stack = get_ppc_stack_size(me, stack0)))
return sp;
argtop = sp + u.u_ppc_stk_argbt; /* Top of area with arguments */
if ((void *)argtop > STK_UPPER_PPC)
argtop = STK_UPPER_PPC;
cpsize = argtop - sp;
cpsize = (cpsize + 15) & ~15;
pushframe_ppc(stack + 15, &sss, old, 1);
sss.stk_Pointer = (void *)((int)sss.stk_Pointer & ~15);
*(char **)&sss.stk_Pointer -= cpsize;
CopyMem(sp, sss.stk_Pointer, cpsize);
u.u_ppc_stk_used->savesp = sp + ret_offset - 4; /* store sp */
*(void **)((char *)sss.stk_Pointer + ret_offset) = &__stkrst_f; /* set returnaddress */
*(unsigned*)sss.stk_Lower = GUARD;
me->tc_ETask->PPCSPUpper = (void *)sss.stk_Upper;
me->tc_ETask->PPCSPLower = sss.stk_Lower;
KPRINTF(("new r1 = %lx, upper = %lx, lower = %lx, used = %lx\n", sss.stk_Pointer, sss.stk_Upper, sss.stk_Lower, u.u_ppc_stk_used));
return sss.stk_Pointer;
}
/*
* Allocate a new stackframe with d0 bytes minimum, copy the callers arguments
* and set his returnaddress (offset d1 from the sp when called) to stk_rst_f
*/
void *stkext_f(char *callsp, size_t d0, sigset_t *old, int frame_size, int prev_frame_size)
{
char *argtop;
char *new_r1;
struct StackSwapStruct sss;
struct Task *me = SysBase->ThisTask;
unsigned long *p = (void *)callsp;
int cpsize;
usetup;
KPRINTF(("stkext_f(%lx, %lx, %lx, %lx, %lx) limit = %lx frame_size 0x%x prev_frame_size 0x%x\n",
callsp, STK_UPPER_PPC, STK_LOWER_PPC, u.u_ppc_stk_used, d0,
u.u_ppc_stk_limit ? *u.u_ppc_stk_limit : NULL, frame_size, prev_frame_size));
KPRINTF(("stack %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]));
KPRINTF(("stack %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]));
if ((void *)callsp >= STK_UPPER_PPC || (void *)callsp < STK_LOWER_PPC)
return callsp; /* User intentionally left area of stackextension */
argtop = callsp + frame_size + prev_frame_size + u.u_ppc_stk_argbt; /* Top of area with arguments */
if ((void *)argtop > STK_UPPER_PPC)
argtop = STK_UPPER_PPC;
cpsize = argtop - callsp - frame_size;
/* FIXME: is "+ u.u_stk_argbt" really necessary? It's added in pushframe(), too. */
pushframe_ppc(d0 + cpsize + frame_size + 15, &sss, old, 0);
sss.stk_Pointer = (void *)(((int)sss.stk_Pointer & ~15) - ((cpsize + frame_size + 15) & ~15));
new_r1 = (char *)sss.stk_Pointer;
CopyMem(callsp, new_r1, frame_size & ~15);
CopyMem(callsp + frame_size, new_r1 + (frame_size & ~15), cpsize);
u.u_ppc_stk_used->savesp = callsp + frame_size + prev_frame_size; /* store sp */
*(void **)new_r1 = new_r1 + (frame_size & ~15);
if (prev_frame_size)
{
*(void **)(new_r1 + (frame_size & ~15)) = new_r1 + (frame_size & ~15) + prev_frame_size;
*(void **)(new_r1 + (frame_size & ~15) + prev_frame_size + 4) = &__stkrst_f;
}
/*else
*(void **)(new_r1 + (frame_size & ~15) + 4) = &__stkrst_f;*/
*(unsigned*)sss.stk_Lower = GUARD;
me->tc_ETask->PPCSPUpper = (void *)sss.stk_Upper;
me->tc_ETask->PPCSPLower = sss.stk_Lower;
KPRINTF(("new r1 = %lx, upper = %lx, lower = %lx, used = %lx\n", sss.stk_Pointer, sss.stk_Upper, sss.stk_Lower, u.u_ppc_stk_used));
return sss.stk_Pointer;
}
asm("
.globl __stkext_f
.type __stkext_f,@function
__stkext_f:
/* called with:
4(r1) = caller's return address
ctr = caller
r3..r10 = arguments for function
r1 might not be aligned on 16 bytes boundary, so we align it. We reserve 64 bytes for our stack
frame plus some padding.
*/
andi. 11,1,15
addi 11,11,64
neg 12,11
stwux 1,1,12
stw 3,8(1)
stw 4,12(1)
stw 5,16(1)
mfctr 4
stw 6,20(1)
mfcr 5
stw 7,24(1)
stw 8,28(1)
stw 9,32(1)
stw 10,36(1)
stw 11,40(1)
stw 4,48(1)
stw 5,52(1)
addi 3,1,60
bl atomic_on
mr 3,1
li 4,0
addi 5,1,60
lwz 6,40(1)
li 7,0
bl stkext_f /* stkextf returns an aligned new stack. It removes the padding
from our frame, so we just have 64 bytes now. */
mr 1,3
lwz 3,60(1)
bl atomic_off
lis 3,__stkrst_f@ha
lwz 4,48(1)
addi 3,3,__stkrst_f@l
lwz 5,52(1)
lwz 6,20(1)
mtlr 3
lwz 7,24(1)
lwz 8,28(1)
mtctr 4
lwz 3,4(11)
lwz 9,32(1)
lwz 10,36(1)
mtcr 5
lwz 3,8(1)
lwz 4,12(1)
lwz 5,16(1)
addi 1,1,64
bctr
__end__stkext_f:
.size __stkext_f,__end__stkext_f-__stkext_f
/* Attn: for ppc, this is actually alloca()
r3 = size
The same alignment comments as above apply, except we have a 16 bytes frame.
*/
.globl __stkext
.type __stkext,@function
__stkext:
andi. 11,1,15
/* beq+ l1
li 12,0
stw 0,0(12)
l1:*/
mflr 0
addi 11,11,16
neg 12,11
stw 0,4(1)
stwux 1,1,12
stw 3,8(1)
addi 3,1,12
bl atomic_on
lwz 7,0(1) /* r6 = end of next frame */
mr 3,1 /* r3 = sp */
lwz 4,8(1) /* r4 = size */
addi 4,4,32
sub 6,7,1 /* r6 = offset to the next frame */
lwz 7,0(7)
addi 5,1,12 /* r5 = sigset */
sub 7,7,1
sub 7,7,6 /* r7 = size to copy after our frame */
bl stkext_f /* Aligns the stack and removes padding */
mr 1,3
lwz 3,12(1)
bl atomic_off
lwz 0,20(1)
lwz 4,8(1)
lwz 5,16(1)
mtlr 0
subfic 4,4,16
stwux 5,1,4
blr
__end__stkext:
.size __stkext,__end__stkext-__stkext
.globl __stkext_startup
.type __stkext_startup,@function
__stkext_startup:
/* called with:
r10 = function to call
r11 = stack size
r3... = arguments for function
*/
stwu 1,-128(1)
mflr 0
stw 0,132(1)
stmw 3,8(1)
addi 3,1,124 /* 124(r1) = old signals */
bl atomic_on
lwz 3,40(1) /* r3 = stack size */
mr 4,1 /* r4 = sp */
addi 5,1,124 /* r5 = &old_sigs */
li 6,132 /* r6 = &save_lr */
bl stkext_startup_ppc
mr 1,3 /* set new sp */
lwz 3,124(1) /* r3 = old signals */
bl atomic_off
lmw 3,8(1) /* restore regs */
lwz 0,132(1) /* r0 = return address */
mtctr 10 /* ctr = function to call */
addi 1,1,128 /* restore frame */
mtlr 0
bctr
__end__stkext_startup:
.size __stkext_startup,__end__stkext_startup-__stkext_startup
.globl __stkrst
.type __stkrst,@function
__stkrst:
/* called with r5 = new sp */
stwu 1,-128(1)
mflr 0
stmw 3,8(1)
stw 0,132(1)
addi 3,1,124
bl atomic_on
mr 3,1 /* r3 = old sp */
addi 4,1,128 /* r4 = call sp*/
lwz 5,16(1) /* r5 = new sp */
bl stkrst
mr 1,3
lwz 3,124(1)
lwz 14,132(1)
bl atomic_off
mtlr 14
lmw 3,8(1)
addi 1,1,128
blr
__end__stkrst:
.size __stkrst,__end__stkrst-__stkrst
.globl __stkrst_f
.type __stkrst_f,@function
__stkrst_f:
stwu 1,-32(1)
stw 3,8(1)
stw 4,12(1)
addi 3,1,28
bl atomic_on
mr 3,1
addi 4,1,32
bl stkrst_f
mr 1,3
addi 3,1,28
bl atomic_off
lwz 0,36(1)
lwz 4,12(1)
mtlr 0
lwz 3,8(1)
addi 1,1,32
stw 3,0(2)
blr
__end__stkrst_f:
.size __stkrst_f,__end__stkrst_f-__stkrst_f
");
void* stkrst68k(void *new_sp, void *old_sp)
{
struct Task *me = SysBase->ThisTask;
usetup;
struct StackSwapStruct sss;
struct stackframe *sf1, *sf2;
sigset_t old;
int ret;
atomic_on(&old);
ret = *(int *)old_sp;
if (new_sp >= STK_LOWER_68K && new_sp < STK_UPPER_68K)
goto end;
KPRINTF(("stkrst(%lx) [68k]\n", new_sp));
sf1 = u.u_68k_stk_used;
if (sf1 == NULL)
goto end;
for (;;)
{
sf2 = sf1->next;
if (sf2 == NULL)
{
if (new_sp < u.u_68k_org_lower || new_sp >= u.u_68k_org_upper)
goto end;
break;
}
if (new_sp >= (void *)(sf2 + 1) && new_sp < sf2->upper) /* This stackframe fits */
break;
sf1 = sf2;
}
popframes_68k(sf1, &sss);
me->tc_SPUpper = (void *)sss.stk_Upper;
me->tc_SPLower = sss.stk_Lower;
end:
new_sp = (void *)((int)new_sp - 4); /* add the return address */
*(int *)new_sp = ret;
atomic_off(old);
return new_sp;
}
static void _trampoline___stkrst(void)
{
void *new_sp;
void *old_sp;
SAVE_68K_REGS
new_sp = (void *)REG_D0;
old_sp = (void *)REG_A7;
REG_A7 = (u_int)stkrst68k(new_sp, old_sp);
RESTORE_68K_REGS
}
struct EmulLibEntry _gate___stkrst = {
TRAP_LIBRESTORE, 0, (void(*)())_trampoline___stkrst
};
char *stkrst68k_f(void *old_sp)
{
usetup;
struct StackSwapStruct sss;
struct Task *me = SysBase->ThisTask;
char *sp;
KPRINTF(("stkrst_f(%lx, %lx) [68k]\n", u.u_68k_stk_used->savesp, old_sp));
sss.stk_Pointer = sp = (char *)u.u_68k_stk_used->savesp;
popframes_68k(u.u_68k_stk_used, &sss);
me->tc_SPUpper = (void *)sss.stk_Upper;
me->tc_SPLower = sss.stk_Lower;
KPRINTF(("sp = %lx\n", sp));
return sp;
}
void _trampoline___stkrst_f(void)
{
sigset_t old;
void *old_sp;
SAVE_68K_REGS
atomic_on(&old);
old_sp = (void *)REG_A7;
REG_A7 = (u_int)stkrst68k_f(old_sp);
atomic_off(old);
RESTORE_68K_REGS
}
struct EmulLibEntry _gate___stkrst_f = {
TRAP_LIBRESTORE, 0, (void(*)())_trampoline___stkrst_f
};
char *stkrst68k_end(void *old_sp)
{
usetup;
struct StackSwapStruct sss;
struct Task *me = SysBase->ThisTask;
char *sp;
int ret;
KPRINTF(("stkrst_end(%lx, %lx) [68k]\n", u.u_68k_stk_used->savesp, old_sp));
ret = *(int *)old_sp;
sss.stk_Pointer = sp = (char *)u.u_68k_stk_used->savesp;
popframes_68k(u.u_68k_stk_used, &sss);
me->tc_SPUpper = (void *)sss.stk_Upper;
me->tc_SPLower = sss.stk_Lower;
KPRINTF(("sp = %lx\n", sp));
sp -= 4; /* add the return address */
*(int *)sp = ret;
return sp;
}
void _trampoline___stkrst_end(void)
{
sigset_t old;
void *old_sp;
SAVE_68K_REGS
atomic_on(&old);
old_sp = (void *)REG_A7;
REG_A7 = (u_int)stkrst68k_end(old_sp);
atomic_off(old);
RESTORE_68K_REGS
}
struct EmulLibEntry _gate___stkrst_end = {
TRAP_LIBRESTORE, 0, (void(*)())_trampoline___stkrst_end
};
/*
* Allocate a new stackframe with d0 bytes minimum.
*/
void __stkext_68k(void)
{
struct StackSwapStruct sss;
usetup;
u_int callsp = REG_A7 + 4;
u_int d0 = REG_D0;
sigset_t old;
struct Task *me = SysBase->ThisTask;
SAVE_68K_REGS
atomic_on(&old);
KPRINTF(("stkext_68k(%lx, %lx, %lx, %lx, %lx) limit = %lx\n", callsp, me->tc_SPUpper, me->tc_SPLower, u.u_68k_stk_used, d0, u.u_68k_stk_limit ? *u.u_68k_stk_limit : NULL));
if ((void *)callsp >= STK_UPPER_68K || (void *)callsp < STK_LOWER_68K)
return; /* User intentionally left area of stackextension */
pushframe_68k(d0, &sss, &old, 0);
me->tc_SPUpper = (void *)sss.stk_Upper;
me->tc_SPLower = sss.stk_Lower;
KPRINTF(("new a7 = %lx, upper = %lx, lower = %lx, used = %lx\n", sss.stk_Pointer, sss.stk_Upper, sss.stk_Lower, u.u_68k_stk_used));
atomic_off(old);
RESTORE_68K_REGS
REG_A7 = (u_int)sss.stk_Pointer;
}
struct EmulLibEntry _gate___stkext = {
TRAP_LIBRESTORE, 0, (void(*)())__stkext_68k
};
/*
* Allocate a new stackframe with d0 bytes minimum, copy the callers arguments
* and set his returnaddress (offset d1 from the sp when called) to stk_rst_f
*/
void __stkext_f_68k(void)
{
char *argtop;
int cpsize;
struct StackSwapStruct sss;
usetup;
void *callsp = (void *)(REG_A7 + 4);
u_int d0 = REG_D0;
u_int d1 = REG_D1;
sigset_t old;
struct Task *me = SysBase->ThisTask;
SAVE_68K_REGS
atomic_on(&old);
KPRINTF(("stkext_f_68k(%lx, %lx, %lx, %lx, %lx, %lx) limit = %lx\n", callsp, me->tc_SPUpper, me->tc_SPLower, u.u_68k_stk_used, d0, d1, u.u_68k_stk_limit ? *u.u_68k_stk_limit : NULL));
if ((void *)callsp >= STK_UPPER_68K || (void *)callsp < STK_LOWER_68K)
return; /* User intentionally left area of stackextension */
argtop = (char *)callsp + u.u_68k_stk_argbt; /* Top of area with arguments */
if ((void*)argtop > STK_UPPER_68K)
argtop = STK_UPPER_68K;
cpsize = (char *)argtop - (char *)callsp + 4;
/* FIXME: is "+ u.u_stk_argbt" really necessary? It's added in pushframe(), too. */
pushframe_68k(d0 + u.u_68k_stk_argbt, &sss, &old, 0);
*(char **)&sss.stk_Pointer -= cpsize;
CopyMem((char *)callsp - 4, sss.stk_Pointer, cpsize);
u.u_68k_stk_used->savesp = (char *)callsp + d1; /* store sp */
*(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp) + d1)
= &_gate___stkrst_f; /* set returnaddress */
me->tc_SPUpper = (void *)sss.stk_Upper;
me->tc_SPLower = sss.stk_Lower;
KPRINTF(("new a7 = %lx, upper = %lx, lower = %lx, used = %lx\n", sss.stk_Pointer, sss.stk_Upper, sss.stk_Lower, u.u_68k_stk_used));
REG_A7 = (u_int)sss.stk_Pointer;
atomic_off(old);
RESTORE_68K_REGS
}
struct EmulLibEntry _gate___stkext_f = {
TRAP_LIBRESTORE, 0, (void(*)())__stkext_f_68k
};
static void *stkext_startup_68k(int stack0, void* a7)
{
int stack;
sigset_t old;
struct StackSwapStruct sss;
struct Task *me = SysBase->ThisTask;
usetup;
KPRINTF(("stkext_startup_68k(%ld, %lx) sz = %ld\n", stack0, a7, u.u_68k_stk_argbt));
KPRINTF(("stack= %08lx %08lx %08lx %08lx %08lx\n", a7, *(int*)((int)a7+4), *(int*)((int)a7+8), *(int*)((int)a7+12), *(int*)((int)a7+16)));
stack = get_68k_stack_size((struct Process*)me, stack0);
if (stack)
{
pushframe_68k(stack, &sss, &old, 1);
u.u_68k_stk_used->savesp = (char *)a7 + 4;
sss.stk_Pointer = (APTR)((char*)sss.stk_Pointer - u.u_68k_stk_argbt);
memcpy((char *)sss.stk_Pointer, (char *)a7, u.u_68k_stk_argbt);
((void **)sss.stk_Pointer)[1] = &_gate___stkrst_end;
a7 = sss.stk_Pointer;
me->tc_SPUpper = (void *)sss.stk_Upper;
me->tc_SPLower = sss.stk_Lower;
}
KPRINTF(("new a7 = %lx\n", a7));
KPRINTF(("stack= %08lx %08lx %08lx %08lx %08lx\n", a7, *(int*)((int)a7+4), *(int*)((int)a7+8), *(int*)((int)a7+12), *(int*)((int)a7+16)));
return a7;
}
asm("
/* stack usage:
0-7: frame
8-71: caos
72-75: trash
76-79: sigset
80-155: save r13-r31
156-159:pad
*/
.globl _trampoline___stkext_startup
_trampoline___stkext_startup:
stwu 1,-160(1)
mflr 0
stmw 13,80(1) /* save ppc regs */
addi 3,1,76 /* r3 = &sigset */
lmw 16,0(2) /* r16-r31 = d0-a7 */
stw 0,164(1) /* save lr */
lwz 15,0(31) /* r15 = *sp = return address */
bl atomic_on
stmw 15,8(1) /* fill caos + trash */
/* install ppc stack */
mr 3,16 /* r3 = d0 = __stack */
mr 4,1 /* r4 = r1 */
addi 5,1,76 /* r5 = &sigset */
li 6,164 /* r6 = offset to saved lr */
bl stkext_startup_ppc /* r3 = new ppc stack */
mr 1,3 /* install new ppc stack */
/* install 68k stack */
mr 3,16 /* r3 = d0 = __stack */
mr 4,31 /* r4 = sp */
bl stkext_startup_68k /* need r3, r4 */
addi 3,3,8 /* r3 = a7 + 8 (skip two return addresses) */
lwz 13,4(31) /* r13 = pop next return address */
stw 3,60(2) /* REG_A7 = stk68k_startup() + 8 */
/* call the startup function */
lwz 15,0x5c(2) /* EmulCall68k */
lwz 3,76(1) /* r3 = sigset */
bl atomic_off
mtctr 15 /* ctr = EmulCall68k */
addi 3,1,8 /* r3 = &caos */
bctrl /* r3 = EmulCall68k(&caos) */
mr 16,3 /* new d0 = r3 */
/* restore the 68k stack if necessary */
lwz 4,60(2) /* r4 = new a7 */
addi 3,31,8 /* r3 = original a7 */
stwu 13,-4(4)
bl stkrst68k
mr 31,3
/*stw 13,0(31) /* put the 2nd return address back */
/* the ppc stack will be restored when this function returns */
lwz 0,164(1)
stmw 16,0(2) /* restore d0-a7 (d0 & a7 are changed) */
mtlr 0
mr 3,16
lmw 13,80(1) /* restore ppc regs */
addi 1,1,160
blr
");
void _trampoline___stkext_startup();
const struct EmulLibEntry _gate___stkext_startup = {
TRAP_LIBRESTORE, 0, (void(*)())_trampoline___stkext_startup
};
void initstack(void)
{
struct Task *me = SysBase->ThisTask;
struct user *u_ptr = getuser(me);
u.u_68k_tc_splower = me->tc_SPLower;
u.u_68k_tc_spupper = me->tc_SPUpper;
u.u_ppc_tc_splower = me->tc_ETask->PPCSPLower;
u.u_ppc_tc_spupper = me->tc_ETask->PPCSPUpper;
KPRINTF(("68k: lower=%lx, upper=%lx\n", u.u_68k_tc_splower, u.u_68k_tc_spupper));
KPRINTF(("ppc: lower=%lx, upper=%lx\n", u.u_ppc_tc_splower, u.u_ppc_tc_spupper));
u.u_68k_org_lower = u.u_68k_tc_splower; /* Lower stack bound */
u.u_68k_org_upper = u.u_68k_tc_spupper; /* Upper stack bound +1 */
u.u_68k_stk_used = NULL; /* Stackframes in use */
u.u_68k_stk_spare = NULL; /* Spare stackframes */
u.u_68k_stk_current = u.u_68k_stk_max = 0; /* No extended stackframes at this point */
u.u_68k_stk_limit = (void **)-1; /* Used uninitialized? Raise address error */
u.u_68k_stk_argbt = 256; /* set some useful default */
u.u_ppc_org_lower = u.u_ppc_tc_splower; /* Lower stack bound */
u.u_ppc_org_upper = u.u_ppc_tc_spupper; /* Upper stack bound +1 */
u.u_ppc_stk_used = NULL; /* Stackframes in use */
u.u_ppc_stk_spare = NULL; /* Spare stackframes */
u.u_ppc_stk_current = u.u_ppc_stk_max = 0; /* No extended stackframes at this point */
u.u_ppc_stk_limit = (void **)-1; /* Used uninitialized? Raise address error */
u.u_ppc_stk_argbt = 256; /* set some useful default */
}
void __init_stk_limit(void **limit, unsigned long argbytes)
{
usetup;
u.u_68k_stk_limit = NULL;
u.u_ppc_stk_limit = limit;
u.u_ppc_stk_argbt = argbytes;
*limit = (char *)u.u_ppc_org_lower + stk_safezone_ppc + argbytes;
KPRINTF(("init_stk_limit_ppc(%lx, %ld)\n", *limit, argbytes));
}
void __init_stk_limit_68k(void)
{
u_int *sp = (u_int*)REG_A7;
void **limit = (void**)sp[1];
unsigned long argbytes = sp[2];
usetup;
u.u_ppc_stk_limit = NULL;
u.u_68k_stk_limit = limit;
u.u_68k_stk_argbt = argbytes;
*limit = (char *)u.u_68k_org_lower + stk_safezone_68k + argbytes;
KPRINTF(("init_stk_limit_68k(%lx, %ld)\n", *limit, argbytes));
}
const struct EmulLibEntry _gate___init_stk_limit = {
TRAP_LIBNR, 0, (void(*)())__init_stk_limit_68k
};
/*
* Free all spare stackframes
*/
void freestack(void)
{
struct stackframe *sf, *s2;
usetup;
KPRINTF(("freestack\n"));
sf = u.u_ppc_stk_spare;
u.u_ppc_stk_spare = NULL;
while (sf != NULL)
{
s2 = sf->next;
KPRINTF(("FreeMem(%lx, %ld)\n", sf, (char *)sf->upper - (char *)sf));
FreeMem(sf, (char *)sf->upper - (char *)sf);
sf = s2;
}
sf = u.u_68k_stk_spare;
u.u_68k_stk_spare = NULL;
while (sf != NULL)
{
s2 = sf->next;
KPRINTF(("FreeMem(%lx, %ld)\n", sf, (char *)sf->upper - (char *)sf));
FreeMem(sf, (char *)sf->upper - (char *)sf);
sf = s2;
}
}
void __stkovf(void)
{
usetup;
KPRINTF(("stkovf\n"));
u.u_ppc_stk_limit = NULL; /* disable stackextend from now on */
for (;;) {
kill(getpid(), SIGSEGV); /* Ciao */
Delay(50);
}
}
void __stkovf_68k(void)
{
usetup;
KPRINTF(("stkovf68k\n"));
u.u_68k_stk_limit = NULL; /* disable stackextend from now on */
for (;;) {
kill(getpid(), SIGSEGV); /* Ciao */
Delay(50);
}
}
const struct EmulLibEntry _gate___stkovf = {
TRAP_LIBNR, 0, (void(*)())__stkovf_68k
};
/*
* Move a stackframe with a minimum of requiredstack bytes to the used list
* and fill the StackSwapStruct structure.
*/
static void pushframe_68k(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old, int startup)
{
struct stackframe *sf;
ULONG recommendedstack;
usetup;
KPRINTF(("pushframe_68k(%ld, %ld)\n", requiredstack, startup));
if (!startup)
{
requiredstack += stk_safezone_68k + u.u_68k_stk_argbt;
if (requiredstack < stk_minframe_68k)
requiredstack = stk_minframe_68k;
}
recommendedstack=u.u_68k_stk_max-u.u_68k_stk_current;
if (recommendedstack<requiredstack)
recommendedstack=requiredstack;
for (;;)
{
sf = u.u_68k_stk_spare; /* get a stackframe from the spares list */
if (sf == NULL)
{ /* stack overflown */
for (; recommendedstack>=requiredstack; recommendedstack/=2)
{
sf = AllocMem(recommendedstack + sizeof(struct stackframe), MEMF_PUBLIC);
KPRINTF(("AllocMem(%ld) = %lx\n", recommendedstack + sizeof(struct stackframe), sf));
if (sf != NULL)
break;
}
if (sf == NULL)
{ /* and we have no way to extend it :-| */
sigprocmask(SIG_SETMASK, old, NULL);
__stkovf_68k();
}
sf->upper = (char *)(sf + 1) + recommendedstack;
KPRINTF(("new frame: %lx - %lx\n", sf + 1, sf->upper));
break;
}
u.u_68k_stk_spare = sf->next;
if ((char *)sf->upper - (char *)(sf + 1) >= recommendedstack)
break;
KPRINTF(("FreeMem(%lx, %ld)\n", sf, (char *)sf->upper - (char *)sf));
FreeMem(sf, (char *)sf->upper - (char *)sf);
}
/* Add stackframe to the used list */
sf->next = u.u_68k_stk_used;
u.u_68k_stk_used = sf;
if (u.u_68k_stk_limit)
*u.u_68k_stk_limit = (char *)(sf + 1) + stk_safezone_68k + u.u_68k_stk_argbt;
/* prepare StackSwapStruct */
(void *)sss->stk_Pointer = (void *)sf->upper;
sss->stk_Lower = sf + 1;
(ULONG)sss->stk_Upper = (ULONG)sf->upper;
KPRINTF(("used = %lx, ptr = %lx, lower = %lx, upper = %lx, limit = %lx\n",
u.u_68k_stk_used, sss->stk_Pointer, sss->stk_Lower, sss->stk_Upper, u.u_68k_stk_limit ? *u.u_68k_stk_limit : NULL));
/* Update stack statistics. */
u.u_68k_stk_current += (char *)sf->upper - (char *)(sf + 1);
if (u.u_68k_stk_current > u.u_68k_stk_max)
u.u_68k_stk_max = u.u_68k_stk_current;
}
static void pushframe_ppc(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old, int startup)
{
struct stackframe *sf;
ULONG recommendedstack;
usetup;
KPRINTF(("pushframe_ppc(%ld, %ld)\n", requiredstack, startup));
if (!startup)
{
requiredstack += stk_safezone_ppc + u.u_ppc_stk_argbt;
if (requiredstack < stk_minframe_ppc)
requiredstack = stk_minframe_ppc;
}
recommendedstack=u.u_ppc_stk_max-u.u_ppc_stk_current;
if (recommendedstack<requiredstack)
recommendedstack=requiredstack;
for (;;)
{
sf = u.u_ppc_stk_spare; /* get a stackframe from the spares list */
if (sf == NULL)
{ /* stack overflown */
for (; recommendedstack>=requiredstack; recommendedstack/=2)
{
sf = AllocMem(recommendedstack + sizeof(struct stackframe), MEMF_PUBLIC);
KPRINTF(("AllocMem(%ld) = %lx\n", recommendedstack + sizeof(struct stackframe), sf));
if (sf != NULL)
break;
}
if (sf == NULL)
{ /* and we have no way to extend it :-| */
sigprocmask(SIG_SETMASK, old, NULL);
__stkovf();
}
sf->upper = (char *)(sf + 1) + recommendedstack;
KPRINTF(("new frame: %lx - %lx\n", sf + 1, sf->upper));
break;
}
u.u_ppc_stk_spare = sf->next;
if ((char *)sf->upper - (char *)(sf + 1) >= recommendedstack)
break;
KPRINTF(("FreeMem(%lx, %ld)\n", sf, (char *)sf->upper - (char *)sf));
FreeMem(sf, (char *)sf->upper - (char *)sf);
}
/* Add stackframe to the used list */
sf->next = u.u_ppc_stk_used;
u.u_ppc_stk_used = sf;
if (u.u_ppc_stk_limit)
*u.u_ppc_stk_limit = (char *)(sf + 1) + stk_safezone_ppc + u.u_ppc_stk_argbt;
/* prepare StackSwapStruct */
(void *)sss->stk_Pointer = (void *)sf->upper;
sss->stk_Lower = sf + 1;
(ULONG)sss->stk_Upper = (ULONG)sf->upper;
KPRINTF(("used = %lx, ptr = %lx, lower = %lx, upper = %lx, limit = %lx\n",
u.u_ppc_stk_used, sss->stk_Pointer, sss->stk_Lower, sss->stk_Upper, u.u_ppc_stk_limit ? *u.u_ppc_stk_limit : NULL));
/* Update stack statistics. */
u.u_ppc_stk_current += (char *)sf->upper - (char *)(sf + 1);
if (u.u_ppc_stk_current > u.u_ppc_stk_max)
u.u_ppc_stk_max = u.u_ppc_stk_current;
}
/*
* Move all used stackframes upto (and including) sf to the spares list
* and fill the StackSwapStruct structure.
*/
static void popframes_68k(struct stackframe *sf, struct StackSwapStruct *sss)
{
struct stackframe *sf2;
usetup;
KPRINTF(("popframes\n"));
if (sf->next != NULL)
{
sss->stk_Lower = sf->next + 1;
(ULONG)sss->stk_Upper = (ULONG)sf->next->upper;
if (u.u_68k_stk_limit)
*u.u_68k_stk_limit = (char *)(sf->next + 1) + stk_safezone_68k + u.u_68k_stk_argbt;
}
else
{
sss->stk_Lower = u.u_68k_tc_splower;
(ULONG)sss->stk_Upper = (ULONG)u.u_68k_tc_spupper;
if (u.u_68k_stk_limit)
*u.u_68k_stk_limit = (char *)u.u_68k_org_lower + stk_safezone_68k + u.u_68k_stk_argbt;
}
KPRINTF(("lower = %lx, upper = %lx, limit = %lx\n", sss->stk_Lower, sss->stk_Upper, u.u_68k_stk_limit ? *u.u_68k_stk_limit : NULL));
sf2 = u.u_68k_stk_spare;
u.u_68k_stk_spare = u.u_68k_stk_used;
u.u_68k_stk_used = sf->next;
sf->next = sf2;
/* Update stack statistics. */
for (sf2 = u.u_68k_stk_spare; sf2 != sf->next; sf2 = sf2->next)
{
KPRINTF(("poping frame %lx-%lx \n", sf2 + 1, sf2->upper));
u.u_68k_stk_current -= (char *)sf2->upper - (char *)(sf2 + 1);
}
}
static void popframes_ppc(struct stackframe *sf, struct StackSwapStruct *sss)
{
struct stackframe *sf2;
usetup;
KPRINTF(("popframes\n"));
if (sf->next != NULL)
{
sss->stk_Lower = sf->next + 1;
(ULONG)sss->stk_Upper = (ULONG)sf->next->upper;
if (u.u_ppc_stk_limit)
*u.u_ppc_stk_limit = (char *)(sf->next + 1) + stk_safezone_ppc + u.u_ppc_stk_argbt;
}
else
{
sss->stk_Lower = u.u_ppc_tc_splower;
(ULONG)sss->stk_Upper = (ULONG)u.u_ppc_tc_spupper;
if (u.u_ppc_stk_limit)
*u.u_ppc_stk_limit = (char *)u.u_ppc_org_lower + stk_safezone_ppc + u.u_ppc_stk_argbt;
}
KPRINTF(("lower = %lx, upper = %lx, limit = %lx\n", sss->stk_Lower, sss->stk_Upper, u.u_ppc_stk_limit ? *u.u_ppc_stk_limit : NULL));
sf2 = u.u_ppc_stk_spare;
u.u_ppc_stk_spare = u.u_ppc_stk_used;
u.u_ppc_stk_used = sf->next;
sf->next = sf2;
/* Update stack statistics. */
for (sf2 = u.u_ppc_stk_spare; sf2 != sf->next; sf2 = sf2->next)
{
KPRINTF(("poping frame %lx-%lx \n", sf2 + 1, sf2->upper));
u.u_ppc_stk_current -= (char *)sf2->upper - (char *)(sf2 + 1);
}
}
#else
#define STK_UPPER \
(u.u_stk_used != NULL ? u.u_stk_used->upper : u.u_org_upper)
#define STK_LOWER \
(u.u_stk_used != NULL ? (void *)(u.u_stk_used + 1) : u.u_org_lower)
#define stk_safezone 6144 /* into ixprefs? */
#define stk_minframe 32768
void clearstack() //68k use that
{
struct Task *me = SysBase->ThisTask;
unsigned long tmp = (char *)(get_sp() - 256); /* 256 bytes safety margin */
memset(me->tc_SPLower+4, 0xdb, ((u_long)tmp - (u_long)me->tc_SPLower)-4);
}
static void popframes(struct stackframe *sf, struct StackSwapStruct *sss);
static void pushframe(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old, int startup);
void __init_stk_limit(void **limit, unsigned long argbytes);
void __stkrst_f(void);
asm(" \n\
.globl ___stkext \n\
___stkext: \n\
moveml d0/d1/a0/a1/a6,sp@- \n\
subqw #4,sp | sigset_t \n\
pea sp@ \n\
jbsr _atomic_on \n\
subqw #8,sp | struct StackSwapStruct (8+4 from pea above) \n\
jbsr _stkext \n\
tstl d0 \n\
jeq s_noext \n\
movel _SysBase,a6 \n\
movel sp,a0 \n\
jsr a6@(-0x2dc) | StackSwap(a0) \n\
s_ret: \n\
jbsr _atomic_off \n\
addqw #4,sp | StackSwapStruct is not copied \n\
moveml sp@+,d0/d1/a0/a1/a6 \n\
rts \n\
s_noext: \n\
addw #12,sp \n\
jra s_ret \n\
\n\
.globl ___stkext_f | see above \n\
___stkext_f: \n\
moveml d0/d1/a0/a1/a6,sp@- \n\
subqw #4,sp \n\
pea sp@ \n\
jbsr _atomic_on \n\
subqw #8,sp \n\
jbsr _stkext_f \n\
tstl d0 \n\
jeq sf_noext \n\
movel _SysBase,a6 \n\
movel sp,a0 \n\
jsr a6@(-0x2dc) \n\
sf_ret: \n\
jbsr _atomic_off \n\
addqw #4,sp \n\
moveml sp@+,d0/d1/a0/a1/a6 \n\
rts \n\
sf_noext: \n\
addw #12,sp \n\
jra sf_ret \n\
\n\
.globl ___stkext_startup \n\
___stkext_startup: \n\
moveml d0/d1/a0/a1/a6,sp@- \n\
subqw #4,sp \n\
pea sp@ \n\
jbsr _atomic_on | FIXME: Is this necessary/allowed that early? \n\
subqw #8,sp \n\
jbsr _stkext_startup \n\
tstl d0 \n\
jeq ss_noext \n\
movel _SysBase,a6 \n\
movel sp,a0 \n\
jsr a6@(-0x2dc) \n\
jsr _clearstack \n\
ss_ret: \n\
jbsr _atomic_off | FIXME: Is this necessary/allowed that early? \n\
addqw #4,sp \n\
moveml sp@+,d0/d1/a0/a1/a6 \n\
rts \n\
ss_noext: \n\
addw #12,sp \n\
jra ss_ret \n\
\n\
.globl ___stkrst_f | see above \n\
___stkrst_f: \n\
moveml d0/d1/a0/a1/a6,sp@- \n\
subqw #4,sp \n\
pea sp@ \n\
jbsr _atomic_on \n\
subqw #8,sp \n\
jbsr _stkrst_f \n\
movel _SysBase,a6 \n\
movel sp,a0 \n\
jsr a6@(-0x2dc) \n\
jbsr _atomic_off \n\
addqw #4,sp \n\
moveml sp@+,d0/d1/a0/a1/a6 \n\
rts \n\
\n\
.globl ___stkrst \n\
___stkrst: \n\
moveml d0/d1/a0/a1/a6,sp@- | preserve registers \n\
subqw #4,sp | make room for the signal mask \n\
pea sp@ \n\
jbsr _atomic_on | disable all signals \n\
subqw #8,sp | make room for a StackSwapStruct \n\
jbsr _stkrst | calculate either target sp or StackSwapStruct \n\
tstl d0 | set target sp? \n\
jeq swpfrm | jump if not \n\
movel d0,a0 | I have a lot of preserved registers and \n\
| returnadresses on the stack. It's necessary \n\
| to copy them to the new location \n\
moveq #6,d0 | 1 rts, 5 regs and 1 signal mask to copy (1+5+1)-1=6 \n\
lea sp@(40:W),a1 | get address of uppermost byte+1 (1+5+1)*4+12=40 \n\
cmpl a0,a1 | compare with target location \n\
jls lp1 | jump if source<=target \n\
lea a0@(-28:W),a0 | else start at lower bound (1+5+1)*4=28 \n\
lea a1@(-28:W),a1 \n\
movel a0,sp | set sp to reserve the room \n\
lp0: movel a1@+,a0@+ | copy with raising addresses \n\
dbra d0,lp0 | as long as d0>=0. \n\
jra endlp | ready \n\
lp1: movel a1@-,a0@- | copy with falling addresses \n\
dbra d0,lp1 | as long as d0>=0 \n\
movel a0,sp | finally set sp \n\
jra endlp | ready \n\
swpfrm: movel _SysBase,a6 | If sp wasn't set call StackSwap() \n\
movel sp,a0 \n\
jsr a6@(-0x2dc) \n\
endlp: jbsr _atomic_off | reenable signals \n\
addqw #4,sp | adjust sp \n\
moveml sp@+,d0/d1/a0/a1/a6 | restore registers \n\
rts | and return \n\
");
void initstack(void)
{
APTR lower, upper;
struct Task *me = SysBase->ThisTask;
struct user *u_ptr = getuser(me);
struct Process *proc = (struct Process *)me;
u.u_tc_splower = me->tc_SPLower;
u.u_tc_spupper = me->tc_SPUpper;
KPRINTF(("lower=%lx, upper=%lx\n", u.u_tc_splower, u.u_tc_spupper));
if (proc->pr_CLI)
{
/* Process stackframe:
* proc->pr_ReturnAddr points to size of stack (ULONG)
* +4 returnaddress
* +8 stackframe
*/
lower = (char *)proc->pr_ReturnAddr + 8 - *(ULONG *)proc->pr_ReturnAddr;
upper = (char *)proc->pr_ReturnAddr + 8;
}
else
{
lower = u.u_tc_splower;
upper = u.u_tc_spupper;
}
KPRINTF(("lower=%lx, upper=%lx\n", lower, upper));
u.u_org_lower = lower; /* Lower stack bound */
u.u_org_upper = upper; /* Upper stack bound +1 */
u.u_stk_used = NULL; /* Stackframes in use */
u.u_stk_spare = NULL; /* Spare stackframes */
u.u_stk_current=u.u_stk_max=0; /* No extended stackframes at this point */
u.u_stk_limit = (void **)-1; /* Used uninitialized? Raise address error */
u.u_stk_argbt = 256; /* set some useful default */
}
void __init_stk_limit(void **limit, unsigned long argbytes)
{
usetup;
u.u_stk_limit = limit;
u.u_stk_argbt = argbytes;
*limit = (char *)u.u_org_lower + stk_safezone + argbytes;
KPRINTF(("init_stk_limit(%lx, %ld)\n", *limit, argbytes));
}
/*
* Free all spare stackframes
*/
void freestack(void) // used in 68k
{
struct stackframe *sf, *s2;
usetup;
KPRINTF(("freestack\n"));
sf = u.u_stk_spare;
u.u_stk_spare = NULL;
while (sf != NULL)
{
s2 = sf->next;
KPRINTF(("FreeMem(%lx, %ld)\n", sf, (char *)sf->upper - (char *)sf));
FreeMem(sf, (char *)sf->upper - (char *)sf);
sf = s2;
}
}
void __stkovf(void)
{
usetup;
KPRINTF(("stkovf\n"));
u.u_stk_limit = NULL; /* disable stackextend from now on */
for (;;) {
kill(getpid(), SIGSEGV); /* Ciao */
Delay(50);
}
}
/*
* Move a stackframe with a minimum of requiredstack bytes to the used list
* and fill the StackSwapStruct structure.
*/
static void pushframe(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old, int startup)
{ // used for 68k
struct stackframe *sf;
ULONG recommendedstack;
usetup;
KPRINTF(("pushframe(%ld, %ld)\n", requiredstack, startup));
if (!startup)
{
requiredstack += stk_safezone + u.u_stk_argbt;
if (requiredstack < stk_minframe)
requiredstack = stk_minframe;
}
recommendedstack=u.u_stk_max-u.u_stk_current;
if (recommendedstack<requiredstack)
recommendedstack=requiredstack;
for (;;)
{
sf = u.u_stk_spare; /* get a stackframe from the spares list */
if (sf == NULL)
{ /* stack overflown */
for (; recommendedstack>=requiredstack; recommendedstack/=2)
{
sf = AllocMem(recommendedstack + sizeof(struct stackframe), MEMF_PUBLIC);
KPRINTF(("AllocMem(%ld) = %lx\n", recommendedstack + sizeof(struct stackframe), sf));
if (sf != NULL)
break;
}
if (sf == NULL)
{ /* and we have no way to extend it :-| */
sigprocmask(SIG_SETMASK, old, NULL);
__stkovf();
}
sf->upper = (char *)(sf + 1) + recommendedstack;
KPRINTF(("new frame: %lx - %lx\n", sf + 1, sf->upper));
break;
}
u.u_stk_spare = sf->next;
if ((char *)sf->upper - (char *)(sf + 1) >= recommendedstack)
break;
KPRINTF(("FreeMem(%lx, %ld)\n", sf, (char *)sf->upper - (char *)sf));
FreeMem(sf, (char *)sf->upper - (char *)sf);
}
/* Add stackframe to the used list */
sf->next = u.u_stk_used;
u.u_stk_used = sf;
*u.u_stk_limit = (char *)(sf + 1) + stk_safezone + u.u_stk_argbt;
/* prepare StackSwapStruct */
(void *)sss->stk_Pointer = (void *)sf->upper;
sss->stk_Lower = sf + 1;
(ULONG)sss->stk_Upper = (ULONG)sf->upper;
KPRINTF(("used = %lx, ptr = %lx, lower = %lx, upper = %lx, limit = %lx\n",
u.u_stk_used, sss->stk_Pointer, sss->stk_Lower, sss->stk_Upper, *u.u_stk_limit));
/* Update stack statistics. */
u.u_stk_current += (char *)sf->upper - (char *)(sf + 1);
if (u.u_stk_current > u.u_stk_max)
u.u_stk_max = u.u_stk_current;
}
/*
* Allocate a new stackframe with d0 bytes minimum.
*/
int stkext(struct StackSwapStruct sss, sigset_t old,
long d0, long d1, long a0, long a1, long a6, long ret1)
{
void *callsp = &ret1 + 1;
int cpsize = (char *)callsp - (char *)&old;
usetup;
if (callsp >= STK_UPPER || callsp < STK_LOWER)
return 0; /* User intentionally left area of stackextension */
KPRINTF(("stkext\n"));
pushframe(d0, &sss, &old, 0);
*(char **)&sss.stk_Pointer -= cpsize;
CopyMem(&old, sss.stk_Pointer, cpsize);
return 1;
}
/*
* Allocate a new stackframe with d0 bytes minimum, copy the callers arguments
* and set his returnaddress (offset d1 from the sp when called) to stk_rst_f
*/
int stkext_f(struct StackSwapStruct sss, sigset_t old,
long d0, long d1, long a0, long a1, long a6, long ret1)
{
void *argtop, *callsp = &ret1 + 1;
int cpsize;
usetup;
if (callsp >= STK_UPPER || callsp < STK_LOWER)
return 0; /* User intentionally left area of stackextension */
KPRINTF(("stkext_f: d0=%lx, argbt=%lx, old=%08lx\n", d0, u.u_stk_argbt, old));
argtop = (char *)callsp + u.u_stk_argbt; /* Top of area with arguments */
if (argtop > STK_UPPER)
argtop = STK_UPPER;
cpsize = (char *)argtop - (char *)&old;
/* FIXME: is "+ u.u_stk_argbt" really necessary? It's added in pushframe(), too. */
pushframe(d0 + u.u_stk_argbt, &sss, &old, 0);
*(char **)&sss.stk_Pointer -= cpsize;
CopyMem(&old, sss.stk_Pointer, cpsize);
u.u_stk_used->savesp = (char *)callsp + d1; /* store sp */
*(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp) + d1)
= &__stkrst_f; /* set returnaddress */
return 1;
}
extern long __ixstack;
static int get_stack_size(struct Process *proc, int stack) // 68k use that
{
struct CommandLineInterface *CLI;
if (stack <= STACKSIZE)
{
if (__ixstack)stack = __ixstack;
else
stack = 512000;
}
if (stack < STACKSIZE)
stack = STACKSIZE;
/* NOTE: This is the most appropriate place for future support of
user-specified, process-specific stacksizes. */
CLI = BTOCPTR (proc->pr_CLI);
if (stack <= (CLI ? CLI->cli_DefaultStack * 4 : proc->pr_StackSize))
return 0;
return stack;
}
/*
* Called at startup to set stack to a safe/reasonable value (which is
* provided in d0). Check if there is a need for stack extension at startup,
* return 0 if it is not necessary. If it is, perform almost the same actions
* as stkext_f.
*/
int stkext_startup(struct StackSwapStruct sss, sigset_t old,
long d0, long d1, long a0, long a1, long a6, long ret1) //68k use that
{
void *argtop, *callsp = &ret1 + 1;
int cpsize, stack;
usetup;
struct Task *me = SysBase->ThisTask;
if (!(stack = get_stack_size((struct Process*)me, d0)))
return 0;
argtop = (char *)callsp + u.u_stk_argbt; /* Top of area with arguments */
if (argtop > STK_UPPER)
argtop = STK_UPPER;
cpsize = (char *)argtop - (char *)&old;
pushframe(stack, &sss, &old, 1);
*(char **)&sss.stk_Pointer -= cpsize;
CopyMem(&old,sss.stk_Pointer, cpsize);
u.u_stk_used->savesp = (char *)callsp; /* store sp */
*(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp))
= &__stkrst_f; /* set returnaddress */
return 1;
}
/*
* Move all used stackframes upto (and including) sf to the spares list
* and fill the StackSwapStruct structure.
*/
static void popframes(struct stackframe *sf, struct StackSwapStruct *sss)
{
struct stackframe *sf2;
usetup;
KPRINTF(("popframes\n"));
ix_stack_usage();
if (sf->next != NULL)
{
sss->stk_Lower = sf->next + 1;
(ULONG)sss->stk_Upper = (ULONG)sf->next->upper;
*u.u_stk_limit = (char *)(sf->next + 1) + stk_safezone + u.u_stk_argbt;
}
else
{
sss->stk_Lower = u.u_tc_splower;
(ULONG)sss->stk_Upper = (ULONG)u.u_tc_spupper;
*u.u_stk_limit = (char *)u.u_org_lower + stk_safezone + u.u_stk_argbt;
}
KPRINTF(("lower = %lx, upper = %lx, limit = %lx\n", sss->stk_Lower, sss->stk_Upper, *u.u_stk_limit));
sf2 = u.u_stk_spare;
u.u_stk_spare = u.u_stk_used;
u.u_stk_used = sf->next;
sf->next = sf2;
/* Update stack statistics. */
for (sf2 = u.u_stk_spare; sf2 != sf->next; sf2 = sf2->next)
{
KPRINTF(("poping frame %lx-%lx \n", sf2 + 1, sf2->upper));
u.u_stk_current -= (char *)sf2->upper - (char *)(sf2 + 1);
}
}
/*
* Set stackpointer back to some previous value
* != NULL: on the same stackframe (returns sp)
* == NULL: on another stackframe
*/
void *stkrst(struct StackSwapStruct sss, sigset_t old,
void *d0, long d1, long a0, long a1, long a6, long ret1)
{
void *callsp = &ret1 + 1;
int cpsize = (char *)callsp - (char *)&old;
struct stackframe *sf1, *sf2;
usetup;
if (d0 >= STK_LOWER && d0 < STK_UPPER)
return d0;
KPRINTF(("stkrst\n"));
sf1 = u.u_stk_used;
if (sf1 == NULL)
return d0;
for (;;)
{
sf2 = sf1->next;
if (sf2 == NULL)
{
if (d0 < u.u_org_lower || d0 >= u.u_org_upper)
return d0;
break;
}
if (d0 >= (void *)(sf2 + 1) && d0 < sf2->upper) /* This stackframe fits */
break;
sf1 = sf2;
}
popframes(sf1, &sss);
sss.stk_Pointer = (char *)d0 - cpsize;
CopyMem(&old, sss.stk_Pointer,cpsize);
return NULL;
}
/*
* return to last stackframe
*/
void stkrst_f(struct StackSwapStruct sss, sigset_t old,
long d0, long d1, long a0, long a1, long a6)
{
void *callsp = &a6 + 1; /* This one has no returnaddress - it's a fallback for rts */
int cpsize = (char *)callsp - (char *)&old;
usetup;
KPRINTF(("stkrst_f\n"));
sss.stk_Pointer = (char *)u.u_stk_used->savesp - cpsize;
popframes(u.u_stk_used, &sss);
CopyMem(&old, sss.stk_Pointer, cpsize);
}
#endif