$MOD186 $PAGELENGTH (45) $PAGEWIDTH (136) ;Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved. ;-- stored as [Eris]<LispCore>Dove>LispBoot.asm ;-- created on 30-Nov-84 13:44:00 ;-- last edited by: ;-- Lichtenberg.pa 31-Jul-85 1:32:36 ;created LispBoot.asm from Ramdskbt.asm NAME LispBoot ;-------------------------------------------------------------------------------- ; $NOLIST $INCLUDE (HardDefs.asm) ; $INCLUDE (IOPDefs.asm) ; $INCLUDE (IOPLRam.asm) $INCLUDE (RAMBDefs.asm) ; ;INCLUDE (EEPDefs.asm) ; $INCLUDE (DskIOFce.def) ; $INCLUDE (DskBDefs.asm) $INCLUDE (IOPMacro.asm) $LIST ;-------------------------------------------------------------------------------- ; Local constants: labelVerifyError EQU 23h RootPageRealPage EQU 0 SysoutVPLo EQU 0h SysoutVPHi EQU (1h OR (mesaLogicalWordOpieAddress SHL 8)) ; The equate below, "VMEMTableIORegionOffset" should be set to TWICE the value of the ; constant \Dove.VmemPageRunTableOffset, which is declared in DOVEINPUTOUTPUT. VMEMTableIORegionOffset EQU 10804 diskTimeout EQU 1650 ;-------------------------------------------------------------------------------- ;******************************************************************************** %*DEFINE (Zero (start,end)) LOCAL Lbl0 ( MOV SI, OFFSET %start %Lbl0: MOV BYTE PTR [SI], 0 INC SI CMP SI, OFFSET %end JL %Lbl0 ) ;-------------------------------------------------------------------------------- PUBLIC GermInit IORegion SEGMENT COMMON ASSUME DS:IORegion dskIOCB EQU bootDeviceIORSpace diskWorkspace EQU bootDeviceIORSpace ;from IORDisk.asm: ;------------------ EXTRN diskFCB: DiskFCBRecord ;from IORDisp.asm: ;------------------ EXTRN borderLow: BYTE EXTRN borderHigh: BYTE EXTRN chngdInfo: WORD borderChanged EQU 2000H ;from IORRAMBt.asm: ;------------------ EXTRN bootDeviceIORSpace: DiskBootArea ;from IORMaint.asm: ;------------------ EXTRN maintPanelCode: WORD EXTRN maintPanelChanged: Condition IORegion ENDS IOPEInRam SEGMENT PUBLIC ASSUME CS:IOPEInRam ASSUME DS:IORegion ASSUME ES:NOTHING ORG 0 GermInit: ; step 1 ; set up ClientCondition in disk FCB MOV BX, OFFSET diskFCB.rd0.diskIOPClientCondition MOV [BX].conditionPtr, OFFSET diskWorkspace.diskCondition MOV [BX].clientMaskPtr, 0 ; set up disk IOCB (disk characteristics and data address) MOV BX, OFFSET dskIOCB.diskOperationBlock MOV AL, diskFCB.rd0.diskSectorsPerTrack MOV [BX].diskSecPerTrack, AL MOV AL, diskFCB.rd0.diskHeadsPerCylinder MOV [BX].diskHdsPerCyl, AL MOV AX, diskFCB.rd0.diskCylindersPerDrive MOV [BX].cylPerDrive, AX MOV AX, diskFCB.rd0.diskReducedWriteCurrentCylinder MOV [BX].diskReducedWriteCyl, AX MOV AX, diskFCB.rd0.diskPreCompensationCylinder MOV [BX].diskPreCompCyl, AX JMP RamDiskCont ; put DiskRead here, so will be in first sectorSize bytes ; proc to read from disk DiskRead PROC NEAR ; calculate next disk address from DOB (prev. address and label) CalcNextAddr: MOV BX, OFFSET dskIOCB.diskOperationBlock MOV AX, WORD PTR [BX].diskLabel.diskDontCare MOV CX, WORD PTR [BX].diskLabel.diskDontCare+2 TEST AX, CX JZ IncrPrevAddress CMP AX, 0FFFFH JNE UseAddressInAXCX ; end-of-file: set carry and return XOR AX,AX STC RET ; secondary entry point for new file -- disk address in AX:CX DiskReadNewFile: MOV BX, OFFSET dskIOCB.diskOperationBlock ; AX:CX contains next sector address: store into DOB UseAddressInAXCX: MOV WORD PTR [BX].diskHeader, AX MOV WORD PTR [BX].diskHeader+2, CX JMP SHORT InitIOCB ; label contains nil: increment previous address IncrPrevAddress: JMP SHORT InitIOCB MOV CX, WORD PTR [BX].diskHeader+2 INC CL CMP CL, [BX].diskSecPerTrack JL StoreNewAddress XOR CL, CL INC CH CMP CH, [BX].diskHdsPerCyl JL StoreNewAddress XOR CH, CH INC [BX].diskHeader.diskCylinder StoreNewAddress: MOV WORD PTR [BX].diskHeader+2, CX ; initialize other IOCB fields InitIOCB: MOV AL, read InitIOCBCont: %Zero (dskIOCB.diskDataInfoRec+2, dskIOCB.diskOperationBlock) MOV dskIOCB.diskDataXferDirection, AL MOV AX,CS:RunLength MOV dskIOCB.diskPageCount, AX NOT AX INC AX MOV [BX].diskMinusSectorCount, AX MOV [BX].diskHeaderError, 0 MOV [BX].diskLabelError, 0 MOV [BX].diskDataError, 0 MOV [BX].diskLastError, 0 ; put IOCB onto disk queue EnqueueIOCB: MOV diskFCB.rd0.diskIOPNextLow, OFFSET dskIOCB MOV diskFCB.rd0.diskIOPNextHigh, (IOPIORegionOpieAddress SHL 8) ; wake up handler and wait for return notify %NotifyCondition (OFFSET diskFCB.diskConditionWork) %WaitForCondition (OFFSET diskWorkspace.diskCondition,noTimeout) ; CMP AL,conditionTimeout ; must be an error... ; JZ DiskReadError ; check for good completion TEST dskIOCB.diskError, 0FFH JNZ DiskReadError CMP diskFCB.diskHandlerState, normalDiskHandlerState JE DiskReadDone MOV diskFCB.diskHandlerState, normalDiskHandlerState ; determine error type (eventually -- just retry for now): ; (a) CRC error -- retry ; (b) wrong cylinder error -- recalibrate, retry ; (c) other errors -- ? ; Check for label verify error... it's special. DiskReadError: MOV diskFCB.diskStartHandlerForIOP, 0FFFFH MOV BX,OFFSET dskIOCB.diskOperationBlock CMP WORD PTR [BX].diskLastError, labelVerifyError JZ SHORT labelError DEC cs:LispBootRetryCount JZ SHORT TooManyRetries JMP InitIOCB DiskReadDone: XOR AX,AX CLC RET labelError: MOV diskFCB.rd0.diskIOPNextLow, 0 MOV diskFCB.rd0.diskIOPNextHigh, 0 MOV diskFCB.diskHandlerState, normalDiskHandlerState MOV AX,labelVerifyError STC RET ;if too many retries, start over from the beginning (at OpieReentry) TooManyRetries: mov maintPanelCode,2217 %NotifyCondition (OFFSET maintPanelChanged) %WaitForSystem ; gives opie a chance to run the mp handler Forever: JMP Forever DiskRead ENDP ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- RamDiskCont: MOV borderHigh, 0 MOV borderLow, 0 OR chngdInfo, borderChanged MOV maintPanelCode, 1000 %NotifyCondition (OFFSET maintPanelChanged) ; This step initializes the VtblCurrentOffset variable, which is used by the ; MakeEntryInVmemTable routine for collecting the runs of pages in the sysout. MOV AX,VMEMTableIORegionOffset MOV CS:VtblCurrentOffset,AX MOV CS:RunLength, 1 MOV BX,OFFSET dskIOCB.diskOperationBlock MOV [BX].diskOperation,ReadDiskLabelAndData ; The next major step is to load in the root page, which is at a known physical disk ; address. This sector is going to be loaded into real page zero. MOV BX, OFFSET dskIOCB.diskOperationBlock MOV AX, rootPageCylinder MOV CX, rootPageHeadAndSector MOV dskIOCB.diskDataPtrLow, RootPageRealPage MOV dskIOCB.diskDataPtrHigh, (extendedBusOpieAddress SHL 8) MOV dskIOCB.diskDataInfoRec,0 ; clear out flags OR dskIOCB.diskDataInfoRec, MASK diskUseLEDs ; pretty lights. MOV cs:LispBootRetryCount, 10 ReadRootPage: CALL DiskReadNewFile ; We've read in the root page. Time to look up the pilot boot file on the page. MOV CX,(extendedBusOpieAddress SHL 8) MOV DX,RootPageRealPage %EstablishIOPAccess(generalMapRegister,CX-DX) ADD DI, rootPageHeaderSize ; set up for 1st file ID (diagnostics) MOV CH, ES:[DI].DFIDcylinderHigh MOV CL, ES:[DI].DFIDcylinderLow MOV DH, ES:[DI].DFIDhead MOV DL, ES:[DI].DFIDsector ; CX-DX contains the sysout DA. MOV cs:sysoutDACyl,CX MOV cs:sysoutDAHdSect,DX inc maintPanelCode %NotifyCondition (OFFSET maintPanelChanged) ; load one complete file MOV cs:LispBootRetryCount, 10 ; Read first sector of file into starting address of Vmem ; Make the first entry in the table. MOV AX,0 ; file page zero MOV CX,cs:sysoutDACyl MOV DX,cs:sysoutDAHdSect CALL MakeEntryInVmemTable ; Load file. MOV BX, OFFSET dskIOCB.diskOperationBlock MOV AX,cs:sysoutDACyl MOV CX,cs:sysoutDAHdSect MOV dskIOCB.diskDataPtrLow, SysoutVPLo MOV dskIOCB.diskDataPtrHigh,SysoutVPHi OR dskIOCB.diskDataInfoRec, MASK incrementDataPtr CALL DiskReadNewFile JNC DiskGotFirstPage DiskErrorFirstPage: JMP TooManyRetries DiskGotFirstPage: ; The first page of the file is a waste (it's a leader page) ; Back up the data ptr to the beginning call BackUpDataPtr mov maintPanelCode,1000 ; We've read the first sector of the file into memory. If we get here, the data ; ptr should be pointing at page 100h, ; Now, loop and read in the rest of it. ; To speed reading the sysout in, we're going to transfer 100 pages at a shot. LoadSectorLoop: MOV BX, OFFSET dskIOCB.diskOperationBlock MOV cs:RunLength, 100 MOV [BX].diskOperation, ReadDiskData ; That's a VVR for real people. inc maintPanelCode %NotifyCondition (OFFSET maintPanelChanged) CALL DiskRead JC LoadSectorLoopExit ; For some reason it looks like the disk controller code is either reading ; one page too little or advancing too much. Backing up the data ptr ; will keep it on track. PUSH AX CALL BackUpDataPtr POP AX JMP LoadSectorLoop LoadSectorLoopExit: ; Some kind of error has happened. If a label verify, check for end else end. CMP AX,labelVerifyError ; label error? JNZ SHORT AllDone ; must be at end of file ; Temporary - first label verify means all done JMP SHORT AllDone ; Check for end of file. MOV BX, OFFSET dskIOCB.diskOperationBlock MOV AX, WORD PTR [BX].diskLabel.diskFilePageLow MOV CX, WORD PTR [BX].diskLabel.diskDontCare MOV DX, WORD PTR [BX].diskLabel.diskDontCare+2 CMP CX, 0FFFFH JZ SHORT AllDone ; really got an EOF. CALL MakeEntryInVmemTable MOV WORD PTR [BX].diskHeader, CX MOV WORD PTR [BX].diskHeader+2, DX MOV WORD PTR [BX].diskLabel.diskDontCare, 0 MOV WORD PTR [BX].diskLabel.diskDontCare+2, 0 JMP LoadSectorLoop ; All done. AllDone: mov maintPanelCode,1111 %NotifyCondition (OFFSET maintPanelChanged) MOV diskFCB.rd0.diskIOPNextLow, 0 MOV diskFCB.rd0.diskIOPNextHigh, 0 MOV diskFCB.diskStartHandlerForIOP,0 MOV diskFCB.diskStartHandlerForMesa,0FFFFH RET ;-------------------------------------------------------------------------------- ; Subroutine BackUpDataPtr - backs up the data ptr in the IOCB by one page BackUpDataPtr: MOV AX,dskIOCB.diskDataPtrLow MOV CX,dskIOCB.diskDataPtrHigh DEC AH CMP AX,0FFh ; did we underflow? JNZ SHORT BackupXit MOV AH,0 DEC CL BackupXit: MOV dskIOCB.diskDataPtrLow, AX MOV dskIOCB.diskDataPtrHigh, CX RET ;-------------------------------------------------------------------------------- ; The following local subroutine makes entries in the VMEM table in the IORegion ; Calling parameters: ; AX = file page number ; CX = Cylinder of disk address ; DX = Head/Sector of disk address ; The format of an entry in the table is: ; ; ---> [fphi,fplo] file page hi,lo (one word) ; [cylhi,cyllo] cylinder number (one word) ; [hd,sec] head and sector (one byte each) ; [fphi,fplo] next entry's fphi and fplo or 0 for end of table MakeEntryInVmemTable: PUSH DI ; save old DI MOV DI,cs:VtblCurrentOffset ; get current loc in tbl MOV BYTE PTR DS:[DI]+0,AH ; file page MOV BYTE PTR DS:[DI]+1,AL MOV BYTE PTR DS:[DI]+2,CH ; cylinder MOV BYTE PTR DS:[DI]+3,CL MOV BYTE PTR DS:[DI]+4,DH ; hd/sec MOV BYTE PTR DS:[DI]+5,DL MOV BYTE PTR DS:[DI]+6,0 ; in case it's the last one MOV BYTE PTR DS:[DI]+7,0 ADD cs:VtblCurrentOffset,6 ; point VtblCurrentOffset at next one POP DI RET ;-------------------------------------------------------------------------------- ; LOCAL STORAGE: EVEN ; 80186 likes this. sysoutDACyl DW ? ; DA of first page of sysout sysoutDAHdSect DW ? LispBootRetryCount DB ? DB ? VtblCurrentOffset DW ? hundredsCounter DW ? RunLength DW ? IOPEInRam ENDS END