-- 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.