supermario/base/SuperMarioProj.1994-02-09/Toolbox/SegmentLoader/SegmentLoader.a
2019-06-29 23:17:50 +08:00

928 lines
38 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: SegmentLoader.a
;
; Contains: Segment Loader for Macintosh Operating System
;
; Written by: Andy Hertzfeld 09-May-83
;
; Copyright: © 1983-1992 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM10> 11/12/92 PN Get rid of ≥ 020 conditionals for ROM builds
; <SM9> 11/3/92 SWC Changed PaletteEqu.a->Palettes.a.
; <SM8> 10/22/92 CSS Change some branch short instructions to word branches.
; <SM7> 6/26/92 kc ReRoll in Terror SegLoad Patch. From Terror OverPatch.a:
; <T13> 7/10/91 RP Removed MPW SegLoad fix. Fix was made in FlushCacheRange.
; <T10> 6/26/91 RP Patched LoadSeg & UnloadSeg to use FlushCacheRange.
; <SM6> 5/16/92 kc Remove onHcMac code and conditional.
; <SM5> 4/14/92 stb change process mgr CODE segment fetches to 'scod'
; <4> 3/27/92 JSM Moved this file to SegmentLoader folder, keeping all the old
; revisions, to reflect current Reality structure.
; <3> 3/9/92 PN Adding machine MC68020 directive
; <2> 3/6/92 RB Flush Cache range inside LoadSeg and UnloadSeg instead of just
; invalidating the caches.
; <7> 9/27/91 JSM Cleanup header, dont use hasCQD conditional since all future
; ROMs will have color QuickDraw.
; <6> 6/12/91 LN removed #include 'HardwareEqu.a'
; <5> 3/12/91 CCH Removed the cache flush at the beginning of LoadSeg, since we
; flush it at the end. Also moved cache flush in UnLoadSeg to the
; end of the routine.
; <4> 8/27/90 CCH Modified <3> to make sure it only gets done on 040s. Also
; removed the -eclipseDebug- conditional since it will always
; apply to 040s.
; <3> 6/22/90 CCH Added cache push for 68040 machines after jump table is created
; to avoid cache incoherency problems.
; <2> 1/12/90 CCH Added include of “HardwarePrivateEqu.a”.
; <1.7> 7/12/89 GGD Added conditional hasCQD around call to PMgrExit, to fix non-CQD
; machines.
; <1.6> 7/8/89 BAL <dvb> Added PMgrExit call to ExitToShell.
; 7/8/89 dvb Added call to PMgrExit in ExitToShell.
; <1.5> 4/11/89 GGD Changed FPUin to the proper equate hwCbFPU to clean up
; HardwareEqu.a, deleted usage of nequ.d.
; <1.4> 3/20/89 MSH Fixed a conditional.
; <1.3> 2/20/89 rwh changed to feature-based conditionals.
; <1.2> 1/30/89 GGD Added unconditional call to CacheFlush in _LoadSeg/_UnloadSeg,
; to allow better support for 68020/030s in the 68000 ROMs.
; <1.1> 11/10/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <•1.1> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles
; <1.0> 2/10/88 BBM Adding file for the first time into EASE…
; <C914> 10/29/87 rwh Port to Modern Victorian (onMvMac)
; <C800> 2/12/87 JTC Clear (a5) on launch in case someone (like old MacWrites) goes
; snooping for QD globals before InitGraf time. Also, adjust C741
; alignment to just AFTER the “above A5” amount has been taken
; from SP.
; <C749> 2/3/87 bbm changed the way the 68881 is inited on launch.
; <C741> 2/2/87 JTC Try to longword align the A5 world.
; <C707> 1/27/87 RDC Removed check for debugger installed in Launch code
; <C681> 1/24/87 JTC Moved init stuff in Launch to InitApplZone, where it may
; actually belong. Made last-minute app start-up code subject to
; new vector jLaunchInit.
; <C668> 1/22/87 bbm added a vector to flush the cache in LoadSeg and UnLoadSeg. For
; overkill, and because the vCacheFlush trashes D1, we preserve D1
; across call.
; <C548> 12/19/86 bbm kill all outstanding sounds on Launch
; <C490> 12/8/86 EMT Launch & Chain now put ROMBase+64K in address 0 if debugger is
; not installed
; <C482> 12/4/86 bbm The code to flush the cache in loadseg and unloadseg needed to
; be set in conditionals for onNuMac.
; <C456> 11/22/86 bbm moved the code to flush the cache into blockmove, loadseg,
; unloadseg, and read. this might improve performance.
; <A284> 10/28/86 LAK Copy launch parameters before resetting the stack (could have
; been passed on stack). Set CurMap to CurApRefNum when loading a
; code resource (but preserve setting of both Resload and Curmap).
; Use StripAddress trap for FlushApplVbls, InstallRDrivers via new
; routine ApZoneAddr which is also more selective about what's in
; the application world (specifically excludes above BufPtr). Use
; launch trap at ExitToShell so we have a hook there.
; <C206> 10/9/86 bbm Modified to mpw aincludes.
; <C192> 10/1/86 JDT Added call to script manager during launch.
; <C169> 9/23/86 JTC Use HLock/HUnlock rather than bset/bclr and use HGetState to
; check lockedness.
; <C141> 9/4/86 RDC Added code to init FPU chip for NuMac
; <C54> 6/24/86 WRL Changed access to ROMBase to make it survive a 32 bit value.
; 2/19/86 BBM Made some modifications to work under MPW
; 1/13/86 JTC Patch for InstallRDrivers to correctly kill DCtlStorage of
; drivers with storage in the app heap.
; 11/2/85 JTC Check global SegHiEnable before MoveHHi in LoadSeg.
; 10/28/85 JTC Changed Launch and Chain to check for extended param block,
; calling OpenRFPerm with desired permissions. Also added vector
; for vSegStack.
; 9/10/85 BBM fix bug - if ExitToShell with ResLoad false, then LoadCode
; wouldn't load the code.
; 8/18/85 LAK Removed call to MakeStkPB and placed that code in-line (moved
; this file to TBLink so had to remove the .Ref). A file system
; call should be added to flush all volumes soon.
; 7/26/85 RDC Added include statement for HWequ file (needed for DiagROM
; reference)
; 7/8/85 LAK Zero D0-D7 and init A0-A2 to DiagROM addr at launch; fixed bug
; in InstallRDrivers to preserve DCtlStorage handle if it's in the
; system heap.
; 5/23/85 JTC Do a MoveHHi on all segments that come in unlocked.
; 5/22/85 LAK Set location 0 to DiagROM at launch (in case Finder doesn't FOBJ
; it).
; 5/21/85 JTC Fix bug in check for "already loaded" seg in LoadSeg.
; 3/27/85 JTC Add loop in Launch to remove appl zone vbl tasks from loop
; before trashing appl zone.
; 1/30/85 LAK Added ram patch after ExitToShell to LodeScrap and prefix to
; BootDrive. Moved ExitToShell label (before ram patch).
; CloseResFile skipped here to avoid bug in driver goodbye kiss
; (where driver came from app file), esp. since it appears to be
; called in Launch anyways.
; 1/29/85 EHB Made Launch and Chain give goodbye calls to drivers that want
; 'em
; 1/29/85 EHB Fix odd stack bug in Launch/Chain
; 9/10/83 AJH Fixed bug -- it wasn't releasing segment 0!
; 9/6/83 AJH BadOpen now deep shits
; 8/19/83 LAK Now inits StkLowPt.
; 8/18/83 SC Changed theScrap to scrapHandle and changed BEQ to BLE
; 8/16/83 AJH Compute screen sound address relative to memTop (instead of
; ScreenBase)
; 8/13/83 SC Dropped flushevents
; 8/12/83 AJH moved globals to SysEqu; use deepShit alert in SysErr made
; ExitToShell use a low memory pBlock save parameters in lomem
; earlier
; 8/11/83 AJH made it preserve scrap by moving it to stack
; 8/10/83 AJH moved LoadTrap to LoadSeg; loader calls SetApplLimit
; 8/9/83 SC Fixed bug in scrap stuff(D0 lost through NewHandle)
; 8/8/83 AJH removed compact before locking (now rMgr does it!)
; 8/6/83 BLH Added initialization of DragHook, DeskHook, CloseOrnHook,
; restProc, saveProc, saveSP, taskLock, fScaleDisable, resErrHook
; right after InitApplZone. These all used to be in InitWindows
; (except fScaleDisable).
; 6/17/83 AJH fixed bug (no InitApplZone) introduced yesterday
; 6/16/83 AJH made it compact before locking code segments
; 6/16/83 AJH made it InitApplZone early so it only opens once
; 6/11/83 AJH cleaned up BadOpen error exit stuff
; 6/8/83 AJH increased size of appName; made it use AppParmHandle
; 6/4/83 AJH made Launch clear D7 & 20(A5) for stupid Lisa Pascal
; 6/2/83 AJH fixed bug in ExitToShell to push page 2 word
; 6/1/83 AJH preserved theScrap; added page two options
; 5/29/83 AJH Changed jumptable from 10 bytes/entry to 8 bytes/entry
; 1/23/83 LAK Adapted for new equate files.
;
;---------------------------------------------------
;
; Really old comments which probably make no sense:
;
; Here is the new resource-based segment loader. It
; is capable of loading multiple Lisa-style code segments
; using a jump table scheme similar to the Lisa "physical
; executable" format.
;
; The loader is also the part of the system that cuts back
; the application heap and builds an "A5 world" for the
; application.
;
; The loader will preserve the handle in low memory called
; "theScrap" across world swaps.
;
;
; To Do:
; - Move FlushApplVBLs, RDrvrInit, etc. to some more sensible place.
; - why is lodescrap called at exittoshell?
; - recover earlier on launches if file is bad . . .
; - remove hardwired constant for 2nd screen delta to memtop.?? for Reno?? <A284>
;
; Problems with incorporating 'Q' init here:
; - hardwired name 'miniFinder'
; - 'Q' code still in flux (should set up launch flags, Finder should reset the
; sublaunch stack since it deallocates WDCBs. We should really use DirIDs and
; VRefNums in 'Q', as well as allocate a WDCB if needed).
; - need this for MacPlus and Mac512 also; why not keep all the code in the
; same place?
;_______________________________________________________________________
BLANKS ON
STRING ASIS
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'Palettes.a'
machine mc68020
Loader PROC EXPORT
EXPORT Launch,Chain,ExitToShell
EXPORT InstallRDrivers
EXPORT LoadSeg,UnloadSeg
EXPORT GetAppParms
EXPORT vSegStack ; <28Oct85>
EXPORT SgLdrEnd
EXPORT vLaunchInit ; to be used by InitApplZone <C681>
EXPORT FlushApplVBLs ; to be used by InitApplZone <C681>
EXPORT AppZoneAddr ; to be used by InitApplZone <C699>
; IMPORT LaunchScript ; during switch-launch (C192)
IMPORT FlushCRange ; <SM2> rb
; segment header definitions
SegJTOffset EQU 0 ; offset of 1st jumpTable entry
SegJTEntries EQU 2 ; number of jumpTable entries
SegHdrSize EQU 4 ; the header is four bytes long
; misc definitions
SegLoadTrap EQU $A9F0 ; LoadSeg trap ID
;------------------------------------------------------------------------------
;
; PROCEDURE LoadSeg(segID: INTEGER);
;
; LoadSeg is used to load a segment and patch all the jump table entries for
; that segment. It is usually called from the jump table entry and almost
; never called directly by the application. It then transfers control
; to the newly loaded code.
;
; All registers are preserved until the newly loaded code is launched.
; If the segment can't be found, a deep shit alert is posted.
;
;------------------------------------------------------------------------------
LoadSeg
MOVEM.L D0-D2/A0-A1,-(SP) ;all registers must be preserved
MOVE.W 24(SP),D0 ; get the segment ID
BSR LoadCode ; A0=D0=segment handle <SM8> CSS
BEQ SegError ; if none, give up <SM8> CSS
_HGetState ; D0 <- master ptr state bits <C169>
BTST #Lock,D0 ; NE => locked <C169>
BNE.S NoMoveHHi ; NotEqual => don't move it <23May85>
TST.B SegHiEnable ; = 0 to disable use of (dubious) MoveHHi <02Nov85> JTC
BEQ.S @37 ; <02Nov85> JTC
_MoveHHi ;Move it to highest possible point <23May85>
@37 ;Aren't we slick and tight? <02Nov85> JTC
_HLock ; <23May85><C169>
NoMoveHHi
MOVE.L (A0),D0 ; handle -> dirty pointer <C169>
_StripAddress ; D0 <- clean ptr <C169>
MOVE.L D0,A0 ; <C169>
MOVE.L A5,A1 ;copy world base address
ADD.W CurJTOffset,A1 ;offset by the current offset
ADD.W SegJTOffset(A0),A1 ;compute address of 1st entry
CMP.W #$4EF9,2(A1) ;is it already loaded? (was 4(A1)) <21May85>
BEQ.S GoLaunch ;if so, don't bother to load
; we must patch the jump table to point to the newly loaded segment. At this
; point A1 points to the first jump table entry.
MOVE.W SegJTEntries(A0),D0 ;get the number of entries
BEQ.S GoLaunch ;if none, just go launch it
MOVE.W 24(SP),D1 ;get the segment ID
MOVEQ #0,D2 ;clear out high part of D2
; LoadSegPatch from Terror overpatch.a
Move.l A2,-(Sp) ; Save A2.
Move.l A1,A2 ; Save starting address.
PatchJTLoop
MOVE.W (A1)+,D2 ;pick up the offset
MOVE.W D1,-2(A1) ;remember the segment ID in entry
MOVE.W #$4EF9,(A1)+ ;patch in the "JMP.L" opcode
PEA SegHdrSize(A0,D2.L) ;compute the entry point address
MOVE.L (SP)+,(A1)+ ;move in the entry point address
SUBQ #1,D0 ;more entries to do?
BNE.S PatchJTLoop ;loop till done
Suba.l A2,A1 ; Length of changes.
Move.l A2,A0 ; Starting address. <T13>
BSR.l FlushCRange ; Flush the Caches. <T10>
Move.l (Sp)+,A2 ; Restore A2.
; now we can transfer control to the newly loaded code at the proper entry point
GoLaunch
MOVE.L 20(SP),A1 ;get the return address from the trap
SUBQ.L #6,A1 ;back up to the JMP.L opcode
MOVE.L A1,22(SP) ;patch the return address
MOVEM.L (SP)+,D0-D2/A0-A1 ;restore the registers
ADDQ #2,SP ;strip parameter
TST.B LoadTrap ;debugging on?
BEQ.S @1 ;go launch if its not
DC.W $A9FF ;invoke debugger
@1
RTS ;launch the code!
; here is the error handler for when we couldnt load a segment we need. Its
; a deep shit alert.
SegError
MOVEQ #DSLoadErr,D0 ;get deep shit ID
_SysError ;invoke deep shit - dont come back
DC.W $A9FF ;trap to debugger, just in case
; LoadCode is a code saving utility that loads the segment with the resource ID
; specified in D0. It returns the segment handle in A0
LoadCode
ST ResLoad ; force a load of code segment <10sep85> BBM
SUBQ #4,SP ; make room for function result
; <sm 5>stb Imported for SuperMario from SegmentLoaderPatches 3/30/92
; Force system code to load as 'scod' resources. The Process Mgr. is our distinguished first guest
; of this mechanism. If the id is in the reserved range [$BFFF,$BF00] it loads a scod instead
; of a CODE.
cmp.w #$BFFF,D0 ; Is it in the BFFF - BF00 range reserved for sys code?
bgt.s @normalCODE
cmp.w #$BF00,D0 ; is it really in the BFFF - BF00 range?
blt.s @normalCODE
move.l #'scod',-(SP) ; load a system-code (scod) resource
bra.s @systemCode
@normalCODE
MOVE.L #'CODE',-(SP) ; load a regular CODE resource
@systemCode
MOVE.W D0,-(SP) ; push the segment ID
_GetResource ; load it
MOVE.L (SP)+,A0 ; get result in A0
MOVE.L A0,D0 ; better set Z-flag based on result
RTS ; return to caller
;------------------------------------------------------------------------------
;
; PROCEDURE UnloadSeg(routineAddr: Ptr);
;
; UnLoadSeg is used to unload a segment when the application feels its no
; longer needed for a while. It patches all of the segment's jump table
; entries back to the "load me" state. The parameter is the address of any
; routine within the segment.
;
;------------------------------------------------------------------------------
UnloadSeg MOVE.L 4(SP),A0 ;get the address of the routine
CMP.W #$4EF9,(A0) ;is it already unloaded?
BNE.S DoneUnload ;if so, we're done
; the first thing we must do is figure out the handle of the segment
MOVE.W -2(A0),D0 ;get the segment ID
BSR.S LoadCode ;get the segment handle
_HUnlock ;let it roam
MOVE.L (A0),A0 ;handle -> pointer
MOVE.L A5,A1 ;copy world base address
ADD.W CurJTOffset,A1 ;offset by current offset
ADD.W SegJTOffset(A0),A1 ;compute address of 1st entry
MOVE.W SegJTEntries(A0),D0 ;get the number of entries
BEQ.S DoneUnload ;if zero, we're all done
; loop through each jump table entry, patching it back to the "load me" state
Movem.l D1/A2,-(Sp) ; Save registers. <T10>
Move.l A1,A2 ; Save starting address. <T10>
UnpatchLoop
MOVE.W (A1),D1 ;remember the segment ID
MOVE.L 4(A1),D2 ;get the current address
SUB.L A0,D2 ;subtract the segment base address
SUBQ.L #SegHdrSize,D2 ;subtract the header size
MOVE.W D2,(A1)+ ;move in the offset
MOVE.W #$3F3C,(A1)+ ;move in the "push immediate" opcode
MOVE.W D1,(A1)+ ;move in the segment ID
MOVE.W #SegLoadTrap,(A1)+ ;move in the "SegLoad" trap
SUBQ #1,D0 ;more to do?
BNE.S UnpatchLoop ;loop until done
; we're all done with unloading the segment so strip the parameter and
; return to the caller
Suba.l A2,A1 ; Length of changes. <T10>
Move.l A2,A0 ; Starting address. <T10>
BSR.l FlushCRange ; Flush the Caches. <T10>
Movem.L (Sp)+,D1/A2 ; Restore registers <T10>
DoneUnload
MOVE.L (SP)+,(SP) ;strip the parameter
RTS ;return to caller
;------------------------------------------------------------------------------
; PROCEDURE AppZoneAddr <A284>
;
; Purpose: Strips any garbage off D0 address and sets D0=0 if in app zone.
; Aguments: D0 is the unstripped address on input, stripped or zeroed on output.
; CCR is set according to D0 value.
; Special case -- always say “dont nuke” when SysZone==ApplZone. <C699>
; Registers: D0.
; Called by: FlushApplVbls, InstallRDrivers.
;------------------------------------------------------------------------------
AppZoneAddr
_StripAddress ;<A284> D0 <- clean ptr
MOVE.L ApplZone,-(SP) ;get two zone ptrs where we can compare them <C699>
MOVE.L SysZone,-(SP) ;two zones poised for compare <C699>
CMP.L (SP)+,(SP)+ ;if appl==sys get out with D0!=0 <C699>
BEQ.S @notInApplZone ;dont nuke sys zone stuff at start time <C699>
CMP.L ApplZone,D0 ;<A284> Carry is set if below ApplZone, i.e. SysZone
BCS.S @notInApplZone ;<A284> in system zone, so leave D1 <C699>
CMP.L BufPtr,D0 ;<A284> Carry is clear if above the application space
BCC.S @notInApplZone ;<A284> (some other system zone? or BufPtr permanent <C699>
;<A284> allocation).
MOVEQ #0,D0 ;<A284> otherwise, return 0.
RTS
@notInApplZone
MOVEQ #-1,D0 ;really nonzero <C699>
RTS ;exit with CCR set <C699>
;------------------------------------------------------------------------------
; PROCEDURE FlushApplVbls
;
; Purpose: Remove from VBL queue any tasks based in applzone.
; Aguments: None.
; Registers: D0,A0-A1
; Called by: InitApplZone <C681>
;------------------------------------------------------------------------------
FlushApplVbls
MOVEA.L VBLQueue+qHead,A1 ; point to queue header <27Mar85>
fAVLoop ; <27Mar85>
MOVE.L A1,D0 ; is there a next element? <27Mar85>
BEQ.S fAVDone ; if not, just quit <27Mar85>
MOVEA.L A1,A0 ; line up element pointer for possible remove <27Mar85>
MOVEA.L vbLink(A0),A1 ; get next element for looping <27Mar85>
MOVE.L vblAddr(A0),D0 ; task pointer <27Mar85>
BSR.S AppZoneAddr ;<A284> in application area (or zero)?
BNE.S fAVLoop ;<A284> br if not
_VRemove ; <27Mar85>
BRA.S fAVLoop ; <27Mar85>
fAVDone ; <27Mar85>
RTS ; <27Mar85>
;------------------------------------------------------------------------------
;
; PROCEDUREs Launch, Chain, ExitToShell:
;
; Here is the main part of the segment loader that actually launches
; an application. It opens the resource file specified by the input name,
; loads segment 0 to get the jumptable and global size information, optionally
; cuts back the application heap and kicks off the application by invoking
; its first jump table entry.
;
; Warning -- LAUNCH obliterates the application heap so if an error occurs
; (like the file isn't executable) the code that called us is no longer
; "in the zone". Callers of LAUNCH should be very careful...(they probably
; should use a deep shit alert to put up a message and then re-launch themselves)
;
; New format parameter block to Launch and Chain has form:
; (a0) = (long) file name ptr
; (word) sounc and screen page option flag
; (word) 'LC' -- Charles Dodgeson's initials mark extended block
; (long) length of param block extension in bytes, past this long
; (word) finder file flags, bit #6 of low byte is 1 for read-only access
;
;------------------------------------------------------------------------------
; This part of the code is here so it can be accessible by short branches.
; Compute the address of sound page 2 and go modify the stackBase if
; neccessary.
SoundPage2
MOVE.L MemTop,D0 ;get address of top of RAM
SUB.L #$00005F00,D0 ;compute address of sound page 2
BRA SetNewStack ;modify stackBase if necessary
; First we have some an alternate entry point "Chain" which is just like
; launch except it doesn't cut back the heap.
Chain
CLR.W LaunchFlag ;flag not to cut back heap
BRA.S LaunchCom ;fall into common code
; Here is the main entry point for launch
Launch
ST LaunchFlag ;flag that we should cut back the heap
; first, send a doGoodBye call to all drivers that want one
MOVEM.L D0-D1/A0-A1,-(SP) ; save registers <EHB 29-Jan-85>
SUB #IOQElSize,SP ; allocate pBlock <EHB 29-Jan-85>
MOVE #-1,CSCode(SP) ; set up control code <EHB 29-Jan-85>
MOVE.L UTableBase,A1 ; point to unit table <EHB 29-Jan-85>
MOVE.W UnitNtryCnt,D1 ; get # entries in unit table <EHB 29-Jan-85>
GoodByeLoop
MOVE.L (A1)+,D0 ; get the DCE handle <EHB 29-Jan-85>
BEQ.S NextGoodBye ; if NIL, try next one <EHB 29-Jan-85>
MOVE.L D0,A0 ; get the DCE handle <EHB 29-Jan-85>
MOVE.L (A0),A0 ; get the DCE pointer <EHB 29-Jan-85>
BTST #DNeedGoodbye,DCtlFlags(A0) ; need a goodbye kiss? <EHB 29-Jan-85>
BEQ.S NextGoodbye ; not tonight dear <EHB 29-Jan-85>
; we found one that needs a goodbye call so issue the control call
MOVE.W DCtlRefNum(A0),IORefNum(SP) ; set up the refNum <EHB 29-Jan-85>
MOVE.L SP,A0 ; point to the DCE <EHB 29-Jan-85>
_Control ; kiss it goodbye... <EHB 29-Jan-85>
NextGoodBye
SUBQ #1,D1 ; check next entry <EHB 29-Jan-85>
BNE.S GoodByeLoop ; if so, loop <EHB 29-Jan-85>
ADD #IOQElSize,SP ; deallocate pBlock <EHB 29-Jan-85>
MOVEM.L (SP)+,D0-D1/A0-A1 ; restore registers <EHB 29-Jan-85>
LaunchCom
; preserve application name, and which sound and screen pages to use
movea.l a0,a3 ; save pblock ptr in a3 until actual launch <28Oct85>
movea.l (a3)+,a0 ; file name ptr <28Oct85>
move.w (a3)+,CurPageOption ; <28Oct85>
LEA CurApName,A1 ;get address to stuff the name
MOVEQ #32,D0 ;move 32 bytes worth
_BlockMove ;move it in
MOVEQ #0,D3 ;<A284> assume all flags are zero
CMP.W #'LC',(A3)+ ;<A284> extension code around?
BNE.S @closeOld ;<A284> br if not
ADDQ #4,A3 ;<A284> skip over length
MOVE.W (A3)+,D3 ;<A284> save flags for later test
; close any previously open application, if any
@closeOld
MOVE CurApRefNum,D0 ;get refnum of current application
BLE.S SkipClose ;if none, skip the close
MOVE.W D0,-(SP) ;push the refNum
_CloseResFile ;close it
CLR.W CurApRefNum ;flag that no application is open
; now initialize the application heapZone, if we're launching
SkipClose
MOVE.L BufPtr,SP ;start stack under screen/debugger
CLR.L StkLowPt ;keep VBL task out
TST.W LaunchFlag ;is it a launch?
BEQ.S OpenApp ;if not, skip
; before obliterating the heap, save the scrap on the stack
MOVE.L scrapHandle,D0 ;get the scrap handle
BLE.S GoInitAZone ;if none, skip
MOVE.L D0,A0 ;get the handle
_GetHandleSize ;get its size
ADDQ.L #1,D0 ; make sure it's even <EHB 29-Jan-85>
BCLR #0,D0 ; because that's how SP likes it! <EHB 29-Jan-85>
SUB.L D0,SP ;allocate space for it
MOVE.L SP,A1 ;set up destination for move
MOVE.L (A0),A0 ;set up source for move
MOVE.L D0,-(SP) ;remember the size
_BlockMove ;move it!
; re-init the application heap zone, destroying the world...
; ...but just before, flush any vbl tasks executing out of that doomed land! <27Mar85>
GoInitAZone
; Code move to InitApplZone, where it might actually belong. <C681>
; Moved here from LaunchCom -- only reinitialize if heap will be trashed. <24Apr85>
;;;CLR.L DragHook ;No drag hook yet
;;;CLR.L DeskHook ;No desk hook for hit-testing desk.
;;;LEA CloseOrnHook, A0 ; Point to closeOrnHook
;;;CLR.L (A0)+ ;clear closeOrnHook
;;;CLR.L (A0)+ ;clear RestProc
;;;CLR.L (A0)+ ;clear saveProc
;;;CLR.W TaskLock ;clear taskLock, fScaleDisable.
;;;CLR.L ResErrProc ;and resource error proc.
;;;CLR.L EjectNotify ;moved here from InitApplZone (from patches) <24Apr85>
;;;BSR SndAppDead ;kill all current channels <C548>
;;;BSR.S FlushApplVbls ;kill off doomed vbl tasks <27Mar85>
_InitApplZone ;cut back the heap
;;;CLR.W CurApRefNum ;InitApplZone closes resource files
;allocate a new handle for the scrap to be copied into, if necessary.
TST.L scrapHandle ;did we have a scrap?
BLE.S SkipScrap ;if none, skip
; we had a scrap so better allocate a new handle for it and rescue its contents
; from the stack
MOVE.L (SP)+,D1 ;get the size of the scrap
MOVE.L D1,D0 ;set up size for NewHandle
_NewHandle ;allocate a handle for it
MOVE.L A0,scrapHandle ;remember the handle
MOVE.L D1,D0 ;get size for blockMove
MOVE.L (A0),A1 ;get destination pointer
MOVE.L SP,A0 ;get source pointer
_BlockMove ;move it in!
ADD.L D1,SP ;deallocate scrap save buffer
SkipScrap
;;;_RDrvrInstall ;fix up ram based drivers -- moved to InitApplZone <C681>
; JSR LaunchScript ;fix up scripts (C192)
; now that the heap's in good shape, open the new application file after reiniting
; some important hooks and globals
; Open the app res file (preloading the most desirable resources). Use the call <28Oct85>
; FUNCTION _OpenResFile(f : Str255) : integer; with RMGRPerm set for read-only access. <30Oct85>
; This ugly implicit param to RMGR supports Finder's need to trap out OpenResFile. <30Oct85>
OpenApp
SUBQ #2,SP ;<A284> space for result
PEA CurApName ;<A284> launchee
MOVEQ #0,D0 ;<A284> assume r/w or r/o if already open
BTST #6,D3 ;<A284> 1 => read-only
BEQ.S @1 ;<A284> br if not
MOVEQ #1,D0 ;<A284> r/o permission
@1 MOVE.B D0,RMGRPerm ;<A284> use implicit READ-ONLY boolean for RMGR
_OpenResFile ;<A284> open resfile with appropriate permissions
MOVE.W (SP)+,CurApRefNum ;<A284> remember it in low memory
BLE BadOpen ;<A284> branch if open wasn't successful
; now load in segment 0, which has the A5 world information as well as the
; jump table
MOVEQ #0,D0 ;get ID for segment 0
BSR LoadCode ;load it in =>seg handle in A0
BEQ BadOpen ;if we failed, report error
MOVE.L A0,SaveSegHandle ;remember code 0 handle in loMem
; set up A5 and A7 for this application
MOVE.L (A0),A0 ;point to seg 0 info
; adjust the stack base according to the page 2 options word
TST.W CurPageOption ;are any page 2 options requested?
BEQ.S SetA5 ;if not, go build A5 world
BPL.S SoundPage2 ;if so, go handle sound page 2
MOVE.L MemTop,D0 ;start at memTop
SUB.L #$0000D900,D0 ;compute video page 2 address
SetNewStack
CMP.L SP,D0 ;should we move down the stack
BGE.S SetA5 ;if not, skip
MOVE.L D0,SP ;move it down
SetA5
; Give the world a chance to mess with the stack before committing to an a5 world. <28Oct85>
movea.l jSegStack,a3 ; get vector to continue stack computation <28Oct85>
jmp (a3) ; <28Oct85>
vSegStack ; <28Oct85>
SUB.L (A0)+,SP ;allocate "above A5" space
; Before jamming A5 for the app, chop down to ensure long alignment, leaving either 0 <C800>
; or 2 dead bytes between the A5 and BufPtr worlds. After that its up to CODE=0 to <C800>
; to keep things lined up. <C800>
MOVE.L SP,D0 ; get stack where we can trim it <C800>
ANDI.W #$FFFC,D0 ; keep all but low 2 bits <C800>
MOVE.L D0,SP ; new, empty stack is 4*N <C800>
MOVE.L SP,A5 ;set up A5
SUB.L (A0)+,SP ;allocate "below A5" space
MOVE.L A5,CurrentA5 ;remember A5 for this application
MOVE.L SP,CurStackBase ;remember stack for this one, too
MOVE.L SP,StkLowPt ;for heap-stack crashes
; move in the jump table to where it belongs
MOVE.L (A0)+,D0 ;get the jump table size
MOVE.L (A0)+,A1 ;get the load offset
MOVE.W A1,CurJTOffset ;remember the offset
ADD.L A5,A1 ;add in the base address
LEA 2(A1),A3 ;remember the launch address
_BlockMove ;move it in
; now that things are set up, we can release segment 0
MOVE.L SaveSegHandle,-(SP) ;push the segment 0 handle
_ReleaseResource ;de-allocate it
; set up the parameters to the application
LEA 8(A5),A0 ;point to parameter area
CLR.L (A0)+ ;standard input
CLR.L (A0)+ ;standard output
MOVE.L AppParmHandle,(A0)+ ;parameter pointer
CLR.W (A0)+ ;physExec flag for stupid Lisa Pascal
; set the default application heap zone limit based on the current stack
MOVE.L SP,A0 ;get the stack
SUB.L DefltStack,A0 ;subtract buffer zone
_SetApplLimit ;set the new limit
MOVE.L jLaunchInit,A0 ; address of init routine <C681>
JSR (A0) ; vectors aweigh! <C681>
JSR (A3) ;launch the application:
; A4,A6 unchanged <08Jul85>
; A5,A7 initialized <08Jul85>
; D0-D7 zeroed <08Jul85>
; A0-A2 set to DiagROM <08Jul85>
; If we reached this point, the application must have successfully terminated.
; Close its resource file and chain back to the finder.
ExitToShell ; <30Jan85>
; MOVE.W CurApRefNum,-(SP) ; push the app's refnum (THIS IS DONE IN LAUNCH!)
; _CloseResFile
; CLR.W CurApRefNum
_PMgrExit ; Empty out the palette manager < 7Jul89>
SUB.L A0,A0 ; clear out A0 <30Jan85>
_SetGrowZone ; disable application's growZone handler <30Jan85>
SUBQ #4,SP ; load the scrap into memory <30Jan85>
_LodeScrap ; <30Jan85>
ADDQ #4,SP ; trashes pascal regs <30Jan85>
MOVEQ #(IOVQElSize/2)-1,D0 ; <18Aug85>
@1 CLR.W -(SP) ; get IO param block off stack <18Aug85>
DBRA D0,@1 ; (with IOFileName zeroed) <18Aug85>
MOVE.L SP,A0 ; <18Aug85>
MOVE.W BootDrive,IOVRefNum(A0) ; prefix to 'boot' drive <30Jan85>
_SetVol ; <30Jan85>
ADD #IOVQElSize,SP ; clean up stack <30Jan85>
LEA LoaderPBlock,A0 ;point to lomem param block
MOVE.L A0,A1 ;copy to A1
PEA FinderName ;get finder name pointer
MOVE.L (SP)+,(A1)+ ;put finder name ptr in pBlock
CLR.L (A1)+ ;no page 2 usage
_Launch ;<A284> launch it!
; here is the error handler for when we can't open the file. We've already
; obliterated the world (possibly) so just deep shit
BadOpen
MOVEQ #DSBadLaunch,D0
_SysError ;post the error
DC.W $A9FF ;invoke debugger
;------------------------------------------------------------------------------
; PROCEDURE vLaunchInit; new <C681>
;
; Vectored utility to set up application world just before launching the app.
; Historically set $0 to be diag ROM rather than even more historical 'FOBJ'
; from early Finders. Much experimentation is being done with different values
; to get as many apps as possible to work despite their love of Nil ptrs and handles.
; Input: a3=app address, a4-a7 preinitialized above.
; Registers: d0-d7/a0-a2
; Called by: Launch&Chain through vector jLaunchInit.
;------------------------------------------------------------------------------
vLaunchInit
; First do init of 68881 (FPU) if present
BTST #hwCbFPU,HWCfgFlags ;FPU installed? <C141><1.5>
BEQ.S @2 ;skip if not <C141>
MC68881 ; <C749>
CLR.L -(SP) ; Place null state frame on stack <C749>
FRESTORE (SP)+ ; … and use it to reset all FPU regs<C749>
; Next do init of A and D regs
@2 MOVEQ #0,D7 ;clear D7 for stupid Pascal
MOVEQ #0,D6 ;set up a fairly constant world <08Jul85>
MOVEQ #0,D5 ; <08Jul85>
MOVEQ #0,D4 ; <08Jul85>
MOVEQ #0,D3 ; <08Jul85>
MOVEQ #0,D2 ; <08Jul85>
MOVEQ #0,D1 ; <08Jul85>
MOVEQ #0,D0 ; <08Jul85>
; deleted check for debugger - always put safe value in location 0 for those <C707>
; NIL handle apps!! <C707>
MOVE.L ROMBase, A2 ; <C490/08Dec86>
ADD.L #$10000, A2 ; <C490/08Dec86>
MOVE.L A2,A1 ; <08Jul85>
MOVE.L A2,A0 ; <08Jul85>
MOVE.L A2,0 ;keep everything constant <08Jul85>
CLR.L (A5) ;fake nil QD world for rude apps <C800>
RTS ; <C681>
;------------------------------------------------------------------------------
;
; PROCEDURE GetAppParms(VAR apName: Str255;
; VAR apRefNum: INTEGER;
; VAR apParam: Ptr)
;
; GetAppParms is a utility routine that returns some information about the
; currently executing application. It returns its name (the first 24
; characters, anyway), its resource refNum and a pointer to the parameter
; block passed by the finder.
;
;------------------------------------------------------------------------------
GetAppParms
MOVE.L (SP)+,A0 ;pull off the return address
MOVE.L (SP)+,A1 ;get pointer to apParam
MOVE.L 16(A5),(A1) ;return a pointer to finder pBlock
MOVE.L (SP)+,A1 ;get pointer to apRefNum
MOVE.W CurApRefNum,(A1) ;pass back the refNum
MOVE.L (SP)+,A1 ;point to place to stuff name string
MOVE.L A0,-(SP) ;replace return address
LEA CurApName,A0 ;point to name in low memory
MOVEQ #32,D0 ;move 32 bytes
_BlockMove ;move it!
RTS ;return to caller (params already stripped)
;------------------------------------------------------------------------------
;
; InstallRDrivers fixes up the unit table after the application heap
; is obliterated between applications.
;
;------------------------------------------------------------------------------
InstallRDrivers
MOVEM.L D0-D4/A0-A3,-(SP)
; loop through the unit table, checking for drivers in the application heap
MOVE.L UTableBase,A3 ; get pointer to unit table
MOVE.W UnitNtryCnt,D3 ; get # of entries in unit table
MOVEQ #-1,D4 ; the first unit is refNum -1
IRDLoop
MOVE.L (A3)+,D0 ; get the DCE handle
BEQ.S NextIRD ; if NIL, skip
MOVE.L D0,A1 ; get handle in A-reg
MOVE.L (A1),D0 ; <08Jul85>
BEQ.S NextIRD ; br if DCE purged (shouldn't be) <08Jul85>
MOVE.L D0,A1 ; get DCE ptr
BTST #DRamBased,DCtlFlags+1(A1) ;is it ROM-based?
BEQ.S NextIRD ; if so, skip
MOVE.L DCtlDriver(A1),D0 ; get driver handle in D0
BEQ.S NextIRD ; if none, skip
MOVE.L DCtlStorage(A1),D1 ; preserve its storage handle <08Jul85>
BSR AppZoneAddr ;<A284> in application area?
BNE.S DoSysZDriver ;<A284> br if not - handle special
; we got a driver in the application heap, so re-init its DCE
MOVEQ #DCtlEntrySize-1,D0 ; get size in bytes
MOVE.L A1,A0 ; point to DCE start
@1 CLR.B (A0)+ ; clear a byte
DBRA D0,@1 ; loop till cleared
; flag it as RAM-based, set up the refNum, restore DCtlStorage
BSET #DRamBased,DCtlFlags+1(A1)
MOVE.W D4,DCtlRefNum(A1) ; set up the refNum (queue inited to 0s)
; At this point, A1 = DCE ptr and D1 = DCtlStorage(A1) (before possible zeroing above). <13Jan86 JTC>
; Clear the DCtlWindow field in any case and, if the storage is in the appl zone,
; clear the DCtlStorage field, too. If the storage is in the system zone, restore
; the DCtlStorage field from saved value in D1.
; Prior to this fix, DCtlStorage(A1) (which was just set to zero) would be checked against
; ApplZone. Since it would appear lower, D1 would be left untouched, so that the DCE would
; have a bogus handle replaced in the DCtlStorage field.
; Note that the window field must be cleared for ALL drivers since the window list is about
; to be trashed as the ApplZone is wiped out. Since the driver has previously been called
; to Close, the window should be nonexistant anyway. In the case of system-resident drivers,
; the storage should be checked for appropriate size on entry, in case FDAMover replaced one
; with another.
DoSysZDriver ; <08Jul85>
CLR.L DCtlWindow(A1) ; zero its window <08Jul85>
MOVE.L D1,D0 ;<A284> storage ptr
BSR AppZoneAddr ;<A284> in application area?
BNE.S @1 ;<A284> if not, leave D1
MOVEQ #0,D1 ; otherwise, zero it before killing app heap <13Jan86 JTC>
@1
MOVE.L D1,DCtlStorage(A1) ; restore or zero DCtlStorage <08Jul85>
; inspect the next table entry
NextIRD
SUBQ #1,D4 ;decrement refNum
SUBQ #1,D3 ;more to do?
BNE.S IRDLoop ;loop until done
MOVEM.L (SP)+,D0-D4/A0-A3
RTS ; all done!
SgLdrEnd
END