MBScript.mesa
Edited by Sandman on 6-Aug-81 15:42:29
Edited by Lewis on 17-Sep-81 16:15:24
Edited by Levin on April 5, 1983 3:42 pm
DIRECTORY
BcdDefs USING [Base],
BcdOps USING [BcdBase, FPHandle, MTHandle, SPHandle],
BootFile USING [MemorySizeToFileSize],
Environment USING [bitsPerWord, wordsPerPage],
Inline USING [LongCOPY],
MB
USING [
BHandle, BIndex, BitArray, DumpSegs, EnumerateBCDs, EnumerateCode, EnumerateFramePacks, EnumerateGlobalFrames, EnumerateSpaces, Handle, nullIndex, VirtualGlobalFrame, Zero],
MBStorage USING [FreeMDSPages, FreePages, FreeWords, MDSPages, PagesForWords, Words],
MBVM
USING [
AllocMDSData, Base, CodeSeg, CopyWrite, DataSeg, FileSeg, MDS, Pages, PointerFromSeg, Seg, SortSegs],
PrincOps USING [GlobalFrameHandle],
StartList
USING [
BackingLocation, Entry, Header, Index, NullSpaceIndex, NullSwapUnitIndex, SpaceIndex, SpaceType, StartIndex, SwapUnitIndex, SwapUnitInfo, SwapUnitState, Base, VersionID];
MBScript:
PROGRAM
IMPORTS BootFile, Inline, MB, MBStorage, MBVM
EXPORTS MB =
BEGIN
OPEN StartList;
PageSize: CARDINAL = Environment.wordsPerPage;
PageState: TYPE = RECORD [busy, resident, in, readOnly, mds, first64K: BOOL];
data: MB.Handle ← NIL;
segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg;
residentTable, resDescTable, inTable, readOnlyTable: MB.BitArray ← NIL;
suIndex: SwapUnitIndex;
Wart Script Management
scriptIndex: Index;
tablePages: CARDINAL;
scriptBase: StartList.Base;
header: LONG POINTER TO Header;
InitScript:
PUBLIC
PROC [h:
MB.Handle] = {
data ← h;
header ← data.zone.NEW[Header];
MB.Zero[header, SIZE[Header]];
data.header ← header;
header.version ← VersionID;
scriptIndex ← StartList.StartIndex;
tablePages ← 0;
scriptBase ← NIL;
};
FinishScript:
PUBLIC
PROC = {
OPEN MBStorage;
IF residentTable ~= NIL THEN {FreeWords[BASE[residentTable]]; residentTable ← NIL};
IF resDescTable ~= NIL THEN {FreeWords[BASE[resDescTable]]; resDescTable ← NIL};
IF inTable ~= NIL THEN {FreeWords[BASE[inTable]]; inTable ← NIL};
IF readOnlyTable ~= NIL THEN {FreeWords[BASE[readOnlyTable]]; readOnlyTable ← NIL};
IF header ~= NIL THEN data.zone.FREE[@header];
IF scriptBase ~= NIL THEN {FreeMDSPages[scriptBase]; scriptBase ← NIL};
data ← NIL;
};
InitBitTables:
PROC [length:
CARDINAL] = {
OPEN MBStorage;
wordsForTable: CARDINAL = (length+Environment.bitsPerWord-1)/Environment.bitsPerWord;
residentTable ← DESCRIPTOR[Words[wordsForTable], length];
MB.Zero[BASE[residentTable], wordsForTable];
resDescTable ← DESCRIPTOR[Words[wordsForTable], length];
MB.Zero[BASE[resDescTable], wordsForTable];
inTable ← DESCRIPTOR[Words[wordsForTable], length];
MB.Zero[BASE[inTable], wordsForTable];
readOnlyTable ← DESCRIPTOR[Words[wordsForTable], length];
MB.Zero[BASE[readOnlyTable], wordsForTable];
};
MakeScript:
PUBLIC
PROC = {
r: stop Entry ← Entry[stop[]];
nSpaces: CARDINAL ← 0;
state: PageState ← [FALSE, FALSE, FALSE, FALSE, FALSE, FALSE];
inMDS, inFirst64K: BOOL;
mdsBase: CARDINAL = data.mdsBase;
newState: PageState;
i, nwords, start: CARDINAL;
tableSeg: MBVM.DataSeg;
segs ← MBVM.SortSegs[];
InitBitTables[LENGTH[data.vmMap]];
Beyond this point it is assumed that the vmMap won't grow.
FOR i IN [0..LENGTH[segs]) DO AddToBitTables[segs[i]] ENDLOOP;
ClassifyPages[];
FOR i
IN [0..data.lastVMPage]
DO
inMDS ← (i IN [mdsBase..mdsBase+255]);
inFirst64K ← (i IN [0..255]);
newState ← [
busy: data.vmMap[i], resident: residentTable[i], in: inTable[i],
readOnly: readOnlyTable[i], mds: inMDS, first64K: inFirst64K
];
IF newState # state THEN {state ← newState; nSpaces ← nSpaces + 1};
ENDLOOP;
nwords ← 0;
FOR i
IN [0..
LENGTH[segs])
DO
WITH seg: segs[i]
SELECT
FROM
data => nwords ← nwords + SIZE[swapUnit Entry];
code =>
nwords ← nwords +
(IF seg.sph # NIL THEN seg.sph.length*SIZE[swapUnit Entry] ELSE SIZE[swapUnit Entry]);
file =>
IF seg.bIndex = MB.nullIndex THEN nwords ← nwords + SIZE[swapUnit Entry]
ELSE {
loadee: MB.BHandle = data.inputBCDs.bcds[seg.bIndex];
IF loadee.bcd.rtPages.pages ~= 0 THEN nwords ← nwords + 2*SIZE[swapUnit Entry]
ELSE nwords ← nwords + SIZE[swapUnit Entry];
};
ENDCASE;
ENDLOOP;
nwords ← (nwords + SIZE[Header] + 16 + nSpaces*SIZE[space Entry]);
AddScriptWords[nwords];
Since the initial vmMap includes the MDS, the following can't cause it to grow
therefore, our bit tables won't need to grow any bigger.
tableSeg ← MBVM.AllocMDSData[base: MBVM.MDS, pages: tablePages]; -- this won't expand vmMap
tableSeg.bootLoaded ← TRUE;
tableSeg.info ← [readOnly: FALSE, state: swappable];
AddToBitTables[tableSeg];
header.table ← MBVM.PointerFromSeg[tableSeg];
MBStorage.FreePages[BASE[segs]];
segs ← MBVM.SortSegs[];
FOR i IN [0..LENGTH[segs]) DO EnterSegment[segs[i]] ENDLOOP;
IF data.debug THEN MB.DumpSegs[segs, "SCRIPT CONSTRUCTION"L];
state ← [
busy: data.vmMap[0], resident: residentTable[0], in: inTable[0],
readOnly: readOnlyTable[0], mds: mdsBase = 0, first64K: TRUE
];
start ← 0;
suIndex ← LOOPHOLE[StartIndex];
FOR i
IN [1..data.lastVMPage]
DO
inMDS ← i IN [mdsBase..mdsBase+255];
inFirst64K ← i IN [0..255];
newState ← [
busy: data.vmMap[i], resident: residentTable[i], in: inTable[i],
readOnly: readOnlyTable[i], mds: inMDS, first64K: inFirst64K
];
IF newState # state THEN {AddSpace[state, start, i-1]; start ← i; state ← newState};
ENDLOOP;
AddSpace[state, start, data.lastVMPage];
AppendBootWords[@r, SIZE[stop Entry]];
[lastBootedPage: header.lastBootLoadedPage, nBootPages: data.nBootPages, nFilePages: data.nFilePages]
← PreScanSegs[segs];
MBStorage.FreePages[BASE[segs]];
header.mdsBase ← data.mdsBase;
header.pdaPages ← data.pdaPages;
header.loadState ← NullSwapUnitIndex;
header.initLoadState ← data.lsseg.index;
header.lastVMPage ← data.lastVMPage;
header.stateVectorCounts ← data.stateVectorCounts;
header.stateVectorSize ← data.svSize;
header.nProcesses ← data.nProcesses;
scriptBase^ ← header^;
MBVM.CopyWrite[from: scriptBase, to: header.table, nwords: PageSize*tablePages];
};
AddToBitTables:
PROC [seg:
MBVM.Seg] = {
resDesc: BOOL = (seg.info.state = residentDescriptor);
resident: BOOL = (seg.info.state = resident);
FOR i:
CARDINAL
IN [seg.base..seg.base+seg.pages)
DO
readOnlyTable[i] ← seg.info.readOnly;
inTable[i] ← seg.bootLoaded;
resDescTable[i] ← resDesc;
residentTable[i] ← resident;
ENDLOOP;
ClassifyPages:
PROC = {
MB.EnumerateCode[in, BootLoadCode];
MB.EnumerateSpaces[in, BootLoadSpaces];
MB.EnumerateFramePacks[in, BootLoadFramePacks];
MB.EnumerateGlobalFrames[in, BootLoadGlobalFrames];
MB.EnumerateBCDs[in, BootLoadBCDs];
MB.EnumerateCode[resDesc, ResDescCode];
MB.EnumerateSpaces[resDesc, ResDescSpaces];
MB.EnumerateFramePacks[resDesc, ResDescFramePacks];
MB.EnumerateGlobalFrames[resDesc, ResDescGlobalFrames];
MB.EnumerateBCDs[resDesc, ResDescBCDs];
MB.EnumerateCode[resident, ResidentCode];
MB.EnumerateSpaces[resident, ResidentSpaces];
-- resident FramePacks and GlobalFrames were done during loading--
MB.EnumerateBCDs[resident, ResidentBCDs];
};
BootLoadCode:
PROC [bh:
MB.BHandle, mth: BcdOps.MTHandle]
RETURNS [
BOOL] = {
cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code;
MarkSegPages[cseg, @inTable];
RETURN[FALSE]
};
BootLoadSpaces:
PROC [bh:
MB.BHandle, sph: BcdOps.SPHandle, index:
CARDINAL]
RETURNS [BOOL] = {
MarkSpacePages[sph, index, @inTable];
RETURN[FALSE]
};
BootLoadFramePacks:
PROC [bh:
MB.BHandle, fph: BcdOps.FPHandle]
RETURNS [
BOOL] = {
mtb: BcdDefs.Base = LOOPHOLE[bh.bcd + bh.bcd.mtOffset];
RETURN[BootLoadGlobalFrames[bh, @mtb[fph.modules[0]]]]
};
BootLoadGlobalFrames:
PROC [bh:
MB.BHandle, mth: BcdOps.MTHandle]
RETURNS [
BOOL] = {
frame: PrincOps.GlobalFrameHandle = bh.mt[mth.gfi].frame;
IF ~
MB.VirtualGlobalFrame[frame].alloced
THEN
MarkSegPages[SegForBase[PageFromAddress[frame] + data.mdsBase], @inTable];
RETURN[FALSE]
};
BootLoadBCDs:
PROC [bh:
MB.BHandle]
RETURNS [
BOOL] = {
bcdSeg: MBVM.FileSeg = bh.bcdSeg;
MarkSegPages[bcdSeg, @inTable];
RETURN[FALSE]
};
ResDescCode:
PROC [bh:
MB.BHandle, mth: BcdOps.MTHandle]
RETURNS [
BOOL] = {
cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code;
cseg.info.state ← residentDescriptor;
MarkSegPages[cseg, @resDescTable];
RETURN[FALSE]
};
ResDescSpaces:
PROC [bh:
MB.BHandle, sph: BcdOps.SPHandle, index:
CARDINAL]
RETURNS [BOOL] = {
MarkSpacePages[sph, index, @resDescTable];
RETURN[FALSE]
};
ResDescFramePacks:
PROC [bh:
MB.BHandle, fph: BcdOps.FPHandle]
RETURNS [
BOOL] = {
mtb: BcdDefs.Base = LOOPHOLE[bh.bcd + bh.bcd.mtOffset];
RETURN[ResDescGlobalFrames[bh, @mtb[fph.modules[0]]]]};
ResDescGlobalFrames:
PROC [bh:
MB.BHandle, mth: BcdOps.MTHandle]
RETURNS [
BOOL] = {
frame: PrincOps.GlobalFrameHandle = bh.mt[mth.gfi].frame;
IF ~
MB.VirtualGlobalFrame[frame].alloced
THEN
MarkSegPages[SegForBase[PageFromAddress[frame] + data.mdsBase], @resDescTable];
RETURN[FALSE]
};
ResDescBCDs:
PROC [bh:
MB.BHandle]
RETURNS [
BOOL] = {
bcdSeg: MBVM.FileSeg = bh.bcdSeg;
bcdSeg.info.state ← residentDescriptor;
MarkSegPages[bcdSeg, @resDescTable];
RETURN[FALSE]
};
ResidentCode:
PROC [bh:
MB.BHandle, mth: BcdOps.MTHandle]
RETURNS [
BOOL] = {
cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code;
cseg.info.state ← resident;
MarkSegPages[cseg, @residentTable];
MarkSegPages[cseg, @inTable];
RETURN[FALSE]
};
ResidentSpaces:
PROC [bh:
MB.BHandle, sph: BcdOps.SPHandle, index:
CARDINAL]
RETURNS [BOOL] = {
cseg: MBVM.CodeSeg = SegForSpace[sph];
first: CARDINAL = cseg.base+sph.spaces[index].offset;
count: CARDINAL = sph.spaces[index].pages;
MarkTablePages[@residentTable, first, count];
MarkTablePages[@inTable, first, count];
RETURN[FALSE]
};
ResidentBCDs:
PROC [bh:
MB.BHandle]
RETURNS [
BOOL] = {
bcdSeg: MBVM.FileSeg = bh.bcdSeg;
bcdSeg.info.state ← resident;
MarkSegPages[bcdSeg, @residentTable];
MarkSegPages[bcdSeg, @inTable];
RETURN[FALSE]
};
MarkSegPages:
PROC [seg:
MBVM.Seg, table:
POINTER
TO
MB.BitArray] =
INLINE {
MarkTablePages[table, seg.base, seg.pages]};
MarkSpacePages:
PROC [
sph: BcdOps.SPHandle, index: CARDINAL, table: POINTER TO MB.BitArray] = {
cseg: MBVM.CodeSeg = SegForSpace[sph];
MarkTablePages[table, cseg.base + sph.spaces[index].offset, sph.spaces[index].pages]
};
MarkTablePages:
PROC [table:
POINTER
TO
MB.BitArray, first, count:
CARDINAL] = {
FOR i:
CARDINAL
IN [first..first+count)
DO
table^[i] ← TRUE;
ENDLOOP;
SegForBase:
PROC [base:
CARDINAL]
RETURNS [seg:
MBVM.Seg] = {
FOR i:
CARDINAL
IN [0..
LENGTH[segs])
DO
seg ← segs[i];
IF base IN [seg.base..seg.base+seg.pages) THEN EXIT;
REPEAT
FINISHED => ERROR;
ENDLOOP;
SegForSpace:
PROC [sph: BcdOps.SPHandle]
RETURNS [cseg:
MBVM.CodeSeg] = {
FOR i:
CARDINAL
IN [0..
LENGTH[segs])
DO
WITH s: segs[i]
SELECT
FROM
code => IF s.sph = sph THEN {cseg ← @s; EXIT};
ENDCASE;
REPEAT
FINISHED => ERROR;
ENDLOOP;
AddScriptWords:
PROC [nwords:
CARDINAL] = {
newPages: CARDINAL ← (tablePages + MBStorage.PagesForWords[nwords]);
newbase: POINTER ← MBStorage.MDSPages[newPages];
IF scriptBase #
NIL
THEN {
Inline.LongCOPY[from: scriptBase, to: newbase, nwords: tablePages*PageSize];
MBStorage.FreeMDSPages[scriptBase];
};
tablePages ← newPages;
data.scriptBase ← scriptBase ← newbase;
};
EnterSegment:
PROC [seg:
MBVM.Seg] = {
WITH s: seg
SELECT
FROM
data => EnterSimpleSegment[seg];
code =>
IF s.sph = NIL THEN EnterSimpleSegment[seg]
ELSE {
r: swapUnit Entry;
first: BOOL ← TRUE;
s.bootLoaded ← FALSE;
FOR i:
CARDINAL
IN [0..s.sph.length)
DO
base: CARDINAL = s.base+s.sph.spaces[i].offset;
state: SwapUnitState =
SELECT
TRUE
FROM
residentTable[base] => resident,
resDescTable[base] => residentDescriptor,
ENDCASE => swappable;
IF residentTable[base] OR inTable[base] THEN s.bootLoaded ← TRUE;
r ← Entry[swapUnit[info: [s.info.readOnly, state],
pages: s.sph.spaces[i].pages, base: s.sph.spaces[i].offset,
parent: NullSpaceIndex]
];
IF first THEN {first ← FALSE; s.index ← LOOPHOLE[scriptIndex]};
AppendBootWords[@r, SIZE[swapUnit Entry]];
ENDLOOP;
};
file =>
IF s.bIndex = MB.nullIndex THEN EnterSimpleSegment[seg]
ELSE {
bcd: BcdOps.BcdBase = data.inputBCDs.bcds[s.bIndex].bcd;
r: swapUnit Entry ← Entry[swapUnit[
info: GetSegmentInfo[seg], pages: seg.pages, base: 0, parent: NullSpaceIndex]];
seg.index ← LOOPHOLE[scriptIndex];
IF r.info.state = resident
OR bcd.rtPages.pages = 0
THEN
AppendBootWords[@r, SIZE[swapUnit Entry]]
ELSE {
s.nUnits ← 2;
r.pages ← bcd.nPages - bcd.rtPages.pages;
AppendBootWords[@r, SIZE[swapUnit Entry]];
r.pages ← bcd.rtPages.pages; r.base ← bcd.rtPages.relPageBase;
AppendBootWords[@r, SIZE[swapUnit Entry]];
};
};
ENDCASE;
EnterSimpleSegment:
PROC [seg:
MBVM.Seg] = {
r: swapUnit Entry ← Entry[swapUnit[
info: GetSegmentInfo[seg], pages: seg.pages, base: 0, parent: NullSpaceIndex]];
seg.index ← LOOPHOLE[scriptIndex];
AppendBootWords[@r, SIZE[swapUnit Entry]];
};
GetSegmentInfo:
PROC [seg:
MBVM.Seg]
RETURNS [info: SwapUnitInfo] = {
state: SwapUnitState =
IF seg.info.state = resident
THEN resident
ELSE
SELECT
TRUE
FROM
residentTable[seg.base] => resident,
resDescTable[seg.base] => residentDescriptor,
ENDCASE => swappable;
seg.bootLoaded ← residentTable[seg.base] OR inTable[seg.base];
RETURN[[seg.info.readOnly, state]]
};
AppendBootWords:
PROC [addr:
POINTER, count:
CARDINAL] = {
IF LOOPHOLE[scriptIndex,CARDINAL]+count > tablePages*PageSize OR count = 0 THEN ERROR;
Inline.LongCOPY[from: addr, to: @scriptBase[scriptIndex], nwords: count];
scriptIndex ← scriptIndex + count;
};
AddSpace:
PROC [state: PageState, start, end:
CARDINAL] = {
r: space Entry;
single: BOOL ← TRUE;
resident: BOOL ← residentTable[start];
anyResDesc, anyReadOnly: BOOL ← FALSE;
allResDesc, allReadOnly: BOOL ← TRUE;
offset: CARDINAL;
pages: CARDINAL = end-start+1;
space: SpaceIndex ← LOOPHOLE[scriptIndex];
IF ~state.busy THEN {AddEmptySpace[start, pages]; RETURN};
r ← Entry[space[
readOnly: state.readOnly,
bootLoaded: (state.resident OR state.in), handle:, type:,
pages: pages, vmpage: start, backingPage: 0,
backingStore: (IF state.resident THEN null ELSE self)]
];
AppendBootWords[@r, SIZE[space Entry]];
FOR i:
CARDINAL
IN [start..end]
DO
anyResDesc ← anyResDesc OR resDescTable[i];
allResDesc ← allResDesc AND resDescTable[i];
anyReadOnly ← anyReadOnly OR readOnlyTable[i];
allReadOnly ← allReadOnly AND readOnlyTable[i];
ENDLOOP;
offset ← 0;
DO
scriptBase[suIndex].parent ← space;
scriptBase[suIndex].base ← offset;
offset ← scriptBase[suIndex].pages + offset;
IF offset >= pages THEN EXIT;
suIndex ← suIndex + SIZE[swapUnit Entry];
single ← FALSE;
ENDLOOP;
scriptBase[space].type ←
IF ~single
THEN
[family[
Trinity or later... anyReadOnlyChildren: anyReadOnly,
anyResidentChildren: resident,
anyResidentDescriptorChildren: anyResDesc,
anySwappableChildren: ~resident,
Trinity or later... allReadOnlyChildren: allReadOnly,
allResidentChildren: resident,
allResidentDescriptorChildren: allResDesc,
allSwappableChildren: ~resident]]
ELSE [unitary[suIndex]];
suIndex ← suIndex + SIZE[swapUnit Entry];
};
AddEmptySpace:
PROC [start, pages:
CARDINAL] = {
r: space Entry;
space: SpaceIndex ← LOOPHOLE[scriptIndex];
r ← Entry[space[bootLoaded:
FALSE, backingStore: null, type: [empty[]],
readOnly: FALSE, pages: pages, vmpage: start, handle:, backingPage: 0]
];
AppendBootWords[@r, SIZE[space Entry]];
};
PageFromAddress:
PROC [p:
POINTER]
RETURNS [
CARDINAL] = {
RETURN[LOOPHOLE[p, CARDINAL]/256]};
PreScanSegs:
PROC [
segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg]
RETURNS [lastBootedPage, nBootPages, nFilePages: CARDINAL] = {
i: CARDINAL;
seg: MBVM.Seg;
nBootPages ← 0;
FOR i
IN [0..
LENGTH[segs])
DO
seg ← segs[i];
IF ~seg.bootLoaded THEN LOOP;
WITH s: seg
SELECT
FROM
data =>
IF seg.base # 376B
THEN {
lastBootedPage ← s.base + s.pages - 1;
nBootPages ← nBootPages + s.pages;
};
code => [lastBootedPage, nBootPages] ← ScanBootedCodeSeg[@s, nBootPages];
file => {
lastBootedPage ← s.base + s.pages - 1;
nBootPages ← nBootPages + s.pages;
};
ENDCASE;
ENDLOOP;
nFilePages ← BootFile.MemorySizeToFileSize[nBootPages];
FOR i
IN [0..
LENGTH[segs])
DO
info: StartList.SwapUnitInfo;
seg ← segs[i];
info ← scriptBase[seg.index].info;
WITH s: seg
SELECT
FROM
data =>
IF info.state # resident
THEN {
IF scriptBase[scriptBase[seg.index].parent].backingPage = 0
THEN
scriptBase[scriptBase[seg.index].parent].backingPage ← nFilePages;
nFilePages ← nFilePages + s.pages;
};
code => nFilePages ← ScanCodeSeg[@s, nFilePages];
file =>
IF info.state # resident
THEN {
IF scriptBase[scriptBase[seg.index].parent].backingPage = 0
THEN
scriptBase[scriptBase[seg.index].parent].backingPage ← nFilePages;
nFilePages ← nFilePages + s.pages;
};
ENDCASE;
ENDLOOP;
ScanBootedCodeSeg:
PROC [seg:
MBVM.CodeSeg, nBootPages:
CARDINAL]
RETURNS [lastPage, pages: CARDINAL] = {
i, page: CARDINAL;
nUnits: CARDINAL ← IF seg.sph = NIL THEN 1 ELSE seg.sph.length;
index: SwapUnitIndex ← seg.index;
page ← seg.base;
pages ← 0;
FOR i
IN [0..nUnits)
DO
IF scriptBase[scriptBase[index].parent].bootLoaded
THEN {
lastPage ← page + scriptBase[index].pages - 1;
pages ← pages + scriptBase[index].pages;
};
page ← page + scriptBase[index].pages;
index ← index + SIZE[swapUnit Entry];
ENDLOOP;
RETURN[lastPage, nBootPages + pages]
};
ScanCodeSeg:
PROC [seg:
MBVM.CodeSeg, nFilePages:
CARDINAL]
RETURNS [
CARDINAL] = {
nUnits: CARDINAL ← IF seg.sph = NIL THEN 1 ELSE seg.sph.length;
index: SwapUnitIndex ← seg.index;
su: POINTER TO swapUnit Entry;
FOR i:
CARDINAL
IN [0..nUnits)
DO
su ← @scriptBase[index];
IF scriptBase[su.parent].backingPage = 0
THEN
scriptBase[su.parent].backingPage ← nFilePages;
IF su.info.state # resident THEN nFilePages ← nFilePages + su.pages;
index ← index + SIZE[swapUnit Entry];
ENDLOOP;
RETURN[nFilePages]
};
END.