-- DiskKD.Mesa Edited by Sandman on July 1, 1980 7:54 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AllocDefs USING [AddSwapStrategy, CantSwap, SwappingProcedure, SwapStrategy], AltoDefs USING [PageCount, PageSize, wordlength], AltoFileDefs USING [DirFP, DISK, DiskShape, FIP, KD, LD, SN, vDA], SwapperOps USING [BootFile], DirectoryDefs USING [DirectoryLookup], DiskDefs USING [sysDisk], DiskKDDefs USING [], ImageDefs USING [ AddCleanupProcedure, CleanupItem, CleanupMask, CleanupProcedure], InlineDefs USING [BITAND, BITNOT, BITOR, BITSHIFT], NucleusOps USING [], SegmentDefs USING [ DefaultBase, DeleteFileSegment, FileHandle, FileNameError, FileSegmentAddress, FileSegmentHandle, MoveFileSegment, NewFileSegment, Read, SwapIn, SwapOut, SwapUp, Unlock, Write]; DiskKD: PROGRAM IMPORTS AllocDefs, SwapperOps, DirectoryDefs, DiskDefs, ImageDefs, InlineDefs, SegmentDefs EXPORTS DiskKDDefs, NucleusOps = BEGIN OPEN AltoDefs, AltoFileDefs, SegmentDefs; InitializeDiskKD: PUBLIC PROCEDURE = BEGIN nameKD: STRING = "DiskDescriptor."L; pages: PageCount; SetDiskFromSysDir[]; IF ~DirectoryDefs.DirectoryLookup[@diskKD.file.fp, nameKD, FALSE] THEN SIGNAL FileNameError[nameKD]; MoveFileSegment[diskKD, DefaultBase, 1]; OpenDiskKD[]; DiskDefs.sysDisk ← kd.disk; pages ← (kd.size + PageSize - 1)/PageSize; [] ← CloseDiskKD[]; MoveFileSegment[diskKD, DefaultBase, pages]; RETURN END; SetDiskFromSysDir: PROCEDURE = BEGIN OPEN SegmentDefs; sysdir: FileSegmentHandle ← NewFileSegment[ SwapperOps.BootFile[Read], 0, 1, Read]; leader: POINTER TO AltoFileDefs.LD; prop: POINTER TO ARRAY OF AltoFileDefs.FIP; i: CARDINAL; sysdir.file.fp ← AltoFileDefs.DirFP; sysdir.file.open ← TRUE; SwapIn[sysdir]; leader ← FileSegmentAddress[sysdir]; prop ← LOOPHOLE[leader, POINTER] + leader.propBegin; FOR i ← 0, i + prop[i].length UNTIL prop[i].length = 0 OR i >= leader.propLength DO IF prop[i].type = AltoFileDefs.DiskShape THEN BEGIN DiskDefs.sysDisk ← LOOPHOLE[@prop[i] + 1, POINTER TO AltoFileDefs.DISK]↑; EXIT END; ENDLOOP; Unlock[sysdir]; DeleteFileSegment[sysdir]; RETURN END; OpenDiskKD: PROCEDURE = BEGIN IF ~diskKD.swappedin THEN BEGIN SwapIn[diskKD]; kd ← FileSegmentAddress[diskKD]; kd.changed ← 0; END ELSE swapKD.proc ← AllocDefs.CantSwap; RETURN END; UpdateDiskKD: PUBLIC PROCEDURE = BEGIN IF diskKD.swappedin AND kd.changed # 0 THEN BEGIN diskKD.write ← TRUE; kd.changed ← 0; SwapUp[diskKD]; diskKD.write ← FALSE; END; RETURN END; CloseDiskKD: PUBLIC PROCEDURE RETURNS [BOOLEAN] = BEGIN IF ~diskKD.swappedin THEN RETURN[FALSE]; swapKD.proc ← AllocDefs.CantSwap; UpdateDiskKD[]; Unlock[diskKD]; SwapOut[diskKD]; RETURN[TRUE] END; DiskKDSwapper: AllocDefs.SwappingProcedure = BEGIN RETURN[CloseDiskKD[]]; END; CleanupDiskKD: PUBLIC ImageDefs.CleanupProcedure = BEGIN SELECT why FROM Finish, Abort, OutLd => [] ← CloseDiskKD[]; -- Save => -- We depend on MakeImage to call CloseDiskKD when -- it has finished allocating the image file pages. -- Logically, it should also call ResetDisk at this -- time, but it can't do that until the Restore. -- Restore => -- We depend on MakeImage to call InitializeDiskKD -- as soon as the image file starts up so that the -- Real to Virtual disk address map can be set up. ENDCASE; RETURN END; AllOnes: WORD = 177777B; NewSN: PUBLIC PROCEDURE RETURNS [sn: SN] = BEGIN OpenDiskKD[]; IF (kd.lastSN.part2 ← kd.lastSN.part2 + 1) = 0 THEN kd.lastSN.part1 ← kd.lastSN.part1 + 1; sn ← kd.lastSN; kd.changed ← AllOnes; swapKD.proc ← DiskKDSwapper; RETURN END; BitAddress: TYPE = RECORD [word: [0..7777B], bit: [0..17B]]; DiskFull: PUBLIC SIGNAL = CODE; AssignDiskPage: PUBLIC PROCEDURE [da: vDA] RETURNS [vDA] = BEGIN OPEN InlineDefs; onebit: WORD; wa: CARDINAL; ba: [0..16); w: POINTER TO WORD; base: BitAddress = LOOPHOLE[da + 1]; baseWa: CARDINAL ← base.word; baseBa: CARDINAL ← base.bit; OpenDiskKD[]; DO ENABLE UNWIND => swapKD.proc ← DiskKDSwapper; FOR wa IN [baseWa..kd.size) DO IF (w ← @kd.table[wa])↑ # AllOnes THEN FOR ba IN [baseBa..wordlength) DO onebit ← BITSHIFT[100000B, -ba]; IF BITAND[w↑, onebit] = 0 THEN BEGIN w↑ ← BITOR[w↑, onebit]; kd.changed ← AllOnes; kd.freePages ← MAX[kd.freePages, 1] - 1; swapKD.proc ← DiskKDSwapper; RETURN[vDA[wa*wordlength + ba]]; END; ENDLOOP; baseBa ← 0; ENDLOOP; IF baseWa = 0 THEN BEGIN [] ← CloseDiskKD[]; SIGNAL DiskFull; OpenDiskKD[]; END; baseWa ← 0; ENDLOOP; END; ReleaseDiskPage: PUBLIC PROCEDURE [v: vDA] = BEGIN OPEN InlineDefs; word: POINTER TO WORD; mask: WORD = BITSHIFT[100000B, -LOOPHOLE[v, BitAddress].bit]; OpenDiskKD[]; word ← @kd.table[LOOPHOLE[v, BitAddress].word]; IF BITAND[word↑, mask] # 0 THEN BEGIN word↑ ← BITAND[word↑, BITNOT[mask]]; kd.changed ← AllOnes; kd.freePages ← kd.freePages + 1; END; swapKD.proc ← DiskKDSwapper; RETURN END; CountFreeDiskPages: PUBLIC PROCEDURE RETURNS [count: CARDINAL] = BEGIN OpenDiskKD[]; count ← kd.freePages; swapKD.proc ← DiskKDSwapper; RETURN END; kd: POINTER TO KD; swapKD: AllocDefs.SwapStrategy; diskKD: FileSegmentHandle; cleanupKD: ImageDefs.CleanupItem; swapKD.proc ← AllocDefs.CantSwap; cleanupKD.proc ← CleanupDiskKD; cleanupKD.mask ← ImageDefs.CleanupMask[Finish] + ImageDefs.CleanupMask[Abort] + ImageDefs.CleanupMask[OutLd]; diskKD ← NewFileSegment[ SwapperOps.BootFile[Read + Write], DefaultBase, 1, Read]; AllocDefs.AddSwapStrategy[@swapKD]; ImageDefs.AddCleanupProcedure[@cleanupKD]; InitializeDiskKD[]; -- Should we support running without a DiskDescriptor? END.