Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!uunet!munnari!vuwcomp!cantuar!james
From: james@cantuar.UUCP (J. Collier)
Newsgroups: comp.sys.mac
Subject: Re: turning off the stack sniffer (long)
Message-ID: <135@cantuar.UUCP>
Date: Thu, 2-Jul-87 02:49:26 EDT
Article-I.D.: cantuar.135
Posted: Thu Jul  2 02:49:26 1987
Date-Received: Tue, 7-Jul-87 06:28:46 EDT
References: <1289@briar.Philips.Com>
Reply-To: james@cantuar.UUCP (J. Collier)
Organization: University of Canterbury, Christchurch, New Zealand
Lines: 90
Keywords: stack 60 Hz multitasking HeapEnd trap dispatcher dirty illegal
Summary: There's another way, but problems aplenty

Paul Rutter (per@philabs.Philips.Com) writes:
>When playing with "multi-tasking", it is useful to be able to move the stack
>pointer to one of several stack areas.  The "stack sniffer" routine checks
>whether the stack overlaps the heap during every tick, and bombs if it does.
>
>How do I disable the stack sniffer? 

Steve Munson (sbm@purdue.edu) suggested an alternative solution to this 
problem some weeks ago. I used a similar method in an experiment earlier this
year - and found it effective to the extent that I tested it (not much). Hope
I'm not deluding myself in thinking other people might be interested...

    NB - the suggestions which follow are most unlikely to work on anything
newer than a 128k ROM, if at all. APPLE THOUGHT POLICE PLEASE HIT 'j' NOW...:-)

    Unfortunately, the 60Hz stack sniffer is not the only ROM routine which
checks the stack. Disabling the stack sniffer (by setting StkLowPt to 0, if I 
remember correctly) also has some messy side-effects.  Besides which, it's
quite nice to have the sniffer look after the behaviour of ones own
heap-resident stacks. 
    The sniffing routines work by comparing the value of the stack pointer to
the global HeapEnd. Somewhat surprisingly, changing the value of this global
to the new stack limit at each context switch appears to achieve the desired
effect. 
    Of course, various other ROM routines will be using HeapEnd. However, after
several cross-eyed hours searching a 128k ROM, I found only the following
references to HeapEnd:

                4008fc  :       Stack Sniffer          (read)
                409172  :       GetFInfo - stack check (read)
                40c218  :       MapRgn   - stack check (read)
                40fed6  :       SetApplBase            (set)
                4100b4  :       SetApplLimit           (set)
                4108xx  :       MoreMasters            (read & set)
                4135a6  :       InitResources (can't remember, but who cares?)

    So it seems that HeapEnd is normally used only to mark the limit of the
stack area. SetApplBase, SetApplLimit and InitResources shouldn't be called
after the application is under way. MoreMasters is trickier; I just allocated
a large block of masters during initialisation and hoped for the best, but 
you will probably want to patch the trap.

    BTW, how are you initiating context switches? Doing it on the 60Hz interrupt
I came across several problems:
   1. I found I had to patch the interrupt vector and do the switch *after* the
normal VBL tasks.
   2. I had to disable switching during ROM routines (non-reentrant code :-().
This involved (don't barf) hooking the trap dispatcher. Tricky. Scott Knaster
mentions (in "How to Write Macintosh Software") a particularly revolting system
patch which relies on the value of the return address being from a certain ROM
routine. The dispatcher therefore has to replace the stack frame if the routine
was called from user code, but not if called from another ROM routine. 
   Oh, what the ***, the bored will have stopped reading by now, so here goes..
It breaks every rule in the book: self modification, RTE, etc. etc. Do you
want to run this on a 68020? %-Q
-----------------------------------------------------------------------
             /* set A-trap vector to "mytrdsp" */
#define CANTXFER    APPLSCRATCH     /*  inhibit context switch if set */
#define XFERPEND    APPLSCRATCH+1   /*  c-s blocked during ROM call? */
                                    /*  (refer VBLtrap.c) */
#define SAVERA      APPLSCRATCH+2   /*  save return address here */

                                    /*   <4EA> <2SR> <-SP */
mytrdsp:    tst.b   CANTXFER        /*  set if called from ROM */
            bne.s   jtdisp          /*  if set, we can't mess with the stack */    
            addq.b  #1, CANTXFER    /*  disable hook in ROM-ROM calls */
            movem.l A0/A1, -(A7)    /*   <4EA> <2SR> <8SV>*/
            movea.l 10(A7), A0      /*  EA -> A0 */
            lea     trpcpy, A1      /*  &(word after jmp) -> A1 */
            move.w  (A0), (A1)      /*  Axxx -> (word after jmp) */
            addq.l  #2, A0          /*  skip trap word on rte */ 
            move.l  A0, SAVERA      /*  RA -> global */
            move.l  A1, 10(A7)      /*  <4MYEA><2SR><8SV> */
            movem.l  (A7)+, A0/A1   /*  <4MYEA><2SR> */
jtdisp:     jmp      /*  initialise on load */
trpcpy:     dc.w    0xA000          /*  dummy trap copied from code */
            move.l  SAVERA, -(A7)   /*  restore saved return address */
            move.l  SR, -(A7)       /*  push SR - cc's not needed */
                                    /*  assert : CANTXFER == 1 */
            clr.b   CANTXFER        /*  returning to user code - clear flag */
            tst.b   XFERPEND        /*  set if process xfer was blocked */
            beq.s   immrtn          /*  if not, return now */
            jsr      /*  context switching routine */
immrtn:     rte                     /*  return & restore saved SR */
------------------------------------------------------------------------------
Grubbiness rules, OK? Have fun.
-------------------------
James Collier  (james@cantuar.uucp / {watmath,munnari,mcvax}!cantuar!james
Computer Science Dept., University of Canterbury, Christchurch, New Zealand.
My supervisor doesn't know that I'm doing this.