home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ixemul-45.0-src.tgz / tar.out / contrib / ixemul / library / stackextend.c < prev    next >
C/C++ Source or Header  |  1996-10-04  |  12KB  |  453 lines

  1. #define    _KERNEL
  2. #include "ixemul.h"
  3.  
  4. #include <exec/memory.h>
  5. #include <signal.h>
  6. #include <unistd.h>
  7.  
  8. /*
  9.  * Glue asm to C.
  10.  */
  11. asm("
  12.     .globl    ___stkext
  13. ___stkext:
  14.     moveml    d0/d1/a0/a1/a6,sp@-
  15.     subqw    #4,sp        | sigset_t
  16.     jbsr    _atomic_on
  17.     subw    #12,sp        | struct StackSwapStruct
  18.     jbsr    _stkext
  19.     tstl    d0
  20.     jeq    s_noext
  21.     movel    4:W,a6
  22.     movel    sp,a0
  23.     jsr    a6@(-0x2dc)    | StackSwap(a0)
  24. s_ret:
  25.     jbsr    _atomic_off
  26.     addqw    #4,sp        | StackSwapStruct is not copied
  27.     moveml    sp@+,d0/d1/a0/a1/a6
  28.     rts
  29. s_noext:
  30.     addw    #12,sp
  31.     jra    s_ret
  32.  
  33.     .globl    ___stkext_f    | see above
  34. ___stkext_f:
  35.     moveml    d0/d1/a0/a1/a6,sp@-
  36.     subqw    #4,sp
  37.     jbsr    _atomic_on
  38.     subw    #12,sp
  39.     jbsr    _stkext_f
  40.     tstl    d0
  41.     jeq    sf_noext
  42.     movel    4:W,a6
  43.     movel    sp,a0
  44.     jsr    a6@(-0x2dc)
  45. sf_ret:
  46.     jbsr    _atomic_off
  47.     addqw    #4,sp
  48.     moveml    sp@+,d0/d1/a0/a1/a6
  49.       rts
  50. sf_noext:
  51.     addw    #12,sp
  52.     jra    sf_ret
  53.   
  54.     .globl    ___stkext_startup
  55. ___stkext_startup:
  56.     moveml    d0/d1/a0/a1/a6,sp@-
  57.     subqw    #4,sp
  58.     jbsr    _atomic_on    | FIXME: Is this necessary/allowed that early?
  59.     subw    #12,sp
  60.     jbsr    _stkext_startup
  61.     tstl    d0
  62.     jeq    ss_noext
  63.     movel    4:W,a6
  64.     movel    sp,a0
  65.     jsr    a6@(-0x2dc)
  66. ss_ret:
  67.     jbsr    _atomic_off    | FIXME: Is this necessary/allowed that early?
  68.     addqw    #4,sp
  69.     moveml    sp@+,d0/d1/a0/a1/a6
  70.       rts
  71. ss_noext:
  72.     addw    #12,sp
  73.     jra    ss_ret
  74.  
  75.     .globl    ___stkrst_f    | see above
  76. ___stkrst_f:
  77.     moveml    d0/d1/a0/a1/a6,sp@-
  78.     subqw    #4,sp
  79.     jbsr    _atomic_on
  80.     subw    #12,sp
  81.     jbsr    _stkrst_f
  82.     movel    4:W,a6
  83.     movel    sp,a0
  84.     jsr    a6@(-0x2dc)
  85.     jbsr    _atomic_off
  86.     addqw    #4,sp
  87.     moveml    sp@+,d0/d1/a0/a1/a6
  88.       rts
  89.   
  90.     .globl    ___stkrst
  91. ___stkrst:
  92.     moveml    d0/d1/a0/a1/a6,sp@-        | preserve registers
  93.     subqw    #4,sp        | make room for the signal mask
  94.     jbsr    _atomic_on    | disable all signals
  95.     subw    #12,sp        | make room for a StackSwapStruct
  96.     jbsr    _stkrst        | calculate either target sp or StackSwapStruct
  97.     tstl    d0        | set target sp?
  98.     jeq    swpfrm        | jump if not
  99.     movel    d0,a0        | I have a lot of preserved registers and
  100.                 | returnadresses on the stack. It's necessary
  101.                 | to copy them to the new location
  102.     moveq    #6,d0        | 1 rts, 5 regs and 1 signal mask to copy (2+5+1)-1=7
  103.     lea    sp@(40:W),a1    | get address of uppermost byte+1 (1+5+1)*4+12=40
  104.     cmpl    a0,a1        | compare with target location
  105.     jls    lp1        | jump if source<=target
  106.     lea    a0@(-28:W),a0    | else start at lower bound (1+5+1)*4=28
  107.     lea    a1@(-28:W),a1
  108.     movel    a0,sp        | set sp to reserve the room
  109. lp0:    movel    a1@+,a0@+    | copy with raising addresses
  110.     dbra    d0,lp0        | as long as d0>=0.
  111.     jra    endlp        | ready
  112. lp1:    movel    a1@-,a0@-    | copy with falling addresses
  113.     dbra    d0,lp1        | as long as d0>=0
  114.     movel    a0,sp        | finally set sp
  115.     jra    endlp        | ready
  116. swpfrm:    movel    4:W,a6        | If sp wasn't set call StackSwap()
  117.     movel    sp,a0
  118.     jsr    a6@(-0x2dc)
  119. endlp:    jbsr    _atomic_off    | reenable signals
  120.     addqw    #4,sp        | adjust sp
  121.     moveml    sp@+,d0/d1/a0/a1/a6        | restore registers
  122.     rts            | and return
  123. ");
  124.  
  125. void __stkrst_f(void);
  126.  
  127. #define    STK_UPPER    \
  128. (u.u_stk_used != NULL ? u.u_stk_used->upper : u.u_org_upper)
  129.  
  130. #define    STK_LOWER    \
  131. (u.u_stk_used != NULL ? (void *)(u.u_stk_used + 1) : u.u_org_lower)
  132.  
  133. #define    stk_safezone    6144    /* into ixprefs? */
  134. #define    stk_minframe    32768
  135.  
  136. void initstack(void)
  137. {
  138.   struct Process *me;
  139.   APTR lower, upper;
  140.  
  141.   me = (struct Process *)SysBase->ThisTask;
  142.  
  143.   u.u_tc_splower = me->pr_Task.tc_SPLower;
  144.   u.u_tc_spupper = me->pr_Task.tc_SPUpper;
  145.  
  146.   if (me->pr_CLI)
  147.   {
  148.     /* Process stackframe:
  149.      * me->pr_ReturnAddr points to size of stack (ULONG)
  150.      *         +4                  returnaddress
  151.      *         +8                  stackframe
  152.      */
  153.     lower = (char *)me->pr_ReturnAddr + 8 - *(ULONG *)me->pr_ReturnAddr;
  154.     upper = (char *)me->pr_ReturnAddr + 8;
  155.   }
  156.   else
  157.   {
  158.     lower = u.u_tc_splower;
  159.     upper = u.u_tc_spupper;
  160.   }
  161.  
  162.   u.u_org_lower = lower; /* Lower stack bound */
  163.   u.u_org_upper = upper; /* Upper stack bound +1 */
  164.   u.u_stk_used = NULL;   /* Stackframes in use */
  165.   u.u_stk_spare = NULL;  /* Spare stackframes */
  166.   u.u_stk_current=u.u_stk_max=0; /* No extended stackframes at this point */
  167.  
  168.   u.u_stk_limit = (void **)-1; /* Used uninitialized? Raise address error */
  169.   u.u_stk_argbt = 256; /* set some useful default */
  170. }
  171.  
  172. void __init_stk_limit(void **limit, unsigned long argbytes)
  173. {
  174.   u.u_stk_limit = limit;
  175.   u.u_stk_argbt = argbytes;
  176.   *limit = (char *)u.u_org_lower + stk_safezone + argbytes;
  177. }
  178.  
  179. /*
  180.  * Free all spare stackframes
  181.  */
  182. void freestack(void)
  183. {
  184.   struct stackframe *sf, *s2;
  185.  
  186.   sf = u.u_stk_spare;
  187.   u.u_stk_spare = NULL;
  188.   while (sf != NULL)
  189.   {
  190.     s2 = sf->next;
  191.     FreeMem(sf, (char *)sf->upper - (char *)sf);
  192.     sf = s2;
  193.   }
  194. }
  195.  
  196. void __stkovf(void)
  197. {
  198.   u.u_stk_limit = NULL; /* disable stackextend from now on */
  199.   for (;;)
  200.     kill(getpid(), SIGSEGV); /* Ciao */
  201. }
  202.  
  203. /*
  204.  * Signal routines may want to benefit from stackextension too -
  205.  * so make all the stack handling functions atomic.
  206.  * FIXME: This seems to have the potential to break a Forbid() ?!?
  207.  */
  208. void atomic_on(sigset_t old)
  209. {
  210.   sigset_t fill;
  211.   sigfillset(&fill);
  212.   sigprocmask(SIG_SETMASK, &fill, &old);
  213. }
  214.  
  215. void atomic_off(sigset_t old)
  216. {
  217.   sigprocmask(SIG_SETMASK, &old, NULL);
  218. }
  219.  
  220. /*
  221.  * Move a stackframe with a minimum of requiredstack bytes to the used list
  222.  * and fill the StackSwapStruct structure.
  223.  */
  224. static void pushframe(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old, int startup)
  225. {
  226.   struct stackframe *sf;
  227.   ULONG recommendedstack;
  228.  
  229.   if (!startup)
  230.   {
  231.     requiredstack += stk_safezone + u.u_stk_argbt;
  232.     if (requiredstack < stk_minframe)
  233.       requiredstack = stk_minframe;
  234.   }
  235.  
  236.   recommendedstack=u.u_stk_max-u.u_stk_current;
  237.   if (recommendedstack<requiredstack)
  238.     recommendedstack=requiredstack;
  239.  
  240.   for (;;)  
  241.   {
  242.     sf = u.u_stk_spare; /* get a stackframe from the spares list */
  243.     if (sf == NULL)
  244.     { /* stack overflown */
  245.       for (; recommendedstack>=requiredstack; recommendedstack/=2)
  246.       {
  247.     sf = AllocMem(recommendedstack + sizeof(struct stackframe), MEMF_PUBLIC);
  248.     if (sf != NULL)
  249.       break;
  250.       }
  251.       if (sf == NULL)
  252.       { /* and we have no way to extend it :-| */
  253.         sigprocmask(SIG_SETMASK, old, NULL);
  254.         __stkovf();
  255.       }
  256.       sf->upper = (char *)(sf + 1) + recommendedstack;
  257.       break;
  258.     }
  259.     u.u_stk_spare = sf->next;
  260.     if ((char *)sf->upper - (char *)(sf + 1) >= recommendedstack)
  261.       break;
  262.     FreeMem(sf, (char *)sf->upper - (char *)sf);
  263.   }
  264.  
  265.   /* Add stackframe to the used list */
  266.   sf->next = u.u_stk_used;
  267.   u.u_stk_used = sf;
  268.   *u.u_stk_limit = (char *)(sf + 1) + stk_safezone + u.u_stk_argbt;
  269.  
  270.   /* prepare StackSwapStruct */
  271.   sss->stk_Pointer = sf->upper;
  272.   sss->stk_Lower = sf + 1;
  273.   sss->stk_Upper = (ULONG)sf->upper;
  274.  
  275.   /* Update stack statistics. */
  276.   u.u_stk_current += (char *)sf->upper - (char *)(sf + 1);
  277.   if (u.u_stk_current > u.u_stk_max)
  278.     u.u_stk_max = u.u_stk_current;
  279. }
  280.  
  281. /*
  282.  * Allocate a new stackframe with d0 bytes minimum.
  283.  */
  284. int stkext(struct StackSwapStruct sss, sigset_t old,
  285.  long d0, long d1, long a0, long a1, long a6, long ret1)
  286. {
  287.   void *callsp = &ret1 + 1;
  288.   int cpsize = (char *)callsp - (char *)&old;
  289.  
  290.   if (callsp >= STK_UPPER || callsp < STK_LOWER)
  291.     return 0; /* User intentionally left area of stackextension */
  292.  
  293.   pushframe(d0, &sss, &old, 0);
  294.   *(char **)&sss.stk_Pointer -= cpsize;
  295.   CopyMem(&old, sss.stk_Pointer, cpsize);
  296.   return 1;
  297. }
  298.  
  299. /*
  300.  * Allocate a new stackframe with d0 bytes minimum, copy the callers arguments
  301.  * and set his returnaddress (offset d1 from the sp when called) to stk_rst_f
  302.  */
  303. int stkext_f(struct StackSwapStruct sss, sigset_t old,
  304.  long d0, long d1, long a0, long a1, long a6, long ret1)
  305. {
  306.   void *argtop, *callsp = &ret1 + 1;
  307.   int cpsize;
  308.  
  309.   if (callsp >= STK_UPPER || callsp < STK_LOWER)
  310.     return 0; /* User intentionally left area of stackextension */
  311.  
  312.   argtop = (char *)callsp + u.u_stk_argbt;    /* Top of area with arguments */
  313.   if (argtop > STK_UPPER)
  314.     argtop = STK_UPPER;
  315.   cpsize = (char *)argtop - (char *)&old;
  316.  
  317.   /* FIXME: is "+ u.u_stk_argbt" really necessary? It's added in pushframe(), too. */
  318.   pushframe(d0 + u.u_stk_argbt, &sss, &old, 0);
  319.   *(char **)&sss.stk_Pointer -= cpsize;
  320.   CopyMem(&old,sss.stk_Pointer, cpsize);
  321.   u.u_stk_used->savesp = (char *)callsp + d1; /* store sp */
  322.   *(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp) + d1)
  323.     = &__stkrst_f; /* set returnaddress */
  324.   return 1;
  325. }
  326.  
  327. static int get_stack_size(struct Process *proc, int stack)
  328. {
  329.   struct CommandLineInterface *CLI;
  330.  
  331.   if (stack < STACKSIZE)
  332.     stack = STACKSIZE;
  333.  
  334.   /* NOTE: This is the most appropriate place for future support of
  335.      user-specified, process-specific stacksizes. */
  336.  
  337.   CLI = BTOCPTR (proc->pr_CLI);
  338.  
  339.   if (stack <= (CLI ? CLI->cli_DefaultStack * 4 : proc->pr_StackSize))
  340.     return 0;
  341.   return stack;
  342. }
  343.  
  344. /*
  345.  * Called at startup to set stack to a safe/reasonable value (which is
  346.  * provided in d0). Check if there is a need for stack extension at startup,
  347.  * return 0 if it is not necessary. If it is, perform almost the same actions
  348.  * as stkext_f.
  349.  */
  350. int stkext_startup(struct StackSwapStruct sss, sigset_t old,
  351.  long d0, long d1, long a0, long a1, long a6, long ret1)
  352. {
  353.   void *argtop, *callsp = &ret1 + 1;
  354.   int cpsize, stack;
  355.  
  356.   if (!(stack=get_stack_size((struct Process*)FindTask(0), d0)))
  357.     return 0;
  358.  
  359.   argtop = (char *)callsp + u.u_stk_argbt;    /* Top of area with arguments */
  360.   if (argtop > STK_UPPER)
  361.     argtop = STK_UPPER;
  362.   cpsize = (char *)argtop - (char *)&old;
  363.  
  364.   pushframe(stack, &sss, &old, 1);
  365.   *(char **)&sss.stk_Pointer -= cpsize;
  366.   CopyMem(&old,sss.stk_Pointer, cpsize);
  367.   u.u_stk_used->savesp = (char *)callsp; /* store sp */
  368.   *(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp))
  369.     = &__stkrst_f; /* set returnaddress */
  370.   return 1;
  371. }
  372.  
  373. /*
  374.  * Move all used stackframes upto (and including) sf to the spares list
  375.  * and fill the StackSwapStruct structure.
  376.  */
  377. static void popframes(struct stackframe *sf, struct StackSwapStruct *sss)
  378. {
  379.   struct stackframe *sf2;
  380.  
  381.   if (sf->next != NULL)
  382.   {
  383.     sss->stk_Lower = sf->next + 1;
  384.     sss->stk_Upper = (ULONG)sf->next->upper;
  385.     *u.u_stk_limit = (char *)(sf->next + 1) + stk_safezone + u.u_stk_argbt;
  386.   }
  387.   else
  388.   {
  389.     sss->stk_Lower = u.u_tc_splower;
  390.     sss->stk_Upper = (ULONG)u.u_tc_spupper;
  391.     *u.u_stk_limit = (char *)u.u_org_lower + stk_safezone + u.u_stk_argbt;
  392.   }
  393.   sf2 = u.u_stk_spare;
  394.   u.u_stk_spare = u.u_stk_used;
  395.   u.u_stk_used = sf->next;
  396.   sf->next = sf2;
  397.  
  398.   /* Update stack statistics. */
  399.   for (sf2 = u.u_stk_spare; sf2 != sf->next; sf2 = sf2->next)
  400.     u.u_stk_current -= (char *)sf2->upper - (char *)(sf2 + 1);
  401. }
  402.  
  403. /*
  404.  * Set stackpointer back to some previous value
  405.  * != NULL: on the same stackframe (returns sp)
  406.  * == NULL: on another stackframe
  407.  */
  408. void *stkrst(struct StackSwapStruct sss, sigset_t old,
  409.  void *d0, long d1, long a0, long a1, long a6, long ret1)
  410. {
  411.   void *callsp = &ret1 + 1;
  412.   int cpsize = (char *)callsp - (char *)&old;
  413.   struct stackframe *sf1, *sf2;
  414.  
  415.   if (d0 >= STK_LOWER && d0 < STK_UPPER)
  416.     return d0;
  417.  
  418.   sf1 = u.u_stk_used;
  419.   if (sf1 == NULL)
  420.     return d0;
  421.   for (;;)
  422.   {
  423.     sf2 = sf1->next;
  424.     if (sf2 == NULL)
  425.     {
  426.       if (d0 < u.u_org_lower || d0 >= u.u_org_upper)
  427.         return d0;
  428.       break;
  429.     }
  430.     if (d0 >= (void *)(sf2 + 1) && d0 < sf2->upper) /* This stackframe fits */
  431.       break;
  432.     sf1 = sf2;
  433.   }
  434.   popframes(sf1, &sss);
  435.   sss.stk_Pointer = (char *)d0 - cpsize;
  436.   CopyMem(&old, sss.stk_Pointer,cpsize);
  437.   return NULL;
  438. }
  439.  
  440. /*
  441.  * return to last stackframe
  442.  */
  443. void stkrst_f(struct StackSwapStruct sss, sigset_t old,
  444.  long d0, long d1, long a0, long a1, long a6)
  445. {
  446.   void *callsp = &a6 + 1; /* This one has no returnaddress - it's a fallback for rts */
  447.   int cpsize = (char *)callsp - (char *)&old;
  448.  
  449.   sss.stk_Pointer = (char *)u.u_stk_used->savesp - cpsize;
  450.   popframes(u.u_stk_used, &sss);
  451.   CopyMem(&old, sss.stk_Pointer, cpsize);
  452. }
  453.