MBScript.mesa
Copyright Ó 1985, 1986 by Xerox Corporation. All rights reserved.
Sandman on 6-Aug-81 15:42:29
Lewis on 17-Sep-81 16:15:24
Levin on January 17, 1984 10:53 am
Russ Atkinson (RRA) March 8, 1985 5:31:09 pm PST
Doug Wyatt, December 12, 1986 6:34:50 pm PST
DIRECTORY
BasicTime USING [ToPupTime],
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 [AddressForPageNumber, LongCopy, LongZero, PagesForWords, WordsForPages],
VM USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval];
MBScript:
CEDAR
PROGRAM
IMPORTS BasicTime, MB, MBVM, PrincOpsUtils, VM
EXPORTS MB
SHARES BootFile
= 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;
scriptBase: Base;
scriptBuffer: VM.Interval;
InitScript:
PUBLIC
PROC [h:
MB.Handle] = {
nullLocation: BootFile.Location = [
deviceType: [0],
deviceOrdinal: 0,
vp: any[ALL[0]]];
data ← h;
data.header ←
NEW[Header ← [
version: versionID,
release: [0, 0, 0],
buildDate: 0,
requiredUCode: ALL[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;
scriptBase ← NIL;
scriptBuffer ← VM.nullInterval;
segs ← NIL;
};
FinishScript:
PUBLIC
PROC = {
residentTable ← resDescTable ← inTable ← readOnlyTable ← NIL;
data.header ← NIL;
IF scriptBase ~=
NIL
THEN {
TRUSTED {VM.Free[scriptBuffer]};
scriptBase ← NIL;
scriptBuffer ← VM.nullInterval;
};
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 segs[i]
SELECT
FROM
seg: MBVM.DataSeg => nwords ← nwords + SIZE[swapUnit Entry];
seg:
MBVM.CodeSeg =>
TRUSTED {
nwords ← nwords +
(IF seg.sph ~= NIL THEN seg.sph.length*SIZE[swapUnit Entry] ELSE SIZE[swapUnit Entry]);
};
seg:
MBVM.FileSeg =>
IF seg.bIndex = MB.nullIndex THEN nwords ← nwords + SIZE[swapUnit Entry]
ELSE {
loadee: MB.BHandle = data.inputBCDs.bcds[seg.bIndex];
TRUSTED {
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: scriptBuffer.count];
scriptSeg.bootLoaded ← TRUE;
scriptSeg.info ← [readOnly: FALSE, state: swappable];
AddToBitTables[scriptSeg];
TRUSTED {
data.scriptBaseInVM ←
PrincOpsUtils.AddressForPageNumber[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];
TRUSTED {AppendBootWords[@r, SIZE[stop Entry]]};
header.buildDate ← BasicTime.ToPupTime[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;
TRUSTED {
scriptBase^ ← header^;
MBVM.LongCopyWrite[
from: scriptBase, to: data.scriptBaseInVM,
nwords: PrincOpsUtils.WordsForPages[scriptBuffer.count]];
};
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] =
TRUSTED {
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] = TRUSTED {
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] = TRUSTED {
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] =
TRUSTED {
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] = TRUSTED {
MarkSpacePages[sph, index, resDescTable];
RETURN[FALSE]
};
ResDescFramePacks:
PROC [bh:
MB.BHandle, fph: BcdDefs.FPHandle]
RETURNS [BOOL] = TRUSTED {
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] = TRUSTED {
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] =
TRUSTED {
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] = TRUSTED {
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:
MB.BitArray] =
INLINE {
MarkTablePages[table, seg.base, seg.pages]};
MarkSpacePages:
PROC [
sph: BcdDefs.SPHandle, index: CARDINAL, table: MB.BitArray] = TRUSTED {
cseg: MBVM.CodeSeg = SegForSpace[sph];
MarkTablePages[table, cseg.base + sph.spaces[index].offset, sph.spaces[index].pages]
};
MarkTablePages:
PROC [table:
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 segs[i]
SELECT
FROM
s: MBVM.CodeSeg => IF s.sph = sph THEN {cseg ← s; EXIT};
ENDCASE;
REPEAT
FINISHED => ERROR;
ENDLOOP;
AddScriptWords:
PROC [nwords:
CARDINAL] =
TRUSTED {
newPages: CARDINAL = scriptBuffer.count + PrincOpsUtils.PagesForWords[nwords];
newBuffer: VM.Interval = VM.Allocate[newPages];
newBase: LONG POINTER = VM.AddressForPageNumber[newBuffer.page];
IF scriptBase =
NIL
THEN
PrincOpsUtils.LongZero[
where: newBase,
nwords: PrincOpsUtils.WordsForPages[newBuffer.count]
]
ELSE {
PrincOpsUtils.LongCopy[
from: scriptBase, to: newBase, nwords: PrincOpsUtils.WordsForPages[scriptBuffer.count]];
VM.Free[scriptBuffer];
PrincOpsUtils.LongZero[
where: newBase + PrincOpsUtils.WordsForPages[scriptBuffer.count],
nwords: PrincOpsUtils.WordsForPages[newBuffer.count - scriptBuffer.count]
];
};
data.scriptBase ← scriptBase ← newBase;
scriptBuffer ← newBuffer;
};
EnterSegment:
PROC [seg:
MBVM.Seg] =
TRUSTED {
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: 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.extended
AND 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];
TRUSTED {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] =
TRUSTED {
IF LOOPHOLE[scriptIndex,CARDINAL]+count > PrincOpsUtils.WordsForPages[scriptBuffer.count] OR count = 0 THEN ERROR;
PrincOpsUtils.LongCopy[from: addr, to: @scriptBase[scriptIndex], nwords: count];
scriptIndex ← scriptIndex + count;
};
AddSpace:
PROC [state: PageState, start, end:
CARDINAL] =
TRUSTED {
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), 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] =
TRUSTED {
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.