mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 16:49:18 +00:00
429 lines
15 KiB
Plaintext
429 lines
15 KiB
Plaintext
|
;
|
||
|
; File: CacheIO.a
|
||
|
;
|
||
|
; Contains: These routines provide disk IO for the TFS caching routines.
|
||
|
;
|
||
|
; Written by: Bill Bruffey
|
||
|
;
|
||
|
; Copyright: © 1985-1994 by Apple Computer, Inc., all rights reserved.
|
||
|
;
|
||
|
; Change History (most recent first):
|
||
|
;
|
||
|
; <SM3> 1/29/94 DCB Roll in changes from MissingLink to support Async SCSI.
|
||
|
; <SM2> 2/17/93 CSS Save additional registers in BasicIO's completion routine. Per
|
||
|
; Radar bug #1063342.
|
||
|
; <SM1> 4/1/92 kc Rolled in PatchBasicIO from FileMgrPatches.a.
|
||
|
; • Pre-SuperMario comments follow •
|
||
|
; <2> 9/10/91 JSM Add a header.
|
||
|
; <1.2> 3/2/89 DNF removed references to forROM; HFS now builds identically for ram
|
||
|
; or rom
|
||
|
; <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/11/88 BBM Adding file for the first time into EASE…
|
||
|
; 9/25/86 BB Updated to use new MPW equate files.
|
||
|
; 9/15/86 BB Modified WriteBlock to fix problem with tag set up for volume
|
||
|
; blocks.
|
||
|
; 9/15/86 BB Modified BasicIO to fix asynch problem and OffLinErr problem.
|
||
|
; 10/22/85 LAK Added ReadOwnBuf, WriteOwnBuf for local buffer support.
|
||
|
; 10/2/85 LAK Added vectored routines for ROM assembly.
|
||
|
; 10/1/85 LAK Added routines RdBlocks and WrBlocks. Added Ref of TFSVCBTst.
|
||
|
; ALL I/O now goes thru one routine, BasicIO.
|
||
|
; 9/10/85 LAK Pass OffLinErr thru as OffLinErr for Mount problems.
|
||
|
; 9/9/85 LAK Pass OffLinErr thru as VolOffLinErr for Mount problems.
|
||
|
; 8/9/85 BB Modified to use VCB pointer in CQH.
|
||
|
; 8/1/85 BB Added code to set up tag data.
|
||
|
; 7/14/85 PWD Changed I/O completion routine to check for synchronous driver
|
||
|
; behavior, and avoid stacking trap completions.
|
||
|
; 6/12/85 BB Added code to check for A6 stack overflow and to maintain the
|
||
|
; stack 'high water mark'.
|
||
|
; 5/16/85 BB Cleaned the code up some.
|
||
|
; 3/26/85 BB Modified to support both file and volume IO.
|
||
|
; 3/16/85 BB Added asynchronous IO.
|
||
|
; 3/16/85 BB Renamed from TFSIO to CacheIO.
|
||
|
; 3/15/85 BB Modified to use A6 stack.
|
||
|
; 1/19/85 BB Extracted from Cache routines.
|
||
|
;
|
||
|
;
|
||
|
|
||
|
;_________________________________________________________________________________
|
||
|
;
|
||
|
; External
|
||
|
; Routines: ReadBlock - Reads a block from disk into a cache buffer.
|
||
|
; WriteBlock - Writes a block to disk from a cache buffer.
|
||
|
; RdBlocks - read a contiguous set of disk blocks to user's buffer
|
||
|
; WrBlocks - read a contiguous set of disk blocks to user's buffer
|
||
|
;
|
||
|
; Vectored routines:
|
||
|
;
|
||
|
; Four routines have been vectored to enable an alternative cacheing scheme to
|
||
|
; replace the default one. The vectors were placed to allow the replacing of
|
||
|
; the Cache routines (GetBlock, RelBlock, etc.) while retaining the low-level
|
||
|
; I/O routines which are not cache-specific (RdBlocks, WrBlocks, SetUpTags, and
|
||
|
; BasicIO). Note that ReadBlock and WriteBlock are cache-specific up to BasicIO.
|
||
|
;
|
||
|
;_________________________________________________________________________________
|
||
|
|
||
|
|
||
|
BLANKS ON
|
||
|
STRING ASIS
|
||
|
|
||
|
PRINT OFF
|
||
|
LOAD 'StandardEqu.d'
|
||
|
include 'HardwarePrivateEqu.a'
|
||
|
include 'SysPrivateEqu.a'
|
||
|
include 'FileMgrPrivate.a'
|
||
|
include 'SCSI.a'
|
||
|
include 'SCSIPriv.a'
|
||
|
PRINT ON
|
||
|
PRINT NOGEN
|
||
|
|
||
|
CacheIO PROC EXPORT
|
||
|
|
||
|
EXPORT ReadBlock,WriteBlock,RdBlocks,WrBlocks
|
||
|
EXPORT ReadOwnBuf,WriteOwnBuf ; <22Oct85>
|
||
|
|
||
|
EXPORT vBasicIO,vRdBlocks,vWrBlocks,vSetUpTags
|
||
|
EXPORT SCSINotBusy
|
||
|
|
||
|
IMPORT TFSVCBTst
|
||
|
|
||
|
|
||
|
;_________________________________________________________________________________
|
||
|
;
|
||
|
; Routine ReadBlock (Read Block)
|
||
|
;
|
||
|
; Function: Reads a block from disk into a specified cache buffer.
|
||
|
;
|
||
|
; Input: A3.L - CQH pointer
|
||
|
; A4.L - CBH pointer
|
||
|
;
|
||
|
; Output: D0.W - error code
|
||
|
; 0 = ok
|
||
|
; other = error
|
||
|
;
|
||
|
; Called by: GetBlock
|
||
|
;_________________________________________________________________________________
|
||
|
|
||
|
ReadOwnBuf
|
||
|
ReadBlock
|
||
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
|
||
|
MOVEM.L D1-D7/A0-A5,-(A6) ; Save away almost all registers on TFS stack
|
||
|
|
||
|
MOVEQ #0,D1 ; indicate 'read' operation
|
||
|
BRA.S RWSetup ; use common code ->
|
||
|
|
||
|
;_________________________________________________________________________________
|
||
|
;
|
||
|
; Routine WriteBlock (Write Block)
|
||
|
;
|
||
|
; Function: Writes contents of cache buffer to disk
|
||
|
;
|
||
|
; Input: A3.L - CQH pointer
|
||
|
; A4.L - CBH pointer
|
||
|
;
|
||
|
; Output: D0.W - error code
|
||
|
; 0 = ok
|
||
|
; other = error
|
||
|
;
|
||
|
; Called by: FlushCache,GetBlock,RelBlock
|
||
|
;_________________________________________________________________________________
|
||
|
|
||
|
WriteOwnBuf ; A2=VCB ptr, A4=OwnBuf ptr - CBHData, (A1,D1)=FCB Ptr
|
||
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack <22Oct85>
|
||
|
MOVEM.L D1-D7/A0-A5,-(A6) ; Save almost all regs on TFS stack <22Oct85>
|
||
|
BRA.S WrBlkCom ; share code <22Oct85>
|
||
|
|
||
|
WriteBlock
|
||
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
|
||
|
MOVEM.L D1-D7/A0-A5,-(A6) ; Save away almost all registers on TFS stack
|
||
|
|
||
|
; set up tag data
|
||
|
|
||
|
MOVEA.L CBHVCBPtr(A4),A2 ; A2 = VCB ptr
|
||
|
MOVE.L CBHDBlk(A4),D0 ; pass D0=disk blk if not a file blk <02Oct85>
|
||
|
MOVE.W CBHFRefNum(A4),D1 ; file refnum or 0
|
||
|
BEQ.S TagCont ; br if volume block <15Sep86>
|
||
|
|
||
|
WrBlkCom
|
||
|
MOVE.L FCBSPtr,A1 ; pass A1=FCB ptr for files
|
||
|
MOVE.L CBHFlBlk(A4),D0 ; ...file block number
|
||
|
TagCont ; <15Sep86>
|
||
|
BSR SetUpTags ; share code with WrBlocks
|
||
|
MOVEQ #1,D1 ; indicate 'write' operation
|
||
|
|
||
|
; set up IO parameter block (ReadBlock code joins here)
|
||
|
|
||
|
RWSetUp
|
||
|
LEA Params,A0 ; use FS IO param block
|
||
|
|
||
|
MOVE.W VCBDrvNum(A2),IODrvNum(A0) ; drive number
|
||
|
MOVE.W VCBDRefNum(A2),IORefNum(A0) ; driver refnum
|
||
|
LEA CBHData(A4),A1 ; addr(cache buffer)
|
||
|
MOVE.L A1,IOBuffer(A0) ;
|
||
|
MOVE.W #1,IOPosMode(A0) ; position mode 1 (from disk start)
|
||
|
MOVE.L #BufSiz,IOByteCount(A0) ; always r/w 512 bytes <22Oct85>
|
||
|
|
||
|
MOVE.L CBHDBlk(A4),D0 ; physical disk block
|
||
|
IF HFSDebug THEN
|
||
|
BNE.S @1 ; should never be zero
|
||
|
_HFSDebug $420
|
||
|
@1
|
||
|
ENDIF
|
||
|
|
||
|
LSL.L #8,D0 ; ...x 512
|
||
|
ADD.L D0,D0 ;
|
||
|
MOVE.L D0,IOPosOffset(A0) ; ... gives disk address
|
||
|
|
||
|
;_______________________________________;
|
||
|
;
|
||
|
; All I/O goes through this routine . . .
|
||
|
;_______________________________________;
|
||
|
|
||
|
BasicIO:
|
||
|
MOVE.L jBasicIO,-(SP) ; jumptable entry for BasicIO <02Oct85>
|
||
|
RTS ; go there <02Oct85>
|
||
|
vBasicIO ; 'vectored' BasicIO routine <02Oct85>
|
||
|
|
||
|
VolatileRegs REG A0-A1/D1-D2
|
||
|
|
||
|
MOVE.L A6,HFSStkPtr ; save stack ptr
|
||
|
|
||
|
IF HFSDebug THEN
|
||
|
TST.W IODrvNum(A0) ; should never be zero
|
||
|
BNE.S @1 ; br if not
|
||
|
_HFSDebug $421
|
||
|
|
||
|
@1 MOVE.L HFSStkTop,D0 ; check for stack overflow
|
||
|
SUBI.L #HFSStkLen,D0 ;
|
||
|
CMP.L A6,D0 ;
|
||
|
BLE.S @2 ; ok ->
|
||
|
_HFSDebug HFSStkOvf
|
||
|
@2
|
||
|
ENDIF
|
||
|
|
||
|
; read/write the disk block
|
||
|
|
||
|
TST.B FSCallAsync ; was FS call async?
|
||
|
BNE.S rwAsync ; br if so (keep it that way)
|
||
|
TST.B D1 ; 'read' operation?
|
||
|
BNE.S @3 ; no, must be a 'write' ->
|
||
|
|
||
|
_Read ; read it synchronously
|
||
|
BRA.S RWCont1 ; then continue
|
||
|
|
||
|
@3 _Write ; write it synchronously
|
||
|
BRA.S RWCont1 ; then continue
|
||
|
|
||
|
rwAsync
|
||
|
|
||
|
; We're about to send an async request to a driver. We have to make sure that
|
||
|
; that request isn't going to collide with another SCSI transaction.
|
||
|
;
|
||
|
; Old (synchronous) SCSI drivers (pre-7.2 HD Setup and 3rd parties') have no
|
||
|
; way of responding to a a request if they attempt to get the SCSI bus and fail
|
||
|
; because the bus is busy. There is no easy way for them to yield asynchronously
|
||
|
; and resume execution when the bus is free. In other words, even though we're sending
|
||
|
; them an async request, they handle it synchronously.
|
||
|
; Under System 7.0, file sharing causes File System I/O to occur at deferred
|
||
|
; task time, making it quite likely that I/O will collide with an already executing
|
||
|
; SCSI transaction, such as one started by CD-Remote or a scanner. Although the new
|
||
|
; async SCSI Manger eliminates this problem for drivers that use the new asynchronous
|
||
|
; API, we still have to handle old drivers that use the old SCSI Manager API., we'll have to settle for avoiding situations where SCSI transactions will
|
||
|
; collide. To do this, there's support in the SCSI Manager to call the vector
|
||
|
; jFSSCSIWakeUp every single time the SCSI manager frees the SCSI bus.
|
||
|
;
|
||
|
; All interrupt-level users of the old SCSI Manager interface free the bus up
|
||
|
; before returning. i.e. they aren't asynchronous users of the bus. So, we only
|
||
|
; have to worry about interrupting event-level users of the bus. We are also assuming
|
||
|
; that any other interrupt-level users of the bus (such as polling routines for CD-ROMs
|
||
|
; or removables) know how to deal with a busy bus, i.e. they figured all this out too.
|
||
|
|
||
|
|
||
|
; Check to see if the lucky driver is in the old synchronous SCSI driver range. This
|
||
|
; check assumes that all drivers that have loaded themselves above this range are
|
||
|
; asynchronous (i.e. any multi-bus aware drivers must be asynchronous).
|
||
|
|
||
|
MOVE.W IORefNum(A0), D0 ; get refNum
|
||
|
CMP.W #$FFDF, D0 ; below old SCSI driver range? (FFDF=ID 0)
|
||
|
BHI.S SCSINotBusy ; yes-> not an old SCSI refNum
|
||
|
CMP.W #$FFD9, D0 ; above? (FFD7=ID 6)
|
||
|
BLO.S SCSINotBusy ; yes-> not an old SCSI refNum
|
||
|
; it is an old SCSI refNum:
|
||
|
|
||
|
MOVEM.L VolatileRegs, -(sp) ; save across _SCSIBusy
|
||
|
CLR.W -(sp) ; space for function result
|
||
|
_SCSIBusy ; is the SCSI bus busy?
|
||
|
TST.W (sp)+
|
||
|
MOVEM.l (sp)+, VolatileRegs
|
||
|
BEQ.S SCSINotBusy ; no -> make call to driver
|
||
|
; yes: make fsSCSIDefer and return (asynchronously)
|
||
|
MOVEM.L D1-D7/A0-A5,-(A6) ; Save away almost all registers on TFS stack
|
||
|
MOVE.L A6,HFSStkPtr ; save stack ptr
|
||
|
BSET.B #fsSCSIDefer, FSBusy ; remind ourselves that we're waiting for SCSI
|
||
|
RTS
|
||
|
|
||
|
SCSINotBusy
|
||
|
LEA RWIOComp,A1 ; IO completion address
|
||
|
MOVE.L A1,IOCompletion(A0) ;
|
||
|
|
||
|
BCLR #HFSContd,HFSFlags ; Clear 'premature-continuation' flag
|
||
|
|
||
|
TST.B D1 ; 'read' operation?
|
||
|
BNE.S @1 ; no, must be a 'write' ->
|
||
|
|
||
|
_Read ,ASYNC ; read it asynchronously
|
||
|
BRA.S @2 ;
|
||
|
|
||
|
@1 _Write ,ASYNC ; write it asynchronously
|
||
|
|
||
|
@2 BEQ.S @3 ; br if no immediate error
|
||
|
TST.W IOResult(A0) ; immediate error? for sure?
|
||
|
BLE.S RWCont ; br if so (otherwise, driver just
|
||
|
; passed back some garbage . . .)
|
||
|
@3 BSET #HFSContd,HFSFlags ; We're now returning from the trap
|
||
|
BNE.S RWCont1 ; If we already returned, do I/O comp. now
|
||
|
|
||
|
RWRTS RTS ; return to caller (complete asynchronously)
|
||
|
|
||
|
; IO completion routine
|
||
|
|
||
|
RWIOComp
|
||
|
BSET #HFSContd,HFSFlags ; We're continuing now
|
||
|
BEQ.S RWRTS ; If trap didn't really return ,ASYNC
|
||
|
; ... then RTS now (we'll be back)
|
||
|
RWCont
|
||
|
MOVEM.L D1-D7/A0-A6,-(SP) ; preserve all significant registers
|
||
|
PEA RWCont2 ; return to here to restore regs
|
||
|
|
||
|
RWCont1
|
||
|
MOVEA.L HFSStkPtr,A6 ; Recover HFS' private stack pointer
|
||
|
MOVEM.L (A6)+,D1-D7/A0-A5 ; Retrieve registers off A6 stack
|
||
|
MOVE.L (A6)+,-(SP) ; pop ret address off HFS stack
|
||
|
|
||
|
TST.W D0 ; any errors?
|
||
|
BEQ.S @1 ; br if not
|
||
|
CMP.W #OffLinErr,D0 ; Offline?
|
||
|
BEQ.S @1 ; br if so
|
||
|
|
||
|
CMP.W #notEnoughMemoryErr,D0 ; was VM able to hold down enough physical memory?
|
||
|
BEQ.S @1 ; send this error through
|
||
|
MOVE.W D0,FSIOErr ; save original error for debugging
|
||
|
MOVEQ #IOErr,D0 ; transform it to generic IO error
|
||
|
@1 TST.W D0 ; set up condition codes
|
||
|
RTS ; return to caller with error code
|
||
|
|
||
|
RWCont2 MOVEM.L (SP)+,D1-D7/A0-A6 ; restore significant registers
|
||
|
RTS ; we're done with it!
|
||
|
|
||
|
|
||
|
;_________________________________________________________________________________
|
||
|
;
|
||
|
; Routine: RdBlocks, WrBlocks
|
||
|
;
|
||
|
; Function: Read/write a consecutive number of blocks from/to the disk. The I/O
|
||
|
; is done directly to/from the user's buffer. This routine is in the
|
||
|
; cache to allow future caching schemes to buffer entire files if the
|
||
|
; room exists.
|
||
|
;
|
||
|
; Input: A0.L - user parameter block ptr
|
||
|
; (A1,D1.W) - FCB pointer
|
||
|
; A2.L - VCB Ptr
|
||
|
; D3.L - disk start block
|
||
|
; D6.L - bytecount to read/write
|
||
|
;
|
||
|
; Output: D0.W - error code
|
||
|
; All other registers preserved
|
||
|
;
|
||
|
; Called by: CacheRdIP,CacheWrIP
|
||
|
;
|
||
|
;_________________________________________________________________________________
|
||
|
|
||
|
RdBlocks:
|
||
|
MOVE.L jRdBlocks,-(SP) ; jumptable entry for vRdBlocks <02Oct85>
|
||
|
RTS ; go there <02Oct85>
|
||
|
vRdBlocks ; 'vectored' RdBlocks routine <02Oct85>
|
||
|
|
||
|
MOVEQ #0,D0 ; indicate 'read' operation <01Oct85>
|
||
|
|
||
|
; RWBlksSub sets up the read/write block
|
||
|
|
||
|
RWBlksSub:
|
||
|
MOVE.L (SP)+,-(A6) ; save caller's addr <01Oct85>
|
||
|
MOVEM.L D1-D7/A0-A5,-(A6) ; Save away almost all registers on HFS stack
|
||
|
|
||
|
MOVE.L IOBuffer(A0),A5 ; user buffer address
|
||
|
ADD.L IOActCount(A0),A5 ; buffer start + count so far = target
|
||
|
|
||
|
MOVE D0,D1 ; save r/w indication
|
||
|
MOVEQ #$40,D0 ; bit 6 mask
|
||
|
AND.B IOPosMode+1(A0),D0 ; save verify mode bit
|
||
|
|
||
|
LEA Params,A0 ; fixed file system I/O param block
|
||
|
MOVE.W VCBDRefNum(A2),IORefNum(A0) ; driver refnum
|
||
|
MOVE.W VCBDrvNum(A2),IODrvNum(A0) ; tell it which drive we want
|
||
|
MOVE.L A5,IOBuffer(A0) ; buffer address
|
||
|
MOVE.L D6,IOReqCount(A0) ; block size
|
||
|
MOVE.W #1,IOPosMode(A0) ; position mode 1 (from disk start)
|
||
|
OR.B D0,IOPosMode+1(A0) ; pass verify bit on to the disk driver
|
||
|
|
||
|
MOVE.L D3,D0 ; convert from block to byte address
|
||
|
LSL.L #8,D0 ; ...x 512
|
||
|
ADD.L D0,D0 ;
|
||
|
MOVE.L D0,IOPosOffset(A0) ; absolute address
|
||
|
|
||
|
BRA BasicIO ; head for the I/O sphincter
|
||
|
|
||
|
WrBlocks:
|
||
|
MOVE.L jWrBlocks,-(SP) ; jumptable entry for vWrBlocks <02Oct85>
|
||
|
RTS ; go there <02Oct85>
|
||
|
vWrBlocks ; 'vectored' WrBlocks routine <02Oct85>
|
||
|
|
||
|
MOVE.L D5,D0 ; current file position
|
||
|
LSR.L #8,D0 ; form current file block
|
||
|
LSR.L #1,D0 ; start file block
|
||
|
BSR.S SetUpTags
|
||
|
|
||
|
MOVEQ #1,D0 ; indicate 'write' operation
|
||
|
BRA.S RWBlksSub ; share code with read
|
||
|
|
||
|
SetUpTags:
|
||
|
MOVE.L jSetUpTags,-(SP) ; jumptable entry for vSetUpTags <02Oct85>
|
||
|
RTS ; go there <02Oct85>
|
||
|
vSetUpTags ; 'vectored' SetUpTags routine <02Oct85>
|
||
|
|
||
|
TST.W D1 ; is it a file block?
|
||
|
BEQ.S @3 ; br if not
|
||
|
|
||
|
MOVE.L FCBFlNm(A1,D1),BufTgFNum ; set up file number
|
||
|
MOVE.L D0,BufTgFFlg ; ...file block number
|
||
|
MOVE.B FCBMdRByt(A1,D1),BufTgFFlg ; ...flags byte
|
||
|
|
||
|
MOVE.L FCBFType(A1,D1),HFSTagData ; set Finder file type
|
||
|
MOVE.L FCBDirID(A1,D1),HFSTagData+4 ; ...and parent DirID
|
||
|
|
||
|
@1 JSR TFSVCBTst ; is it MFS or is it HFS? <01Oct85>
|
||
|
BNE.S @4 ; br if not Memorex <01Oct85>
|
||
|
|
||
|
MOVE.L VCBWrCnt(A2),BufTgDate ; set write count in tag data <01Oct85>
|
||
|
ADDQ.L #1,VCBWrCnt(A2) ; bump volume write count <01Oct85>
|
||
|
|
||
|
@2 RTS
|
||
|
|
||
|
; set up for non-file block . . .
|
||
|
|
||
|
@3 MOVE.L D0,BufTgFFlg ; filblk = logical block on volume
|
||
|
MOVEQ #FSRtParID,D0
|
||
|
MOVE.L D0,BufTgFNum ; filnum = parent DirID of root
|
||
|
|
||
|
CLR.L HFSTagData ; no HFS tag data for volume level IO
|
||
|
CLR.L HFSTagData+4 ;
|
||
|
BRA.S @1 ; rejoin
|
||
|
|
||
|
@4 MOVE.L Time,BufTgDate ; use date for MFS <01Oct85>
|
||
|
RTS
|
||
|
|
||
|
END
|
||
|
|
||
|
|