-- Cedar Remote Debugging: MapLog handling

-- WVMMapLog.mesa

-- Andrew Birrell September 30, 1982 10:40 am

DIRECTORY
CPSwapDefs  USING[ ExternalStateVector, SwapInfo ],
PSB    USING[ PDA ],
VMMapLog,
WorldVM  USING[Address, CopyRead, World],
WVMPrivate;

WVMMapLog: MONITOR
IMPORTS WorldVM, WVMPrivate
EXPORTS WVMPrivate, WorldVM =

BEGIN

MapLogObject: PUBLIC TYPE = RECORD[
found: CARDINAL ← 0, -- maplog entries read in so far --
entries: REF Entries];

MapLog: TYPE = REF MapLogObject;

Entries: TYPE = RECORD[ SEQUENCE length: CARDINAL OF Entry ];

Entry: TYPE = VMMapLog.Entry ← NULL;

CreateMapLog: PUBLIC PROC[world: WorldVM.World] RETURNS[ MapLog ] =
BEGIN
RETURN[NEW[MapLogObject ← [0,NIL]]]
END;

ReadMapLog: PUBLIC PROC[world: WorldVM.World, log: MapLog]
RETURNS[patchTable, loadState: WorldVM.Address] =
BEGIN
swapInfo: CPSwapDefs.SwapInfo;
swapInfoAddr: WorldVM.Address = LOOPHOLE[@PSB.PDA.available];
esv: CPSwapDefs.ExternalStateVector;
esvAddr: WorldVM.Address;
descr: VMMapLog.Descriptor;
descrAddr: WorldVM.Address;
logBase: WorldVM.Address;
logSize: CARDINAL; -- number of entries, excluding self --
WorldVM.CopyRead[world, swapInfoAddr, SIZE[CPSwapDefs.SwapInfo],
@swapInfo];
esvAddr ← LOOPHOLE[swapInfo.externalStateVector];
WorldVM.CopyRead[world, esvAddr, SIZE[CPSwapDefs.ExternalStateVector],
@esv];
loadState ← WVMPrivate.PageAddress[esv.loadstatepage];
descrAddr ← LOOPHOLE[esv.mapLog];
WorldVM.CopyRead[world, descrAddr, SIZE[VMMapLog.Descriptor],
@descr];
patchTable ← LOOPHOLE[descr.patchTable];
logBase ← WVMPrivate.PageAddress[descr.self.page];
logSize ← LOOPHOLE[descr.limit, CARDINAL] / SIZE[VMMapLog.Entry];
log.entries ← NEW[Entries[logSize+1--self--]];
log.entries[0] ← descr.self;
log.found ← 1;
BEGIN
used: CARDINAL = MIN[logSize,
(descr.writer - descr.reader) / SIZE[VMMapLog.Entry] ];
IF logBase # 0 AND logSize > 0
THEN WorldVM.CopyRead[world, logBase, used*SIZE[VMMapLog.Entry],
@log.entries[1]]; -- may call GetMapLogEntry --
log.found ← log.found+used;
END;
END;

LocalPatchTable: PUBLIC PROC RETURNS[patchTable: WorldVM.Address] =
BEGIN
swapInfo: LONG POINTER TO CPSwapDefs.SwapInfo = LOOPHOLE[@PSB.PDA.available];
descr: LONG POINTER TO VMMapLog.Descriptor =
swapInfo.externalStateVector.mapLog;
RETURN[LOOPHOLE[descr.patchTable]]
END;

AddressFault: PUBLIC ERROR[mempage: WVMPrivate.PageNumber] = CODE;

lastEntryIndex: CARDINAL ← 0; -- hint for log entry to try first --

GetMapLogEntry: PUBLIC ENTRY PROC[log: MapLog, mempage: WVMPrivate.PageNumber]
RETURNS[ WVMPrivate.DiskAddress ] =
BEGIN
ENABLE UNWIND => NULL;
entry: LONG POINTER TO Entry ←
IF lastEntryIndex IN [0..log.found) -- lastEntryIndex may be for another log!
THEN @log.entries[lastEntryIndex]
ELSE NIL;
IF entry = NIL
OR entry.kind = nil
OR mempage NOT IN [entry.page..entry.page+entry.count)
THEN -- sigh! Need to search for it. --
BEGIN
FOR i: CARDINAL IN [0..log.found)
DO entry ← @log.entries[lastEntryIndex←i];
IF entry.kind # nil
AND mempage IN [entry.page..entry.page+entry.count)
THEN EXIT;
REPEAT FINISHED => ERROR AddressFault[mempage]
ENDLOOP;
END;
WITH e: entry SELECT FROM
disk => RETURN[[e.driveTag, e.diskPage, mempage-e.page, e.labelCheck]];
ENDCASE => ERROR AddressFault[mempage]
END;

END.