dvlmfs@afrodite.cs.umu.se (Michael Forselius) (10/30/90)
[I have read your articles Marc, Tom]
I suppose that most of you people haven't read my previous
article ("Re: More Mac Wierdness (Memory Mangler..") were
I gave you a brief description on how about calling traps
during an autovectored interrupt, IPL0-IPL2, this could be
a VBL task or something like that. Then I told you to tell
me if you could find anything wrong with my assumptions. Now
I have made a simple program that uses this technique and it
looks like it's working, the program follow my ravings...
For those of you that haven't read the first article here's
the theory:
... First of all we need to allocate a block of memory that
will be resident. We would call InitZone(growZoneProc, ...)
to make this memory block a heap zone.
When we are called during some autovectored interrupt we
would save the current zone, set the current zone to the one
we've made. After this we should (theoretically) be able to
call any trap even if they could cause the heap to be purged
scrambled or compacted due to fact that the memory mangler
MUST work WITHIN the current heap zone. This is a truth with
some modification since you could call NewPtrSys but that's
no problem since YOU are supposed to know what you're doing.
When we are done we simply restore the current zone and the
next interrupt handler (if any) can continue?
That's the theory, now what about the real world? What kind
of problems could one expect if this were to be used?
Well, you have this about reentrancy and partially completed
operations on the application heap as Peter Lewis at Curtin
University in Australia pointed out. Since yesterday I have
been looking through my ROM listings and have found that it
looks like Apple for once doesn't use any scratch areas, or
break too many rules so it SHOULD be pretty safe to do this,
i.e. the trap routines seems to handle reentrancy well - as
far as I have seen... Although the 5 ton elephant called
Apple often changes it's direction (S. Jasik quoted).
Also, this will break if you can't run it when the Mac is in
supervisor mode (can I be thinking of TRUE multitasking ???)
but that's no problem since all but MPW and just about copy
protected program then will break as well. This is the price
you'll have to pay when you don't have the guts to do a
complete rewrite of the system.
Tell me what you think of all this, no flames or stupid
answers, only constructive criticism will be considered.
I liked your answers Marc, Tom. I said that you had to know
what you were doing, this provides some help to "go beyond
the limit".
Hey Waldemar, I want TMON Professional !!!
I'm also looking for a nice well-paid job - anyone...
END /* Ravings */
This is how the system heap could be arranged after
execution.
+--System Heap Zone-+
| |
| |
| |
| |
+--Our Heap Zone----+ <-- Heap Zone header (52 bytes)
|*******************| <-- Interrupt handler (xxx bytes)
| | <-- Free (xxx bytes)
| |
+-End Our Heap Zone-+
+--System Heap Zone-+
| |
| |
.....................
+-End Sys.Heap Zone-+
Here comes the program, written in assembler - no language
gives this much control. (Don't comment this PLEASE)
---------------------------------------------------
#define ZONESIZE 4096L
#define heapData OFFSET(Zone,heapData)
void Twiddle(void);
void
main(void)
{
asm {
;
;
;Create our heap zone
;
;
;
;save some registers:
; D3 - size of interrupt code
; D4 - start address in our heap zone to interrupt code
; D5 - start address of our heap zone
;
MOVEM.L D3-D5,-(SP) ;save a couple of working registers
;
;try to get some space in the system heap for our zone
;remember that this can also be done at startup by moving BufPtr downwards
;
MOVE.L #ZONESIZE,D0 ;alloc this many bytes for our zone
_NewPtr SYS ;in system heap
MOVE.L A0,D5 ;save for later use
BEQ @xit ;if not enough heap space -> quit
;
;create our heap zone, we're allocating the parameter block on stack
;InitZone(growZoneProc, numMasters, limit, start) /
; A0-block(start,limit,numMasters,growZoneProc)
;
MOVE.L TheZone,-(SP) ;save current zone
SUBI.L #14,SP ;parameter block for _InitZone
MOVE.L A0,(SP) ;start of our zone
LEA ZONESIZE(A0),A1 ;end of our zone
MOVE.L A1,4(SP) ;- // -
MOVE.W #16,8(SP) ;alloc 16 master every time
CLR.L 10(SP) ;no growZoneProc
MOVE.L SP,A0 ;ptr to start of block
_InitZone ;create zone
ADDI.L #14,SP ;return stack space, pop args
MOVE.L (SP)+,TheZone ;must do this since _InitZone
;has set the current zone to the one
;just created
;
;
;Install IPL0 routine
;
;
;
;save original address to autovector 0
;also initialize our variables
;
LEA @next,A0 ;start of variable storage
MOVE.L 0x0064,(A0)+ ;save current IPL0 routine
MOVE.L D5,(A0) ;our THz, ptr to start of system block
;
;calculate size of our patch/interrupt code and get ptr
;to first usable byte in our heap zone, we're moving the
;interrupt code to the beginning of our heap zone - convienent isn't it?
;
LEA @CSTART,A0 ;must do this since TC is a
LEA @CEND,A1 ;simple one-pass assembler
SUBA.L A0,A1 ;calculate size of patch code
MOVE.L A1,D3 ;save size
MOVEA.L D5,A0 ;ptr to start of our sysheap block
LEA heapData(A0),A0 ;first usable byte in zone,past header
MOVE.L A0,D4 ;save this address
;
;move our interrupt handler into system heap (our heap zone),
;it doesn't have to be there but this probably will be in an INIT/cdev ...
;
LEA @CSTART,A1 ;start of interrupt routine
EXG.L A0,A1 ;EXchanGe register contents
MOVE.L D3,D0 ;size of interrupt code
_BlockMove ;move code into position
;
;remember to disable interrupts while we "connect" our simple patch
;
ORI.W #0x0300,SR ;disable IPL0-IPL1 interrupts
MOVE.L D4,0x0064 ;install our interrupt handler
MOVE.W #0x2000,SR ;enable ALL interrupts
;
;do something, test of our code
;if this were to be a "real" program we could have been finished here with
;patching and installing but this is a skeleton prog so we continue
;and "twiddles" a while before we remove the patch/interrupt handlers
;
JSR Twiddle
;
;restore the original interrupt handler, "disconnect" our code
;
ORI.W #0x0300,SR ;disable IPL0-IPL1 interrupts
MOVE.L @next,0x0064 ;connect original interrupt handler
MOVE.W #0x2000,SR ;enable ALL interrupts
@noSpace
;
;free the memory held in system zone by our heap zone
;
MOVEA.L D5,A0
_DisposPtr
@xit
MOVEM.L (SP)+,D3-D5 ;restore working registers
return
CSTART:
MOVE.W SR,-(SP) ;save status register
ORI.W #0x0300,SR ;disable IPL0-IPL1 interrupts
MOVE.L TheZone,-(SP) ;save current heap zone
MOVEM.L D0-D2/A0-A1,-(SP) ;save these since we're thrashing them
MOVE.L ScrnBase,A0 ;flip topleft bit of screen
EOR.B #0xC0,(A0) ;will this work on color Macs !?!
MOVE.L @ourZone,TheZone ;install our zone
MOVE.L #maxSize,D0 ;let's cause some relocation!
_NewPtr
MOVE.L #maxSize,D0
_NewHandle
MOVE.L #maxSize,D0
_PurgeMem
MOVE.L #maxSize,D0
_CompactMem
MOVEM.L (SP)+,D0-D2/A0-A1 ;restore registers
MOVE.L (SP)+,TheZone ;restore original heap zone
MOVE.W (SP)+,SR ;restore status register
MOVE.L @next,-(SP) ;next IPL0 routine, autovector 0
RTS ;"chain" routine
@next
DC.L 0 ;address to next interrupt handler
@ourZone
DC.L 0 ;our heap zone ptr
CEND:
}
}
void
Twiddle(void)
{
EventRecord theEvent;
InitGraf(&thePort);
InitFonts();
InitWindows();
FlushEvents(everyEvent, 0);
while (!GetNextEvent(keyDownMask, &theEvent));
}
+---------------------------------------------------------+
| Michael Forselius Internet: dvlmfs@cs.umu.se |
|---------------------------------------------------------|
| Ever heard of 'Pirate Purgatory' !?! - tough one though |
+---------------------------------------------------------+