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 June 21, 1983 2:59 pm
DIRECTORY
BcdDefs USING [Base, BcdBase, FPHandle, MTHandle, SPHandle],
BootFile USING [Location],
BootStartList USING [
BackingLocation, Entry, Header, Index, nullSpaceIndex, nullSwapUnitIndex, SpaceIndex, SpaceType, startIndex, SwapUnitIndex, SwapUnitInfo, SwapUnitState, Base, versionID],
MB USING [
BHandle, BIndex, BitArray, BitArrayObject, DumpSegs, EnumerateBCDs, EnumerateCode, EnumerateFramePacks, EnumerateGlobalFrames, EnumerateSpaces, Handle, nullIndex, PreScanSegsForOutput, VirtualGlobalFrame],
MBVM USING [
AllocMDSData, Base, CodeSeg, DataSeg, FileSeg, LongCopyWrite, MDS, Pages, PointerFromSeg, Seg, Segs, SortSegs],
PrincOps USING [GlobalFrameHandle, NullControl],
PrincOpsUtils USING [LongCOPY, PageNumberToAddress, PagesToWords, WordsToPages],
Space USING [Create, Delete, Handle, LongPointer, Map, nullHandle, virtualMemory];
MBScript: PROGRAM
IMPORTS MB, MBVM, PrincOpsUtils, Space
EXPORTS MB =
BEGIN
OPEN BootStartList;
PageState: TYPE = RECORD [busy, resident, in, readOnly, mds, first64K: BOOL];
data: MB.Handle ← NIL;
segs: MBVM.Segs ← NIL;
residentTable, resDescTable, inTable, readOnlyTable: MB.BitArray ← NIL;
suIndex: SwapUnitIndex;
Wart Script Management
scriptIndex: Index;
scriptPages: CARDINAL;
scriptBase: Base;
scriptSpace: Space.Handle;
InitScript: PUBLIC PROC [h: MB.Handle] = {
nullLocation: BootFile.Location = [
deviceType: null,
deviceOrdinal: 0,
vp: any[a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0]];
data ← h;
data.header ← NEW[Header ← [
version: versionID,
release: [0, 0, 0],
buildDate: 0,
requiredUCode: [0, 0, 0, 0],
controlList: PrincOps.NullControl,
initLoadState: nullSwapUnitIndex,
mdsBase: 0,
pdaPages: 0,
stateVectorCounts: ALL[0],
stateVectorSize: 0,
nProcesses: 0,
lastVMPage: 0,
lastBootLoadedPage: 0,
switches: [0,0,0,0],
locDebuggerMicrocode: nullLocation,
locDebuggerGerm: nullLocation,
locDebugger: nullLocation,
locDebuggee: nullLocation
]];
scriptIndex ← startIndex;
scriptPages ← 0;
scriptBase ← NIL;
scriptSpace ← Space.nullHandle;
segs ← NIL;
};
FinishScript: PUBLIC PROC = {
residentTable ← resDescTable ← inTable ← readOnlyTable ← NIL;
data.header ← NIL;
IF scriptBase ~= NIL THEN {
Space.Delete[scriptSpace];
scriptBase ← NIL;
scriptSpace ← Space.nullHandle;
};
segs ← NIL;
data ← NIL;
};
InitBitTables: PROC [length: CARDINAL] = {
residentTable ← NEW[MB.BitArrayObject[length]];
FOR i: CARDINAL IN [0..length) DO residentTable[i] ← FALSE; ENDLOOP;
resDescTable ← NEW[MB.BitArrayObject[length]];
FOR i: CARDINAL IN [0..length) DO resDescTable[i] ← FALSE; ENDLOOP;
inTable ← NEW[MB.BitArrayObject[length]];
FOR i: CARDINAL IN [0..length) DO inTable[i] ← FALSE; ENDLOOP;
readOnlyTable ← NEW[MB.BitArrayObject[length]];
FOR i: CARDINAL IN [0..length) DO readOnlyTable[i] ← FALSE; ENDLOOP;
};
MakeScript: PUBLIC PROC = {
header: REF Header = data.header;
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;
scriptSeg: MBVM.DataSeg;
segs ← MBVM.SortSegs[];
InitBitTables[data.vmMap.length];
Beyond this point it is assumed that the vmMap won't grow.
FOR i IN [0..segs.length) 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..segs.length) 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 --?? RL-- + 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.
scriptSeg ← MBVM.AllocMDSData[base: MBVM.MDS, pages: scriptPages];
scriptSeg.bootLoaded ← TRUE;
scriptSeg.info ← [readOnly: FALSE, state: swappable];
AddToBitTables[scriptSeg];
data.scriptBaseInVM ←
PrincOpsUtils.PageNumberToAddress[data.mdsBase] +
LOOPHOLE[MBVM.PointerFromSeg[scriptSeg], CARDINAL];
segs ← MBVM.SortSegs[];
FOR i IN [0..segs.length) DO EnterSegment[segs[i]] ENDLOOP;
IF data.debug THEN MB.DumpSegs[segs, "SCRIPT CONSTRUCTION"];
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]];
header.buildDate ← LOOPHOLE[data.buildTime];
header.lastBootLoadedPage ← MB.PreScanSegsForOutput[segs];
header.mdsBase ← data.mdsBase;
header.pdaPages ← data.pdaPages;
header.initLoadState ← data.lsseg.index;
header.lastVMPage ← data.lastVMPage;
header.stateVectorCounts ← data.stateVectorCounts;
header.stateVectorSize ← data.svSize;
header.nProcesses ← data.nProcesses;
scriptBase^ ← header^;
MBVM.LongCopyWrite[
from: scriptBase, to: data.scriptBaseInVM, nwords: PrincOpsUtils.PagesToWords[scriptPages]];
segs ← NIL;
};
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: BcdDefs.MTHandle] RETURNS [BOOL] = {
cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code;
MarkSegPages[cseg, @inTable];
RETURN[FALSE]
};
BootLoadSpaces: PROC [bh: MB.BHandle, sph: BcdDefs.SPHandle, index: CARDINAL]
RETURNS [BOOL] = {
MarkSpacePages[sph, index, @inTable];
RETURN[FALSE]
};
BootLoadFramePacks: PROC [bh: MB.BHandle, fph: BcdDefs.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: BcdDefs.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: BcdDefs.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: BcdDefs.SPHandle, index: CARDINAL]
RETURNS [BOOL] = {
MarkSpacePages[sph, index, @resDescTable];
RETURN[FALSE]
};
ResDescFramePacks: PROC [bh: MB.BHandle, fph: BcdDefs.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: BcdDefs.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: BcdDefs.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: BcdDefs.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: BcdDefs.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..segs.length) DO
seg ← segs[i];
IF base IN [seg.base..seg.base+seg.pages) THEN EXIT;
REPEAT
FINISHED => ERROR;
ENDLOOP;
};
SegForSpace: PROC [sph: BcdDefs.SPHandle] RETURNS [cseg: MBVM.CodeSeg] = {
FOR i: CARDINAL IN [0..segs.length) 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 = scriptPages + PrincOpsUtils.WordsToPages[nwords];
newSpace: Space.Handle = Space.Create[newPages, Space.virtualMemory];
newBase: LONG POINTER = Space.LongPointer[newSpace];
Space.Map[newSpace];
IF scriptBase ~= NIL THEN {
PrincOpsUtils.LongCOPY[
from: scriptBase, to: newBase, nwords: PrincOpsUtils.PagesToWords[scriptPages]];
Space.Delete[scriptSpace];
};
scriptPages ← newPages;
data.scriptBase ← scriptBase ← newBase;
scriptSpace ← newSpace;
};
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: BOOLTRUE;
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: BcdDefs.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 > PrincOpsUtils.PagesToWords[scriptPages] OR count = 0 THEN ERROR;
PrincOpsUtils.LongCOPY[from: addr, to: @scriptBase[scriptIndex], nwords: count];
scriptIndex ← scriptIndex + count;
};
AddSpace: PROC [state: PageState, start, end: CARDINAL] = {
r: space Entry;
single: BOOLTRUE;
resident: BOOL ← residentTable[start];
anyResDesc, anyReadOnly: BOOLFALSE;
allResDesc, allReadOnly: BOOLTRUE;
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), type: ,
pages: pages, vmPage: start, backingPage: 0,
backingStore: null]
];
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, backingPage: 0]
];
AppendBootWords[@r, SIZE[space Entry]];
};
PageFromAddress: PROC [p: POINTER] RETURNS [CARDINAL] = {
RETURN[LOOPHOLE[p, CARDINAL]/256]};
END.