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 | +---------------------------------------------------------+