; ; File: StartSearch.a ; ; Contains: This collection of subroutines is used to search out the most appropriate device to become ; the startup device, and to load the boot blocks from that device. It also provides the user ; with feedback as to what is happening. ; ; Written by: Wayne R. Loofbourrow - September, 1986 ; ; Copyright: © 1986-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 11/22/93 pdw Rolling in ; 11/9/93 pdw Fixed the "failed floppy boot causing wrong device boot" bug. ; Moved initialization of SCSIDrvrs back out of here and into ; SCSIMgrInit and BootItt (IttBoot) because on a failed boot, ; FindStartupDevice is called again and it wipes out SCSIDrvrs. ; Same with call to InitSCSIBoot. ; 10/14/93 pdw Added selectable partition booting. Added forceBoot for ; InstallMeFirst CD-ROMs. Fixed Cmd-Shift-Opt-Del bugs with async ; SCSI. Rearranged some stuff and cleaned up some stuff. ; 9/9/93 pdw Changed Peril to SetOSPassword and put it in SysEqu.a. ; 8/23/93 pdw Added support for LimitPRAMClear, IgnoreCmdOptShDel, ; LoadDefaultOnly - three options required for AIX security, ; enabled by setting bits in PRAM $76. ; 6/14/93 kc Roll in Ludwig. ; 6/11/93 KW Do not call HideCursor in routine ShowSuccess if cursor is ; already hidden i.e. CrsState < 0. Fixes Radar bug #1087192 ; 2/13/93 PW Added Ludwig changes and . ; 2/12/93 PW Added passing of drivers' "don't munge heaps" bit into SCSILoad. ; 1/27/93 DCB Added code for CmdShiftOptDel startup sequence to fix Radar Bug ; 1051033. ; 12/16/92 SWC Moved CenterRect here from StartBoot.a. Did some cleanup. ; 11/30/92 PW Changed COUSIN_ITT uses to COUSIN_ITT AND hasAsyncSCSI. ; (Reserving use of COUSIN_ITT for special test builds.) ; 11-12-92 jmp Eliminated assembler warning when not building with the ; COUSIN_ITT flag enabled. ; 7/28/92 PW Turned on Cousin Itt (SCSIMgr4pt3). ; 7/28/92 PW Added Cousin Itt stuff. ; 5/16/92 kc Roll in Horror. Remove conditionals. ; <5> 1/2/92 RB Include UniversalEqu.a for TestFor macro. ; <4> 1/2/92 RB Do universal test for PowerMgr before calling it so that the ; conditionals can be taken out. Flush the cpu cache before boot ; block validation. ; <3> 9/16/91 JSM Cleanup header. ; <2> 6/12/91 LN Changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a' ; <1.9> 11/13/89 MSH Pmgr equates now in record format. ; <1.8> 8/22/89 SES Removed references to nFiles. Changed include DeclRomEqu.a to ; RomEqu.a. Changed sRsrc_BootRec to sRsrcBootRec. ; <1.7> 6/10/89 SWC Converted the HappyMac and disk icon drawing routines to use ; QuickDraw on all machines. ; <1.6> 5/24/89 GGD Converted to feature based conditionals in more places, more ; works is needed for the 16 bit machines. ; <1.5> 4/10/89 gmr Removed specific drive checks in InBootMask, now just check for ; drive number within range (0..15). This allows BootMask to work ; with RAM disks, as well as future drivers. Eliminated IsItSCSI, ; IsItHD20 in the process. ; <¥1.4> 3/13/89 BBM SetOSDefault blindly set pram to the values pointed at by A0. ; Master pointers to rom resources on a macintosh ][ are of the ; form A083XXXX. The Trap number for SetOSDefault is A083. If a ; program crashed and started executing random blocks, then there ; was a good chance that it would try to execute a master pointer. ; The result would be that the default OS on reboot is not valid. ; Cross reference PB337 in system sources. The fix is to require a ; password, to prevent wandering programs from creating Chaos. ; <1.3> 2/27/89 jwk Added BigJSR's to SCSILoad as part of async SCSI roll in. ; <1.2> 2/16/89 rwh removed Mv conditionals for Vias not working. ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <2.0> 11/7/88 rwh fixed bug in 'command-shift-option-del' disabling of internal ; drive ; <1.9> 9/24/88 rwh roll in on MvMac changes ; <¥1.8> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; <1.7> 9/12/88 MSH Last version of sleep count down. Time saved on stack. ; <1.6> 9/9/88 MSH Screen clearing before shut down uses lomem values instead of ; equates. ; <1.5> 9/8/88 MSH Slightly revised sleep count down method. ; <1.4> 6/24/88 MSH HcMac: Fixed the time out waiting for boot device to two ; minutes. Sleep command now requires a signature word sent with ; the command. ; <1.3> 6/15/88 MSH fix for ramdisk stuff ; <1.2> 6/7/88 MSH Converted to Mac ][ boot screen and SCSI boot device selection ; for HcMac. ; <1.1> 5/23/88 BBM fixed name conflicts by adding i to internal routines. ; <1.0> 2/10/88 BBM Adding file for the first time into EASEÉ ; 10/29/87 rwh Port to Modern Victorian (on MvMac). Removed those ugly "--- ; NuMac ---)))"s. ; 9/2/87 MSH Port to HcMac (Laguna) ; 2/8/87 SHF Added delay between calls to SCSILoad in WaitForInternal to ; accomodate drives which don't like to be polled too quickly. ; 2/2/87 GWN Renamed SDM selector. Changed HandleSlotDev to LoadSlotDrivers. ; Fixed bug in NeverAgain. ; 1/29/87 GWN Cleared spExtDev field where neccessary. ; 1/27/87 SHF Changed the internal drive wait timeout value to 20 seconds. ; 1/24/87 WRL [NuMac] Modified the disk and happy Mac plotting routines to use ; QuickDraw. HappyMac routine moved here from startfail. ; 1/23/87 SHF Increased the internal drive wait timeout value to 25 seconds. ; 1/15/87 GWN Changed the interface of GetVideoDefault and SetVideoDefault. ; 1/13/87 GWN Test the status of the sLoad code. ; 1/12/87 SHF Now uses low-memory global for SCSI ID of the internal hard disk ; (used to always assume 0). ; 1/7/87 GWN Made minor changes for slot booting. ; 1/5/87 GWN Added code to center disk icon & company. ; 1/4/87 JTC Changed MyIOPB to $380, but then restored it to $400. ; 12/12/86 GWN Changed PRAM address of Video default to $80. ; 12/2/86 GWN Added code to enable boot off of a default slot device. Modified ; EmbarkOnSearch to get more parameters from PRAM. Added ; GetOSDefault and SetOSDefault routines. Added GetVideoDefault ; and SetVideoDefault traps (code by WRL). ; 11/8/86 CSL Load SCSI driver 0 in general LoadDriver routine if no ; don't-load drive 0 keys (command, shift, option and delete) are ; down. ; 11/6/86 CSL Power user - don't load internal hard disk - command, if hold ; down command, shift, option and delete keys are bootup time, ; internal hard disk would not be loaded, code in startsearch, ; with this power user command, check internal disk disable is ; changed from FullWaitMask to DynWaitMask. ; 11/4/86 SHF Changed mask value in SetWaitFlags which caused the timeout ; value to always have been reset to 0 and the wait flags to ; always retain their current value (meaning Permanent Disable was ; always set). Removed nWaitMacs.a include (rolled into ; StartMacs.a). ; 11/4/86 WRL Add new internal wait disable bit. Don't continue internal wait ; if device is there, but driver fails to load. Added new ; _InternalWait trap. ; 11/3/86 WRL Put LoadSCSIDrivers ahead of InternalWait so that SCSI devices ; 7..1 get priority in the drive queue over SCSI device 0 if no ; default is set. ; 10/31/86 WRL Cut SCSILoad related delays down to 1.75 seconds (from 3.5 ; seconds). Fixed bug: No, SEQ doesn't affect the CCR!!! Fixed ; bug: Branch in WaitForInternal was wrong polarity. Enhancement: ; Don't try to load internal hard disk's driver if corrupted. ; 10/30/86 WRL Changed GetDefaultStartup, SetDefaultStartup, and InternalWait ; to use an OS style interface, as they should. ; 10/30/86 SHF Changed GetStartupDevice trap to bsr since the trap was OS but ; expected to be called ToolBox style. Fixed stack bug in ; SetRawTimeOut routine. ; 10/29/86 WRL After case-laden discussions with Jerome, Tony, Steve, Sheila, ; and Rich, we decided to have the time delay refer only to the ; maximum amount of time the system will wait for the internal ; SCSI device (whose ID must be zero). If the delay is exhausted, ; it is assumed that the user doesn't have an internal drive, and ; the delay in PRAM is reset to zero. The delay now refers to ; total time since Ticks was cleared. Isn't this fun? ; 10/28/86 WRL Made delay apply up front, to give drives a chance to warm up. ; 10/27/86 SMH modified rom search procedure. ; 10/9/86 bbm Modified to mpw aincludes. ; 10/2/86 Fixed bug in flashing X on disk icon. ; 9/30/86 Creation based loosely on the Mac Plus boot code. ; PRINT OFF LOAD 'StandardEqu.d' INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'UniversalEqu.a' INCLUDE 'Devices.a' INCLUDE 'PowerPrivEqu.a' INCLUDE 'SlotMgrEqu.a' INCLUDE 'ROMEqu.a' INCLUDE 'SCSI.a' PRINT ON MACHINE MC68020 ;--------------- ; Local Equates ;--------------- MyIOPBA6 EQU -$400 ; A6 offset for IOPB FlashEnable EQU 8 ; (bit) 0 = disable; 1 = enable. FlashParity EQU 9 ; (bit) 0 = no marks in disk icon, 1 = mark present (X or ?) XEnable EQU 10 ; (bit) 1 = enable X flash next time FlashTicks EQU 60 ; min number of ticks between half-flashes of X or ? NumFlashX EQU 3 ; number of times to flash X before going ; back to flashing ? on disk icon. FloppyRefNum EQU -5 ; floppy driver refnum IntHDRefNum EQU -33 ; refnum of driver for SCSI ID 0 DefaultTimeOut EQU 20 ; number of seconds timeout if PRAM is pristine MaxTimeOut EQU 31 ; maximum number of seconds allowed as timeout PollDelay EQU 15 ; delay (in ticks) between poll drive SCSILoads TimeOutMask EQU $1F ; mask for bits used as timeout WaitFlagsMask EQU $E0 ; mask for bits used as flags DynWaitBit EQU 7 ; 0 = enable; 1 = disable dynamic wait PermWaitBit EQU 6 ; 0 = enable; 1 = disable permanent wait DynWaitMask EQU (1< WITH PmgrRec,pmCommandRec TestFor hwCbPwrMgr ; do we have Power Manager? beq.s @noSleep ; if not then skip time check MOVE.L Ticks,D0 ; Get the current time SUB.L startTicks(A4),D0 ; Determine the time to go back to sleep CMP.L #BootDevTicks,D0 ; See if time out has occured BLS.S @nosleep @sleepnow LEA pmCommandPB(A4), A0 ; A0 gets pointer to parameter block MOVE.W #SleepReq, pmCommand(A0) ; PMGR command, Go to sleep MOVE.W #4, pmLength(A0) ; Four bytes of data to send LEA pmData(A0), A1 MOVE.L A1, pmSBuffer(A0) ; pointer to send buffer MOVE.L A1, pmRBuffer(A0) ; pointer to receive buffer MOVE.L #SleepSig, pmData(A0) ; Put sleep signature in buffer _PmgrOp CMPI.W #SleepAck,pmData(A0) ; is the reply a sleep confirmation? @waitsleep BEQ.S @waitsleep ; Wait for the drugs to take affect @nosleep ENDWITH ENDIF ; CMPI.W #FloppyRefNum,D4 ; do we have floppy set as the default? BEQ.S @NoChange ; -> yes, keep looking for floppies LEA IsItAnything,A3 ; no, from now on, any device will do @NoChange BSR LoadSCSIDrivers ; load more drivers if we can @TryAgain BSR VisualUpdate ; Update dynamic user feedback @FirstEntry BSR FindNextCandidate ; Find the next potential Startup Device. BEQ.S @NextPass ; Branch if we're at the end of the queue. BSR SelectDevice ; Set up parameter block for this device. BSR CheckMouseEject ; Eject it if requested by mouse-down. BEQ.S @TryAgain ; Branch if ejected (we won't try reading it). BSR GetStartupInfo ; Try to read the boot blocks from the device. BEQ.S @GotIt ; Branch if success. BSR ReactToFailure ; Handle the failure case. BRA.S @TryAgain ; Try to find another Startup Device. @GotIt ; show that we have succeeded in finding a startup device TST CrsrState ; if negative, don't call HideCursor BMI.S @ShowHappyMac ; prevents cursor depth from sinking ; to far if can't find boot drive _HideCursor @ShowHappyMac MOVE.L A5, -(SP) BSR HappyMac ; Plot the Happy Mac MOVE.L (SP)+, A5 unlk A4 RTS ;________________________________________________________________________________________ ; ; Routine: EmbarkOnSearch ; ; Inputs: none ; ; Outputs: D3 - bits 31-24: -reserved- ; 23-16: default OS ; 15- 8: default device ID (for slots) ; 7- 0: default partition ; D4 - default driver reference number ; D6 - bits: 10: 1=enable X flash next time, 0=flash ? next time ; 9: 1=mark present (X or ?) ; 8: 1=flashing enabled, 0=flashing disabled ; 7- 0: counter for how long to wait before switch from X back to ? ; A2 - pointer to current drive queue entry (or nil) ; A3 - pointer to routine to filter out desired drive queue entries ; flashTime - absolute time at which we next flash the disk icon ; ; Trashes: D0-D2, A0-A1 ; ; Function: initializes the above variables to their default states, preparing for ; a fresh search to be embarked upon ;________________________________________________________________________________________ EmbarkOnSearch ; get the scoop on the default startup device SUBQ.W #4,SP ; make room for parameters on the stack MOVE.L SP,A0 ; and point to them _GetDefaultStartup ; get info about the default device MOVE.L (SP), startPRAM(A4) ; store for later partition check MOVE.W (SP)+,D3 ; D3.L = MOVE.W (SP)+,D4 ; get the driver's refNum/ ; get the default OS of startup device SUBQ.W #2,SP ; make room for parameters on the stack MOVE.L SP,A0 ; and point to them _GetOSDefault ; get info about the default OS SWAP D3 MOVE.W (SP)+,D3 SWAP D3 ; D3.L = ; do we have a default drive? cmp.w #NoDefaultVal, D4 ; magic value? bne.s @weHaveDefault move.b #1, noDefaultDrive(A4) ; set flag clr.b ckPartition(A4) ; we don't want to ck partition number bra.s @1 @weHaveDefault clr.b noDefaultDrive(A4) ; we have default move.b #1, ckPartition(A4) ; at start, we need to check the partition num @1 clr.b foundDrvr(A4) ; we start off not having found the drvr clr.b forcedBoot(A4) ; assume - not a forced boot ; initialize the rest of the register variables SUBA.L A2,A2 ; initialize the drive queue pointer LEA IsItFloppyOrDefault,A3 ; ASSUME match default or floppy devices. CASE OBJ IMPORT Ck4OnlyLoadFromDefault ; :SCSIMgr4pt3:BootItt.a BSR.L Ck4OnlyLoadFromDefault ; supposed to limit our search to default device? CASE OFF BEQ.S @ck4NoDefault LEA IsItDefault, A3 ; match only default device @ck4NoDefault TST.B noDefaultDrive(A4) ; is there a default drive? BEQ.S @HaveDefault ; -> yes LEA IsItAnything,A3 ; no, match any device @HaveDefault MOVE.L Ticks,flashTime(A4) ; let flash time expire immediately. CLR.W D6 ; clear visual state information. ;--- Initialize SCSIPoll (used to tell StartSearch which ID to wait for) ; and set up SCSIDrvrs to contain only the CPU's ID bit (so far the only ID we know of) ; At first, we default to the "internal" drive ID (SCSI ID 0). If not on a portable ; and the default driver is a valid old-SCSI driver, we use the default startup device number. subq.l #2, sp ; make space for PRAM SCSI id move.l sp, A0 ; address of PRAM return buffer move.l #$00020002, D0 ; read 2 bytes of PRAM at offset 2 _ReadXPRam ; get the SCSI IDs of concern move.w (sp)+, D0 ; and.w #$0707,d0 ; mask all but the ID bits move.b D0, SCSIPoll ; initialize hd flag (bit 7=0) & ID TestFor hwCbPwrMgr ; is this a portable? bne.s @exit ; yes -> use Internal Drive ; Put Default Startup Device number into SCSIPoll - assume no SCSIMgr4pt3 and corresponding ; multi-bus support. If SCSIMgr4pt3 does run, it will just ignore SCSIPoll. If it ; doesn't run, SCSIPoll will be used by WaitForPollDrive. move.w D4, D1 ; get refNum (maybe) not.w D1 ; convert refNum to unit number sub.w #$20, D1 ; convert to SCSI ID blt.s @exit ; out of range -> use previous value cmpi.w #$07, D1 bgt.s @exit ; out of range -> use previous value move.b SCSIPoll, D0 and.b #$F8, D0 ; strip out old internal HD SCSI ID or.b D1, D0 ; put in new one move.b D0, SCSIPoll ; initialize hd flag (bit 7=0) & ID @NoDefault ; @exit RTS ;________________________________________________________________________________________ ; ; Routine: LoadSlotDrivers ; ; Inputs: D3 - bits 31-24: -reserved- ; 23-16: default OS ; 15- 8: default device ID (for slots) ; 7- 0: default partition ; D4 - may contain a slot number (bits 8-15) and sRsrc ID (bits 0-7), ; if not, the routine just exits ; ; Outputs: D4 - default driver reference number, or zero if none ; ; Trashes: D0-D2, A0-A1 ; ; Function: If D4 specifies a slot device, use it to load and execute boot code. If a ; Mac OS is to be booted, then a driver will be loaded and execution will ; continue here, otherwise a different OS will be brought up, so we're done. ;________________________________________________________________________________________ LoadSlotDrivers WITH spBlock,seBlock TST.B noDefaultDrive(A4) ; is there a default device? BNE.S @exit ; no -> out of here ; Test for slot device. TST.W D4 ;Is this a real slot device? BLE.S @Exit ;Branch if not (n=0,n<0 => not slot) ; note: even tho newSCSI uses slot 0, we ; don't have any sRsrc to load so we exit ; Find the default sResource. LEA -spBlockSize(SP),SP ;Allocate parameter block for SDM calls. MOVE.L SP,A0 LEA -seBlockSize(SP),SP ;Allocate parameter block for code executed by _sExec. MOVE.L SP,A1 MOVE.L A1,spsExecPBlk(A0) MOVE.B D4,spId(A0) ;Default Id, LSR.W #8,D4 MOVE.B D4,spSlot(A0) ;Default Slot, _sFindsRsrcPtr ;Get a pointer to the sResource list BNE.S @Fail ;Branch if error ; Set the parameters for the code in sExec. MOVE.B spSlot(A0),seSlot(A1) ;Default Slot, MOVE.B spId(A0),sesRsrcId(A1) ;Default sResource. MOVE.L D3,D0 ;Boot code extensions. MOVE.B D0,sePartition(A1) ;Default Partition, LSR.L #8,D0 MOVE.B D0,seDevice(A1) ;Default Device, and LSR.L #8,D0 MOVE.B D0,seOSType(A1) ;Default OS. LSR.L #8,D0 MOVE.B D0,seReserved(A1) ;Reserved field. MOVE.B #sbState0,seBootState(A1) ;State of StartBoot code. ; Execute the code in the sBoot record. MOVE.B #sRsrcBootRec,spId(A0) ;Execute the code: _sExec ; On entry to the boot code, A0 points to the SE parameter block. BNE.S @Fail ;Branch if fail. TST.W seStatus(A1) ;Test the status of the sLoad code BNE.S @Fail ;Branch if error @Good MOVE.W seRefNum(A1),D4 ;Set D4 to default RefNum. @End LEA spBlockSize+seBlockSize(SP),SP ;Deallocate parameter blocks. @Exit RTS @Fail CLR.W D4 ;Clear default (match any device) BRA.S @End ;Good, now exit. ;________________________________________________________________________________________ ; ; Routine: LoadSCSIDrivers ; ; Inputs: D3 - bits 31-24: -reserved- ; 23-16: default OS ; 15- 8: default device ID (for slots) ; 7- 0: default partition ; D4 - default driver reference number ; ; Outputs: D3 - bits 31-24: -reserved- ; 23-16: default OS ; 15- 8: default device ID (for slots) ; 7- 0: default partition ; D4 - default driver reference number ; ; Trashes: D0-D2, A0-A1 ; ; Function: loads more SCSI device drivers from the devices themselves, if they're available ;________________________________________________________________________________________ LoadSCSIDrivers IF hasAsyncSCSI THEN BSR.L ISITT ; check if we're running SCSI 4.3 TST.B D0 ; are we? BEQ.S @UseOldSCSI ; -> no, use the old code to load drivers PEA forcedBoot(A4) ; ptr to flag indicating a forcedBoot CLR.L -(SP) ; load all drivers BSR.L ITTBOOT ; Load Drivers and look for startup disk ADDQ.W #8,SP ; (clean up the stack) tst.b forcedBoot(A4) ; was it a forced boot? beq.s @1 ; no -> nothing special clr.b ckPartition(A4) ; yes:don't ck part'n (for a different drvr) @1 tst.w d0 ; did we get a startup disk? bge.s @StageLeft ; nope, exit move.w D0, D4 ; yep, change d4 to reflect that @StageLeft RTS @UseOldSCSI ENDIF ; there is a new mechanism to disable loading of poll drive, so, check power ; user command, "command, shift, option and delete keys", if those keys are ; not down, go load the poll drive. ; Make sure that command, shift, option and delete keys are not down MOVEQ #-1,D0 ; try to load all SCSI devices CMPI.W #CmdShiftOptDel,KeyMap+6 ; are command, shift, option and delete keys down? BNE.S @GoLoadD ; -> no, continue MOVEQ #$07,D1 AND.B SCSIPoll,D1 ; get the SCSI ID of the poll drive BCLR D1,D0 ; and clear the bit in the available drive list @GOLoadD move.l d6,-(sp) ; save d6 pdw move.l a0,-(sp) ; save a0 moveq.l #0, D6 ; allow drivers to munge heap pdw BSR.L SCSILoad ; try to load driver(s) from disk move.l (sp)+,a0 ; restore a0 move.l (sp)+,d6 ; restore d6 pdw RTS ;________________________________________________________________________________________ ; ; Routine: WaitForPollDrive ; ; Inputs: none ; ; Outputs: none ; ; Trashes: D0-D2, A0-A1 ; ; Function: Waits until the poll hard disk has had a chance to warm up. ; If it doesn't appear after the recommended amount of time, it ; is assumed absent and parameter RAM is updated accordingly. ;________________________________________________________________________________________ WaitForPollDrive MOVEM.L A2/D5,-(SP) ; Save my registers. ; make sure the poll wait feature is enabled. _GetWaitFlags ; get the current flags AND.B #DynWaitMask,D0 ; and mask off the dynamic flag BNE @RawExit ; -> exit if dynamic wait is disabled ; get the timeout value and convert it to ticks _GetTimeOut ; get the timeout parameter BNE.S @UseGivenTime ; -> use the returned parameter MOVEQ #DefaultTimeOut,D0 ; no parameter returned, so use the default timeout. @UseGivenTime MOVEQ #60,D5 ; convert the timeout to ticks MULU D0,D5 ; and save it ; We now disable waiting for the poll device in the future. ; This way, if loading the driver causes a crash, then next time ; the system boots, it won't wait for it. ; The waiting feature gets re-enabled if no crash occurs. _DisablePermWait ; Disable permanent wait in case driver crashes @WaitForIt IF hasAsyncSCSI THEN BSR.L ISITT ; check if we're running SCSI 4.3 TST.B D0 ; are we? BEQ.S @UseOldSCSI ; -> no, use the old code to load drivers PEA forcedBoot(A4) ; ptr to flag indicating a forcedBoot PEA 1 ; only look for the startup device BSR.L ITTBOOT ; get the startup device's refnum in D0 ADDQ.W #8,SP ; (clean up the stack) tst.b forcedBoot(A4) ; was it a forced boot? beq.s @1 ; no -> nothing special clr.b ckPartition(A4) ; yes:don't ck part'n (for a different drvr) @1 CMP.W #1, D0 ; CmdShiftOptDel or Nonbootable? BEQ.S @RawExit ; yes -> don't wait no more TST.W D0 ; no: did we get a drive? BEQ.S @ckTimeout ; no -> check timeout and loop MOVE.W D0, D4 ; yes: go with it BRA.B @MyExit ; @UseOldSCSI ENDIF ; make sure that command, shift, option and delete keys are not down MOVE.W KeyMap+6,D0 ; get keys down CMP.W #CmdShiftOptDel,D0 ; are command, shift, option and delete keys down? BEQ.S @RawExit ; -> exit if so MOVEQ #$07,D1 AND.B SCSIPoll,D1 ; Get SCSI ID of poll drive MOVEQ #0,D0 ; Clear register BSET D1,D0 ; Set the bit for the drive ; Call SCSILoad with bit map in D0 and heap_munge_flag in D6 move.l d6,-(sp) ; save d6 pdw move.l a0,-(sp) ; save a0 moveq.l #0, D6 ; allow drivers to munge heap pdw BSR.L SCSILoad ; Try to load driver for poll disk move.l (sp)+,a0 ; restore a0 move.l (sp)+,d6 ; restore d6 pdw BEQ.S @MyExit ; Branch if warmed up, but driver is invalid MOVEQ #IntHDRefNum,D0 ; Refnum for ID 0 SUB.W SCSIPoll,D0 ; Convert to refnum for poll drive MOVE.W D0,D1 ; Put back in D1 for comparison ; Let's see if the poll hard disk is actually in the queue @ExamDQ SUBA.L A2,A2 ; Start at beginning of drive queue @FindIntHD BSR NextDQEntry ; Get the next drive queue entry BEQ.S @EndOfQueue ; Branch if we're out of queue entries CMP.W dqRefNum(A2),D1 ; Is it our trusty poll hard disk? BNE.S @FindIntHD ; Nope, see if the next one's it @Warm_n_Toasty ; We found the drive; it must have warmed up BRA.S @MyExit ; That's all folks @ckTimeout @EndOfQueue CMP.L Ticks,D5 ; Should the poll HD be visible by now? BLO.S @NoDrivePresent ; Yes, so quit waiting for it MOVEQ.L #PollDelay,D0 ; Get number of ticks to wait before retrying ADD.L Ticks,D0 ; Calculate new time to try it again @DelayLoop CMP.L Ticks,D0 ; Time to try again? BHS.S @DelayLoop ; No, so just be patient BRA.S @WaitForIt ; Ready to try the poll drive again @NoDrivePresent ; Time expired, drive must not be there _DisableDynWait ; Drive not found, disable dynamic wait @MyExit _EnablePermWait ; No crash, re-enable disk wait @RawExit MOVEM.L (SP)+,A2/D5 ; Restore my registers RTS ; Return to the world ;________________________________________________________________________________________ ; ; Routine: FindNextCandidate ; ; Inputs: A2 - Points to the drive queue entry which was tried last time; the search ; for an appropriate device will begin with the NEXT drive queue entry. ; A nil pointer means you wish to search from the beginning of the queue. ; ; Outputs: A2 - pointer to the next appropriate drive queue entry found ; A3 - pointer to a subroutine which returns BEQ if A2 is pointing to a drive ; queue entry that we are interested in, otherwise it returns BNE. All ; registers except D0/A2 are passed through to the subroutine untouched ; (A2 points to the "next" queue entry). The subroutine must preserve ; all registers except D0-D2/A0-A1. ; CCR - BNE if we found an appropriate entry, BEQ if we've reached the end of the queue ; ; Trashes: D0-D2, A0-A1 ; ; Function: finds the next possible startup device ;________________________________________________________________________________________ FindNextCandidate BSR.S NextDQEntry ; Find the next drive queue entry. BNE.S @ckThisOut ; valid -> check out the drive ; not: we've searched the whole queue. tst.b ckPartition(A4) ; were we looking for right partition beq.s @DoneLooking ; no-> return to scan bus some more tst.b foundDrvr(A4) ; did we see a drive for the default drvr? beq.s @DoneLooking ; no-> return to scan bus some more clr.b ckPartition(A4) ; yes: no longer look for right partition bra.s FindNextCandidate ; and search the DrvQ again @ckThisOut MOVE.W dqDrive(A2),D1 ; get the drive number CMPI.W #15,D1 ; is it in range? BHI.S @OuttaRange ; -> no, try it regardless MOVE.W BootMask,D0 ; get failure info BTST D1,D0 ; is this drive one we've rejected before? BEQ.S FindNextCandidate ; -> yes, skip it @OuttaRange JSR (A3) ; is this one of the devices we're looking for? BNE.S FindNextCandidate ; -> no, keep looking @DoneLooking MOVE.L A2,D0 ; Return result. RTS ;________________________________________________________________________________________ ; ; Routine: NextDQEntry ; ; Inputs: A2 - points to the drive queue entry which was tried last time (nil if ; at the end of the queue) ; ; Outputs: A2 - pointer to the next drive queue entry (nil if at the end of the queue) ; CCR - BEQ if we're reached the end of the queue, BNE if A2 is valid ; ; Trashes: D0 ; ; Function: advances A2 to point to the next drive queue entry. If the pointer is nil, ; point to the start of the queue ;________________________________________________________________________________________ NextDQEntry MOVE.L A2,D0 ; is the pointer NIL? BNE.S @NextEntry ; -> no, more entries left in the queue LEA DrvQHdr+QHead,A2 ; point to the head of the queue @NextEntry MOVE.L qLink(A2),A2 ; point to next entry MOVE.L A2,D0 ; test for end of queue RTS ;________________________________________________________________________________________ ; ; Routine: SelectDevice ; ; Inputs: A2 - points to the current drive queue entry ; ; Outputs: A0 - pointer to A6-based I/O parameter block ; A2 - points to the current drive queue entry ; BtDskRfn contains the driver reference number of the startup device ; BootDrive contains the drive number of the startup device ; ; Trashes: D0 ; ; Function: sets up variables to make the current device the startup device ;________________________________________________________________________________________ SelectDevice LEA MyIOPBA6(A6),A0 ; Point to my parameter block MOVE.W dqRefNum(A2),D0 ; Get driver reference number. MOVE.W D0,IORefNum(A0) ; Put it in parameter block. MOVE.W D0,BtDskRfn ; Save RefNum in case this is boot device. MOVE.W dqDrive(A2),D0 ; Get drive number. MOVE.W D0,IODrvNum(A0) ; Put it in param block. MOVE.W D0,BootDrive ; Save DrvNum in case this is boot device. RTS ;________________________________________________________________________________________ ; ; Routine: CheckMouseEject ; ; Inputs: A0 - pointer to A6-based I/O parameter block ; ; Outputs: CCR - BEQ if the disk was ejected ; ; Trashes: D0 ; ; Function: ejects the disk from the current device if the mouse button is down ;________________________________________________________________________________________ CheckMouseEject TST.B MBState ; does user want eject? BMI.S DontEject ; -> no, skip ; fall thru into EjectMe ;________________________________________________________________________________________ ; ; Routine: EjectMe ; ; Inputs: A0 - pointer to A6-based I/O parameter block ; ; Outputs: CCR - BEQ if the disk was ejected ; ; Trashes: D0 ; ; Function: ejects the disk from the current device ;________________________________________________________________________________________ EjectMe LEA MyIOPBA6(A6),A0 ; Point to my parameter block MOVE.W #EjectCode,csCode(A0) _Control ; Issue an eject command to the device DontEject RTS ; Return with status ;________________________________________________________________________________________ ; ; Routine: GetStartupInfo ; ; Inputs: A0 - pointer to A6-based I/O parameter block ; A6 - pointer to buffer for holding the boot blocks ; ; Outputs: CCR - BEQ if the blocks were read successfully and they're boot blocks ; ; Trashes: D0 ; ; Function: reads the boot blocks from the current device ;________________________________________________________________________________________ GetStartupInfo MOVE.W #1,IOPosMode(A0) ; position relative to start CLR.L IOPosOffset(A0) ; start at byte position 0 MOVE.L A6,IOBuffer(A0) ; load boot blocks at (A6) MOVE.L #$400,IOReqCount(A0) ; two 512-byte blocks _Read ; read the boot blocks BNE.S @Exit ; -> error, so exit move.l a0,-(sp) BSR.L CacheFlush ; flush the caches move.l (sp)+,a0 CMP.W #'LK',(A6) ; check if it's a true boot block @Exit RTS ; and return BEQ if so ;________________________________________________________________________________________ ; ; Routine: ReactToFailure ; ; Inputs: D0 - error code indicating what went wrong ; D4 - default device's driver reference number ; ; Outputs: D6 - may have the XEnable bit set ; BootMask is modified to prevent retries to the current device ; ; Trashes: D0-D1 ; ; Function: responds to a failure to read the boot blocks correctly (this may include ; ejecting the disk) ;________________________________________________________________________________________ ReactToFailure CMP.W #OffLinErr,D0 ; is the disk present and up to speed? BEQ.S @Exit ; -> no, leave it alone so we can try it later CMP.W #NoDriveErr,D0 ; is the drive present? BEQ.S @This1NoMo ; -> no, don't talk to it again BSR.S EjectMe ; for any other error, eject the device BEQ.S @ShowMe ; -> its ejectable, so we can try it again @This1NoMo MOVE.W dqDrive(A2),D1 ; get the drive number CMPI.W #15,D1 ; is it in range? BHI.S @ShowMe ; -> skip if not MOVE.W BootMask,D0 ; get failure info BCLR D1,D0 ; disable this device MOVE.W D0,BootMask ; and update the failure info @ShowMe BSR IsItFloppy ; is it a floppy that failed? BNE.S @Exit ; -> no, don't do anything special BSET #XEnable,D6 ; enable the flashing X on the disk icon @Exit RTS ;________________________________________________________________________________________ ; ; Routine: Ck4SupportsPartition ; ; Inputs: A2 - pointer to the current drive queue entry (must not be nil!) ; D4 - default device's driver reference number ; ; Outputs: CCR - BEQ if the current device support the partition field of PRAM ; D0 - long returned by driver to check against startPRAM ; ; Trashes: D0-D2/A0-A1 ; ; Function: determines whether the current drive queue entry is the default boot device ;________________________________________________________________________________________ Ck4SupportsPartition ; ; Get the DCE using the Device Manager's statusGetDCE call ; lea csPB(A4), A0 ; point to pb move.w D4, ioRefNum(A0) ; pass driver refNum move.w #statusGetDCE, csCode(A0) ; (Device Mgr call, not driver) _Status movea.l csParam(A0), A0 ; get DCE handle (doesnÕt touch CCR) bmi @notSupported ; no such Driver (i.e. DCE not installed) ; ; now check this driver to see if it "follows new rules" and responds ; to driverGestalt status call ; move.w dCtlFlags(A0), D0 ; does it Follow New Rules? btst #FollowsNewRules, D0 ; (word-relative bit #) beq.s @notSupported ; no -> skip driverGestalt call lea csPB(A4), A0 ; point to it move.w #driverGestaltCode, csCode(A0) move.l #'boot', DriverGestaltParam.driverGestaltSelector(A0) move.w dqDrive(A2), ioVRefNum(A0) ; put drive q num in ioVRefNum move.w D4, ioRefNum(A0) _Status ; make driverGestalt call tst.w D0 bne.s @notSupported move.l DriverGestaltParam.driverGestaltResponse(A0), D0 @exit cmp.l #NoDefaultVal, D0 ; set Z if not supported rts @notSupported clr.b ckPartition(A4) ; no longer look for right partition move.l #NoDefaultVal, D0 bra.s @exit ;________________________________________________________________________________________ ; ; Routine: IsItDefault ; ; Inputs: A2 - pointer to the current drive queue entry (must not be nil!) ; D4 - default device's driver reference number ; ; Outputs: CCR - BEQ if the current device is the default device ; ; Trashes: none ; ; Function: determines whether the current drive queue entry is the default boot device ;________________________________________________________________________________________ IsItDefault cmp.w dqRefNum(A2), D4 ; is this driver for the default device? bne.s @notTheDisk ; no-> definitely no the disk then move.b #1, foundDrvr(A4) ; so we know to clr ckPartition if end-of-Q tst.b ckPartition(A4) ; do we need to check the partition num? beq.s @isTheDisk ; no-> well then, it is the right disk bsr Ck4SupportsPartition ; does driver support partition info? beq.s @isTheDisk ; no-> then this is the right volume cmp.l startPRAM(A4), D0 ; yes: does returned boot value eq pram? beq.s @isTheDisk ; yes-> selected disk @notTheDisk moveq.l #1, D0 rts @isTheDisk moveq.l #0, D0 @exit rts ; return result of compare ;________________________________________________________________________________________ ; ; Routine: IsItFloppyOrDefault ; ; Inputs: A2 - pointer to the current drive queue entry (must not be nil!) ; D4 - default device's driver reference number ; ; Outputs: CCR - BEQ if the current device is a floppy or the default device ; ; Trashes: none ; ; Function: determines whether the current drive queue entry is either a floppy or ; the default boot device ;________________________________________________________________________________________ IsItFloppyOrDefault bsr.s IsItDefault beq.s @exit bsr.s IsItFloppy @exit rts ;________________________________________________________________________________________ ; ; Routine: IsItFloppy ; ; Inputs: A2 - pointer to the current drive queue entry (must not be nil!) ; D4 - default device's driver reference number ; ; Outputs: CCR - BEQ if the current device is a floppy ; ; Trashes: none ; ; Function: determines whether the current drive queue entry is a floppy ;________________________________________________________________________________________ IsItFloppy CMPI.W #FloppyRefNum,dqRefNum(A2) ; check if this drive is a floppy ItsDefault RTS ; and return BEQ if so ;________________________________________________________________________________________ ; ; Routine: IsItAnything ; ; Inputs: A2 - pointer to the current drive queue entry (must not be nil!) ; D4 - default device's driver reference number ; ; Outputs: CCR - always BEQ ; ; Trashes: none ; ; Function: always returns true to let all devices be accepted as startup candidates ;________________________________________________________________________________________ IsItAnything CMP D0,D0 ; return BEQ RTS ;________________________________________________________________________________________ ; ; Routine: VisualUpdate ; ; Inputs: flashTime(A4) - the absolute time of the next flash of the ? or X ; D6 - the current state of the icons on the screen ; bits: 10: 1=enable X flash next time, 0=flash ? next time ; 9: 1=mark present (X or ?) ; 8: 1=flashing enabled, 0=flashing disabled ; 7- 0: counter for how long to wait before switch from X back to ? ; ; Outputs: same as inputs ; ; Trashes: D0-D2, A0-A1 ; ; Function: keeps the user interface magic alive: flashes the disk icon when appropriate ;________________________________________________________________________________________ VisualUpdate ; Prevent a visual glitch if device is ready right away. BSET #FlashEnable,D6 ; Enable flashing icon. BEQ.S @DoneDisk ; Branch if previously disabled. MOVE.L flashTime(A4), D0 CMP.L Ticks, D0 ; Is it time to flash? BHI.S @DoneDisk ; Branch if not. MOVE.L Ticks, flashTime(A4) ; Get current time. ADD.L #FlashTicks, flashTime(A4) ; Compute next time to flash. BCLR #XEnable,D6 ; Disable XEnable for next time; ; Should we enable it for this time? BEQ.S @NoSwitch ; Branch if not MOVE.B #NumFlashX,D6 ; Enable X flash by getting its count. @NoSwitch BCHG #FlashParity,D6 ; Switch parity. BNE.S @XorQ ; Branch if we need X or ? showing. LEA DiskIcon,A0 ; plot the plain disk icon BRA.S PlotMyIcon @XorQ TST.B D6 ; Are we showing an ? BEQ.S @ShowQ ; Branch if so. SUBQ.B #1,D6 ; Eventually, we go back to a ?. LEA XDiskIcon,A0 ; but for now, plot the disk icon with the X BRA.S PlotMyIcon @ShowQ LEA QDiskIcon,A0 ; plot the disk icon with the question mark BRA.S PlotMyIcon @DoneDisk RTS ;________________________________________________________________________________________ ; ; Routine: HappyMac ; ; Inputs: none ; ; Outputs: none ; ; Trashes: D0-D2, A0-A1 ; ; Function: displays the Happy Mac icon, centered on the main video device ;________________________________________________________________________________________ HappyMac BSR.S EraseMyIcon ; erase what's on the screen where the icon goes LEA HappyIcon,A0 ; plot the happy mac icon BSR.S PlotMyIcon RTS ;________________________________________________________________________________________ ; ; Routine: EraseMyIcon ; ; Inputs: none ; ; Outputs: none ; ; Trashes: none ; ; Function: erases the ICN# in the center of the main screen ;________________________________________________________________________________________ EraseMyIcon MOVEM.L D0-D2/A0-A1,-(SP) BSR.S PushIconRect ; push the icon's rectangle onto the stack MOVE.L SP,-(SP) ; and point to it MOVE.L grafGlobals(A5),A0 ; point to the QuickDraw globals PEA gray(A0) ; and use 50% gray as the background _FillRect ; erase the rectangle with the desktop pattern ADDQ.W #8,SP ; clean up the stack MOVEM.L (SP)+,D0-D2/A0-A1 RTS ;________________________________________________________________________________________ ; ; Routine: PlotMyIcon ; ; Inputs: A0 - pointer to ICN# to plot ; ; Outputs: none ; ; Trashes: D0-D2, A0-A1 ; ; Function: plots an icon, centered on the main video device ;________________________________________________________________________________________ PlotMyIcon MOVE.L A0,D2 ; save the pointer to the ICN# ; put the source bitmap on the stack (icon's bit image) BSR.S PushIconRect ; bounds = 32x32 rectangle, centered on the main screen MOVE.W #32/8,-(SP) ; rowBytes MOVE.L D2,-(SP) ; baseAddr = pointer to the icon ; put the mask bitmap on the stack (icon's mask image) LEA bitMapRec(SP),A0 ; point to the end of this bitmap so we can make a copy MOVE.L -(A0),-(SP) ; bounds MOVE.L -(A0),-(SP) MOVE.W -(A0),-(SP) ; rowBytes MOVEA.L -(A0),A1 PEA 128(A1) ; baseAddr = pointer to icon's mask ; now copy the icon to the screen using CopyMask... MOVE.L A0,-(SP) ; srcBits PEA 4(SP) ; maskBits MOVEA.L grafGlobals(A5),A1 ; point to QuickDraw's globals MOVEA.L thePort(A1),A1 ; and from there get the current grafport PEA portBits(A1) ; dstBits PEA bounds(A0) ; srcRect MOVE.L (SP),-(SP) ; maskRect MOVE.L (SP),-(SP) ; dstRect _CopyMask ; blast it LEA 2*bitmapRec(SP),SP ; clean up the stack RTS ;________________________________________________________________________________________ ; ; Routine: PushIconRect ; ; Inputs: none ; ; Outputs: none ; ; Trashes: D0-D1, A0-A1 ; ; Function: pushes a 32x32 rectangle on the stack, and then centers it on the main screen ;________________________________________________________________________________________ PushIconRect MOVEA.L (SP)+,A0 ; pop the return address MOVE.L #(32<<16)+32,-(SP) ; push an icon rect (0,0,32,32) on the stack CLR.L -(SP) MOVEA.L SP,A1 ; and point to it MOVE.L A0,-(SP) ; push the return address back on the stack MOVE.L grafGlobals(A5),A0 ; point to QuickDraw globals LEA screenBits+bounds(A0),A0 ; and use the screen's rectangle as a guide BSR.S @TranslateEdge ; translate the top and bottom edges * BRA.S @TranslateEdge ; translate the left and right edges NOP ; (we need this otherwise the assembler barfs on the BSR.S) @TranslateEdge MOVE.W bottom-top(A0),D0 ; calculate the height or width SUB.W (A0),D0 ; of the guide rect MOVE.W bottom-top(A1),D1 ; calculate the height or width SUB.W (A1),D1 ; of the rect to be centered SUB.W D1,D0 ; calculate how much to shift the position ASR.W #1,D0 ; of the rect to be centered (half the difference) ADD.W (A0)+,D0 ; calculate the new top or left edge MOVE.W D0,(A1)+ ; of the rect to be centered ADD.W D1,D0 ; do the same for the bottom or right edge MOVE.W D0,bottom-top-2(A1) RTS ;--------------------------------------------------------------------------------------------- ; The ICN# bitmaps (icon and mask). ;--------------------------------------------------------------------------------------------- HappyIcon DC.L $07FFFFC0,$08000020,$10000010,$11FFFF10,$12000090,$12000090,$12000090,$12111090 DC.L $12111090,$12010090,$12010090,$12030090,$12000090,$12084090,$12078090,$12000090 DC.L $12000090,$11FFFF10,$10000010,$10000010,$10000010,$10000010,$13003F10,$10000010 DC.L $10000010,$10000010,$10000010,$0FFFFFE0,$08000020,$08000020,$08000020,$0FFFFFE0 DC.L $07FFFFC0,$0FFFFFE0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0 DC.L $1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0 DC.L $1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0 DC.L $1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$0FFFFFE0,$0FFFFFE0,$0FFFFFE0,$0FFFFFE0,$0FFFFFE0 DiskIcon DC.L $7FFFFFF0,$81000108,$81007104,$81008902,$81008901,$81008901,$81008901,$81008901 DC.L $81007101,$81000101,$80FFFE01,$80000001,$80000001,$80000001,$87FFFFE1,$88000011 DC.L $88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$88000011 DC.L $88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$FFFFFFFE DC.L $7FFFFFF0,$FFFFFFF8,$FFFFFFFC,$FFFFFFFE,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFE QDiskIcon DC.L $7FFFFFF0,$81000108,$81007104,$81008902,$81008901,$81008901,$81008901,$81008901 DC.L $81007101,$81000101,$80FFFE01,$80000001,$80000001,$80000001,$87FFFFE1,$88000011 DC.L $88000011,$8807E011,$880FF011,$880C3011,$880C3011,$88007011,$8800E011,$8801C011 DC.L $88018011,$88018011,$88000011,$88018011,$88018011,$88000011,$88000011,$FFFFFFFE DC.L $7FFFFFF0,$FFFFFFF8,$FFFFFFFC,$FFFFFFFE,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFE XDiskIcon DC.L $7FFFFFF0,$81000108,$81007104,$81008902,$81008901,$81008901,$81008901,$81008901 DC.L $81007101,$81000101,$80FFFE01,$80000001,$80000001,$80000001,$87FFFFE1,$88000011 DC.L $88000011,$88100811,$88381C11,$881C3811,$880E7011,$8807E011,$8803C011,$8803C011 DC.L $8807E011,$880E7011,$881C3811,$88381C11,$88100811,$88000011,$88000011,$FFFFFFFE DC.L $7FFFFFF0,$FFFFFFF8,$FFFFFFFC,$FFFFFFFE,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFE ENDWITH ENDPROC ;---------------------------------------------------------------------- ; Execute one of the subroutines related to the timeout while waiting for ; the poll hard disk to warm up. ; ; A0 -> Selector indicating which routine to call. ; D0 <-> The meaning of these parameters depends upon which routine is called. ; ; Destroys D0-D2/A0-A1. ;---------------------------------------------------------------------- InternalWait PROC EXPORT MaxDispVal EQU 9 ; Entries 0-9 exist. MOVE.L A0,D1 ; Get selector. CMP.W #MaxDispVal,D1 ; Is value in range? BHI.S @Exit ; If not, do nothing. ADD.W D1,D1 ; Multiply by table entry size LEA @MyTable,A1 ; Point to jump table. MOVE.W (A1,D1.W),D1 ; Get table entry. JMP (A1,D1.W) ; Execute proper subroutine. @Exit RTS ; Return @MyTable DC.W iGetTimeOut-@MyTable ; 0 DC.W iSetTimeOut-@MyTable ; 1 DC.W iGetWaitFlags-@MyTable ; 2 DC.W iSetWaitFlags-@MyTable ; 3 DC.W iDisableDynWait-@MyTable ; 4 DC.W iEnableDynWait-@MyTable ; 5 DC.W iDisablePermWait-@MyTable ; 6 DC.W iEnablePermWait-@MyTable ; 7 ;---------------------------------------------------------------------- ; Get the timeout value. ; ; D0.L <- Timeout value (zero means use default). ; Z <- EQ if timeout indicates default; NE otherwise. ; ; Destroys D0/A0. ;---------------------------------------------------------------------- iGetTimeOut BSR.S GetRawTimeOut ; Get the current timeout parameter AND.B #TimeOutMask,D0 ; Mask out significant bits RTS ; Return ;---------------------------------------------------------------------- ; Get the internal wait flags. ; ; D0.B <- Current wait flags. ; ; Destroys D0/A0. ;---------------------------------------------------------------------- iGetWaitFlags BSR.S GetRawTimeOut ; Get the current timeout parameter AND.B #WaitFlagsMask,D0 ; Mask out significant bits RTS ; Return ;---------------------------------------------------------------------- ; Set the timeout value. ; ; D0.B -> Timeout value (zero means use default). ; ; Destroys D0-D1/A0. ;---------------------------------------------------------------------- iSetTimeOut MOVE.B D0,-(SP) ; Save timeout value BSR.S GetRawTimeOut ; Get the current timeout parameter MOVE.B (SP)+,D1 ; Get timeout value CMP.B #MaxTimeOut,D1 ; Is proposed timeout greater than max? BLS.S @InRange ; Branch if not MOVEQ #MaxTimeOut,D1 ; If out of range, use max @InRange AND.B #$FF-TimeOutMask,D0 ; Clear out timeout bits OR.B D1,D0 ; Put in new timeout value BRA.S SetRawTimeOut ; Set new timeout parameter ;---------------------------------------------------------------------- ; Set the timeout value. ; ; D0.B -> Wait flags to set. ; ; Destroys D0-D1/A0. ;---------------------------------------------------------------------- iSetWaitFlags MOVE.B D0,-(SP) ; Save wait flags BSR.S GetRawTimeOut ; Get the current timeout parameter MOVE.B (SP)+,D1 ; Get wait flags AND.B #WaitFlagsMask,D1 ; Mask out the wait flags AND.B #TimeOutMask,D0 ; Clear out wait flag bits OR.B D1,D0 ; Put in new wait flags ; fall into SetRawTimeOut ;---------------------------------------------------------------------- ; Set the raw timeout parameter. ; ; D0.B -> Timeout parameter. ; ; Destroys D0/A0. ;---------------------------------------------------------------------- SetRawTimeOut MOVE.B D0,-(SP) ; Save new value on stack. MOVE.L SP,A0 ; Point to parameter. MOVE.L #$00010001,D0 ; Write 1 byte starting at loc $01 _WriteXPRam ; Write it to PRAM. MOVE.B (SP)+,D0 ; Clean up stack RTS ; Return. ;---------------------------------------------------------------------- ; Get the raw timeout parameter. ; ; D0.L <- Timeout parameter (only lowest byte is significant). ; Z <- EQ if timeout indicates default; NE otherwise. ; ; Destroys A0. ;---------------------------------------------------------------------- GetRawTimeOut CLR.B -(SP) ; Create a place to put result. MOVE.L SP,A0 ; Point to parameter block. MOVE.L #$00010001,D0 ; Read 1 byte starting at loc $01 _ReadXPRam ; Read it from PRAM. MOVEQ.L #0,D0 ; Clear upper bits. MOVE.B (SP)+,D0 ; Return value in timeout field. RTS ; Return. ;---------------------------------------------------------------------- ; Disable the dynamic wait feature. ; ; Destroys D0/A0. ;---------------------------------------------------------------------- iDisableDynWait _GetWaitFlags ; Get the current wait flags. BSET #DynWaitBit,D0 ; Disable the dynamic wait feature. _SetWaitFlags ; Set the new wait flags. RTS ;---------------------------------------------------------------------- ; Enable the dynamic wait feature. ; ; Destroys D0/A0. ;---------------------------------------------------------------------- iEnableDynWait _GetWaitFlags ; Get the current wait flags. BCLR #DynWaitBit,D0 ; Enable the dynamic wait feature. _SetWaitFlags ; Set the new wait flags. RTS ;---------------------------------------------------------------------- ; Disable the permanent wait feature. ; ; Destroys D0/A0. ;---------------------------------------------------------------------- iDisablePermWait _GetWaitFlags ; Get the current wait flags. BSET #PermWaitBit,D0 ; Disable the permanent wait feature. _SetWaitFlags ; Set the new wait flags. RTS ;---------------------------------------------------------------------- ; Enable the permanent wait feature. ; ; Destroys D0/A0. ;---------------------------------------------------------------------- iEnablePermWait _GetWaitFlags ; Get the current wait flags. BCLR #PermWaitBit,D0 ; Enable the permanent wait feature. _SetWaitFlags ; Set the new wait flags. RTS ENDPROC ;---------------------------------------------------------------------- ; Get information about the current default startup device. ; ; A0 -> A pointer to the record in which the info should be put. ; ; The record has the following format: ; ; RECORD ; sdDrvNum: INTEGER; { Drive number } ; sdRefNum: INTEGER; { Driver reference number } ; END; ; ; The sdDrvNum field is $FFFF if the drive number is irrelevant. ; The sdRefNum field is $0000 if the first available device should be chosen. ; ; Destroys D0-D2/A0-A1. ;---------------------------------------------------------------------- GetDefaultStartup PROC EXPORT ; Read info from parameter RAM. Format is: ; $78 [ (byte) DriveId{for slots} | (byte) PartitionId | (word) RefNum ] MOVE.L #$00040078,D0 ; Read 4 bytes starting at loc $78 _ReadXPRam ; Get it from PRAM. RTS ; Return. ENDPROC ;---------------------------------------------------------------------- ; Set a new default startup device. ; ; A0 -> A pointer to the record from which the info should be taken. ; ; The record has the following format: ; ; RECORD ; sdDrvNum: INTEGER; { Drive number } ; sdRefNum: INTEGER; { Driver reference number } ; END; ; ; The sdDrvNum field is $FFFF if the drive number is irrelevant. ; The sdRefNum field is $0000 if the first available device should be chosen. ; ; Destroys D0-D2/A0-A1. ;---------------------------------------------------------------------- SetDefaultStartup PROC EXPORT ; Write info to parameter RAM. Format is: ; $78 [ (byte) DriveId{for slots} | (byte) PartitionId | (word) RefNum ] MOVE.L #$00040078,D0 ; Write 4 bytes starting at loc $78 _WriteXPRam ; Write it to PRAM. RTS ; Return. ENDPROC IF hasSlotMgr THEN ; (what condition should this be???) ;---------------------------------------------------------------------- ; Get more information about the current default startup device ; ; A0 -> A pointer to the record in which the info should be put. ; ; The record has the following format: ; ; RECORD ; sdOSType: BYTE; { Default OS type } ; sdReserved: BYTE; { Reserved } ; END; ; ; Destroys D0-D2/A0-A1. ;---------------------------------------------------------------------- GetOSDefault PROC EXPORT ; Read info from parameter RAM. Format is: ; $76 [ (byte) Reserved | (byte) OSType ] MOVE.L #$00020076,D0 ; Read 2 bytes starting at loc $76 _ReadXPRam ; Get it from PRAM. move.b #0, (A0) ; clear high byte RTS ; Return. ENDPROC ;---------------------------------------------------------------------- ; Set more information about a new default startup device. ; ; A0 -> A pointer to the record from which the info should be taken. ; ; The record has the following format: ; ; RECORD ; sdOSType: BYTE; { Default OS type } ; sdReserved: BYTE; { Reserved } ; END; ; ; Destroys D0-D2/A0-A1. ; ; <1.4> SetOSDefault blindly set pram to the values pointed at by A0. ; Master pointers to rom resources on a macintosh ][ are of the ; form A083XXXX. The Trap number for SetOSDefault is A083. If ; a program crashed and started executing random blocks, then ; there was a good chance that it would try to execute a master ; pointer. The result would be that the default OS on reboot is ; not valid. Cross reference PB337 in system sources. The fix ; is to require a password, to prevent wandering programs from ; creating Chaos. ; ;---------------------------------------------------------------------- SetOSDefault PROC EXPORT AppPhne EQU $09961010 cmpi.l #AppPhne, SetOSPassword ; check if oneshot is on bne.s @errexit clr.l SetOSPassword ; Write info to parameter RAM. Format is: ; $76 [ (byte) Reserved | (byte) OSType | (byte) DriveId{for slots} | (byte) PartitionId | (word) RefNum ] MOVE.L #$00020076,D0 ; Write 2 bytes starting at loc $76 _WriteXPRam ; Write it to PRAM. RTS ; Return. @errexit clr.l SetOSPassword moveq #-1,d0 ; signal error rts ; and return ENDPROC ;________________________________________________________________________________________ ; ; Routine: Ck4LimitPRAMClear ; ; Inputs: none ; ; Outputs: Z: NE = only boot from Default device ; EQ = boot from Floppy or Default ; D0: NE = only boot from Default device ; EQ = boot from Floppy or Default ; ; Trashes: D0, A0 ; ;________________________________________________________________________________________ Ck4LimitPRAMClear PROC EXPORT IMPORT ValidatePRAM76 ; StartSearch.a bsr ValidatePRAM76 subq.w #2,sp ; allocate buffer on stack movea.l sp, A0 ; get buffer ptr MOVE.L #$00010076, D0 ; Read 1 bytes starting at loc $76 _ReadXPRam move.b (sp)+, D0 and.b #1, D0 ; low bit rts ENDPROC ;________________________________________________________________________________________ ; ; Routine: ValidatePRAM76 ; ; Inputs: none ; ; Outputs: none ; ; Trashes: none ; ; Function: Validates byte $76 of xpram: counts set bits in lower 6 and compares with ; upper two bits. If not equal, zeros out the byte. ; ; Note: Byte $76 (previously reserved but used by OSDefault stuff) is ; being defined as sensitive boot bits generally having to do with ; security issues driven by AIX but these functions can be used ; by other OSes as well. The upper two bits of byte $76 are a ; "checksum" of the other 6 bits (i.e. count of bits set). This ; is desired because of the danger if one of these bits is set ; accidentally by some bogus client. Failing this checksum will ; cause the byte to revert to 00 - a safe value. Currently defined ; bits are: ; 0: limit PRAM clear - don't clear PSWD, AUXPRAM, OSType, DefBoot ; 1: only load drivers from default device, don't boot from floppy ; 2: ignore CmdShiftOptDel ; ;________________________________________________________________________________________ vp76trashedRegs REG D0-D2/A0 ValidatePRAM76 PROC EXPORT movem.l vp76trashedRegs, -(sp) subq.w #2, sp ; allocate buffer on stack movea.l sp, A0 ; get buffer ptr MOVE.L #$00010076, D0 ; Read 1 bytes starting at loc $76 _ReadXPRam ; Get it from PRAM. move.b (sp)+, D0 move.b #0, D2 ; zero reg for addx moveq.l #0, D1 ; clear checksum and.b #$3F, D0 ; get data bits (strip sum bits) @bitloop lsr.b #1, D0 ; get a bit addx.b D2, D1 ; add that bit to checksum tst.b D0 ; loop until no more bits bne.s @bitloop and.b #3, D1 ; only 2 low bits are valid move.b (A0), D0 ; get byte 76 again lsr.b #6, D0 ; get only checksum bits cmp.b D0, D1 ; valid signature? beq @valid ; Yes, don't clear all move.b #00, -(sp) ; clean up bogus value movea.l sp, A0 ; get buffer ptr move.l #$00010076, D0 ; get #, addr PRAM bytes _WriteXPram ; write out zeros to 76 move.b (sp)+, D0 @valid movem.l (sp)+, vp76trashedRegs rts ENDP ;---------------------------------------------------------------------- ; Get information about the current default video device. ; ; A0 -> A pointer to the record from which the info should be put. ; ; The record has the following format: ; ; RECORD ; sdSlot: BYTE; ; sdsRsrcId: BYTE ; END; ; ; sdSlot and sdsRsrcId are zero if no default. ; ; Destroys D0-D2/A0-A1. ;---------------------------------------------------------------------- GetVideoDefault PROC EXPORT ; Read info from parameter RAM. Format is: ; $80 [ (byte) Slot Number | (byte) sResource Number ] MOVE.L #$00020080,D0 ; Read 2 bytes starting at loc $80 _ReadXPRam ; Get it from PRAM. RTS ; Return. ENDPROC ;---------------------------------------------------------------------- ; Set information about the default video device. ; ; A0 -> A pointer to the record from which the info should be put. ; ; The record has the following format: ; ; RECORD ; sdSlot: BYTE; ; sdsRsrcId: BYTE ; END; ; ; sdSlot and sdsRsrcId are zero if no default. ; ; Destroys D0-D2/A0-A1. ;---------------------------------------------------------------------- SetVideoDefault PROC EXPORT ; Write info to parameter RAM. Format is: ; $80 [ (byte) Slot Number | (byte) sResource Number ] MOVE.L #$00020080,D0 ; Write 2 bytes starting at loc $80 _WriteXPRam ; Write them to PRAM. RTS ; Return. ENDPROC ENDIF END