mac-rom/Toolbox/SegmentLoader/SegmentLoader.a

928 lines
38 KiB
Plaintext

;
; 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, donÕt 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),A0 ; handle -> dirty pointer <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 ÒdonÕt 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 ;donÕt 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 2c22a:
;
; 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
_BlockMoveData ;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
_BlockMoveData ;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
_BlockMoveData ;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 itÕs 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
MOVE #$C, D0 ; Empty out the palette manager < 7Jul89>
_PaletteDispatch
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 2c266; 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 2c298(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
_BlockMoveData ;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