MBOutput.mesa
Edited by Sandman on 6-Aug-81 15:41:43
Edited by Lewis on 25-Sep-81 15:01:46
Edited by Levin on June 21, 1983 2:59 pm
DIRECTORY
Ascii USING [CR],
BcdDefs USING [MTHandle],
BootFile
USING [
Entry, Header, maxEntriesPerHeader, maxEntriesPerTrailer, MemorySizeToFileSize, Trailer, currentVersion],
BootStartList USING [Base, Entry, SwapUnitIndex, SwapUnitInfo],
ConvertUnsafe USING [AppendRope],
FileIO USING [CapabilityFromStream, Open],
IO
USING [
card, Close, GetIndex, GetLength, PutChar, PutF, PutRope, rope, SetIndex, SetLength, STREAM, UnsafeGetBlock, UnsafePutBlock],
MB USING [BHandle, DoAllModules, DumpSegs, Handle, StartControlLink, Zero],
MBVM
USING [
Base, CodeSeg, CopyRead, CopyWrite, DataSeg, FileSeg, GetPage, ReleaseCodeSegs, Seg, Segs, SortSegs, Write],
PrincOps
USING [
bytesPerPage, flagsClean, flagsReadOnly, GlobalFrame, InterimPageState, PageFlags, PageNumber, wordsPerPage],
PrincOpsUtils USING [HighHalf, LongMult, LowHalf],
Rope USING [ROPE],
Segments
USING [
FHandle, FP, InsertFile, ReleaseFile, SegmentAddress, SetFileTimes, SHandle, SwapIn, Unlock, Write],
Space USING [Create, Delete, Handle, LongPointer, Map, virtualMemory],
Time USING [Packed];
MBOutput:
PROGRAM
IMPORTS BootFile, ConvertUnsafe, FileIO, IO, MB, MBVM, PrincOpsUtils, Segments, Space
EXPORTS MB =
BEGIN
OPEN MBVM;
wordsPerPage: CARDINAL = PrincOps.wordsPerPage;
bytesPerPage: CARDINAL = PrincOps.bytesPerPage;
PageOfWords: TYPE = ARRAY [0..wordsPerPage) OF WORD;
data: MB.Handle ← NIL;
header: REF BootFile.Header ← NIL;
trailer: REF BootFile.Trailer ← NIL;
nEntries, currentEntry: CARDINAL;
filePage: MBVM.Base;
trailerIndex: LONG CARDINAL;
EtherHeader:
TYPE =
MACHINE
DEPENDENT
RECORD [
version(0): CARDINAL ← 1,
mustBeZero(1): LONG CARDINAL ← 0,
createTime(3): BCPLTime
the following are implicit
name(5): StringBody,
fill(5+WordsForString[name]): ARRAY [5+WordsForString[name]..wordsPerPage) OF WORD ← ALL[0]
];
BCPLTime: TYPE = MACHINE DEPENDENT RECORD [high, low: CARDINAL];
InitOutput: PUBLIC PROC [h: MB.Handle] = {data ← h};
FinishOutput:
PUBLIC
PROC = {
IF data.bootStream ~= NIL THEN {data.bootStream.Close[abort: TRUE]; data.bootStream ← NIL};
header ← NIL;
trailer ← NIL;
MBVM.ReleaseCodeSegs[];
data ← NIL;
};
Boot file (not germ) output
PreScanSegsForOutput:
PUBLIC
PROC [segs:
MBVM.Segs]
RETURNS [lastBootedPage: PrincOps.PageNumber] = {
scriptBase: BootStartList.Base = data.scriptBase;
nFilePages: CARDINAL ← 0;
data.nBootLoadedPages ← 0;
FOR i:
CARDINAL
IN [0..segs.length)
DO
seg: MBVM.Seg = segs[i];
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[seg.index];
WITH s: seg
SELECT
FROM
data =>
IF scriptBase[su.parent].bootLoaded
THEN {
IF s.base = 376B THEN IF s.pages ~= 1 THEN ERROR ELSE LOOP; -- ugh!
IF su.info.state = resident
THEN
data.nResidentPages ← data.nResidentPages + su.pages;
data.nBootLoadedPages ← data.nBootLoadedPages + su.pages;
lastBootedPage ←
MAX[lastBootedPage, scriptBase[su.parent].vmPage + su.base + su.pages - 1];
};
code => {
nUnits: CARDINAL = IF s.sph = NIL THEN 1 ELSE s.sph.length;
index: BootStartList.SwapUnitIndex ← s.index;
THROUGH [0..nUnits)
DO
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[index];
IF scriptBase[su.parent].bootLoaded
THEN {
IF su.info.state = resident
THEN
data.nResidentPages ← data.nResidentPages + su.pages;
data.nBootLoadedPages ← data.nBootLoadedPages + su.pages;
lastBootedPage ←
MAX[lastBootedPage, scriptBase[su.parent].vmPage + su.base + su.pages - 1];
};
index ← index + SIZE[swapUnit BootStartList.Entry];
ENDLOOP;
};
file =>
IF scriptBase[su.parent].bootLoaded
THEN {
IF su.info.state = resident
THEN
data.nResidentPages ← data.nResidentPages + s.pages;
data.nBootLoadedPages ← data.nBootLoadedPages + s.pages;
lastBootedPage ← s.base + s.pages - 1;
};
ENDCASE;
ENDLOOP;
nFilePages ← BootFile.MemorySizeToFileSize[data.nBootLoadedPages];
FOR i:
CARDINAL
IN [0..segs.length)
DO
seg: MBVM.Seg = segs[i];
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[seg.index];
WITH s: seg
SELECT
FROM
data =>
IF AppendNecessary[su]
THEN {
scriptBase[su.parent].backingStore ← self;
IF scriptBase[su.parent].backingPage = 0
THEN
scriptBase[su.parent].backingPage ← nFilePages;
nFilePages ← nFilePages + su.pages;
};
code => {
nUnits: CARDINAL = IF s.sph = NIL THEN 1 ELSE s.sph.length;
index: BootStartList.SwapUnitIndex ← s.index;
THROUGH [0..nUnits)
DO
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[index];
IF AppendNecessary[su]
THEN {
scriptBase[su.parent].backingStore ← self;
IF scriptBase[su.parent].backingPage = 0
THEN
scriptBase[su.parent].backingPage ← nFilePages;
nFilePages ← nFilePages + su.pages;
};
index ← index + SIZE[swapUnit BootStartList.Entry];
ENDLOOP;
};
file =>
IF AppendNecessary[su]
THEN {
scriptBase[su.parent].backingStore ← self;
IF scriptBase[su.parent].backingPage = 0
THEN
scriptBase[su.parent].backingPage ← nFilePages;
nFilePages ← nFilePages + s.pages;
};
ENDCASE;
ENDLOOP;
data.nFilePages ← nFilePages;
WriteBootFile:
PUBLIC
PROC = {
data.typescript.PutF["Writing *q file..."];
InitializeBootFile[];
WriteVM[];
FinalizeBootFile[];
data.typescript.PutRope["finished writing.\N"];
IF data.etherFormat THEN MakeEtherFile[];
};
InitializeBootFile:
PROC = {
data.bootStream ← FileIO.Open[
fileName: data.output,
accessOptions: overwrite,
createLength: PrincOpsUtils.LongMult[data.nFilePages, bytesPerPage]
];
data.bootStream.SetLength[bytesPerPage];
data.bootStream.SetIndex[bytesPerPage];
data.bootHeader ← header ← LOOPHOLE[NEW[PageOfWords]];
MB.Zero[LOOPHOLE[header], wordsPerPage];
header^ ← BootFile.Header[
creationDate: data.buildTime,
pStartListHeader: PrincOpsUtils.LowHalf[data.scriptBaseInVM],
inLoadMode: load,
continuation: [vp: initial[mdsi: [data.mdsBase/256], destination: MB.StartControlLink[]]],
countData: data.nBootLoadedPages,
entries:
];
trailer ← NIL;
nEntries ← BootFile.maxEntriesPerHeader;
currentEntry ← 0;
filePage ← 1;
};
FinalizeBootFile:
PROC = {
fp: Segments.FP ← FileIO.CapabilityFromStream[data.bootStream];
file: Segments.FHandle;
length: INT = data.bootStream.GetIndex[];
data.bootStream.SetIndex[0];
data.bootStream.UnsafePutBlock[
block: [base: LOOPHOLE[header], startIndex: 0, stopIndexPlusOne: bytesPerPage]];
data.bootStream.SetIndex[length];
data.bootStream.SetLength[length];
data.bootStream.Close[];
data.bootStream ← NIL;
Now set the create time to the desired value
file ← Segments.InsertFile[@fp, Segments.Write];
Segments.SetFileTimes[file: file, create: data.buildTime];
Segments.ReleaseFile[file];
};
WriteVM:
PROC = {
segs: MBVM.Segs = MBVM.SortSegs[];
scriptBase: BootStartList.Base = data.scriptBase;
loadmap: IO.STREAM = data.loadmap;
loadmap.PutRope["\N\NBOOT FILE MAP\N\N"];
BootloadedHeadingToLoadmap[" Bootloaded Memory\N"];
loadmap.PutF["%6n Header Page\N", IO.card[filePage-1]]; -- header page
data.typescript.PutRope["bootloaded memory..."];
FOR i:
CARDINAL
IN [0..segs.length)
DO
WITH s: segs[i]
SELECT
FROM
data => WriteDataSeg[@s];
code => WriteCodeSeg[@s];
file => WriteFileSeg[@s];
ENDCASE;
ENDLOOP;
IF trailer ~= NIL THEN [] ← WriteTrailerPage[];
NonBootloadedHeadingToLoadmap["\N Non-Bootloaded Memory\N"];
data.typescript.PutRope["non-bootloaded memory..."];
FOR i:
CARDINAL
IN [0..segs.length)
DO
WITH s: segs[i]
SELECT
FROM
data => AppendDataSeg[@s];
code => AppendCodeSeg[@s];
file => AppendFileSeg[@s];
ENDCASE;
ENDLOOP;
loadmap.PutF["\N\NBoot file pages: %n (%n bootloaded, of which %n are resident)\N",
IO.card[data.nFilePages], IO.card[data.nBootLoadedPages], IO.card[data.nResidentPages]];
WriteDataSeg:
PROC [seg:
MBVM.DataSeg] = {
scriptBase: BootStartList.Base = data.scriptBase;
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[seg.index];
v: PrincOps.InterimPageState = MapValueForSeg[seg];
IF ~scriptBase[su.parent].bootLoaded THEN RETURN;
IF seg.base = 376B THEN IF seg.pages ~= 1 THEN ERROR ELSE RETURN; -- ugh!
BootloadedSegToLoadmap[seg, filePage, v.flags];
FOR page:
CARDINAL
IN [seg.base..seg.base+seg.pages)
DO
lp: LONG POINTER;
EnterPage[page: page, value: v];
lp ← MBVM.GetPage[page];
IF lp = NIL THEN WriteEmptyPage[] ELSE WritePage[lp];
ENDLOOP;
WriteCodeSeg:
PROC [seg:
MBVM.CodeSeg] = {
nUnits: CARDINAL = IF seg.sph = NIL THEN 1 ELSE seg.sph.length;
scriptBase: BootStartList.Base = data.scriptBase;
index: BootStartList.SwapUnitIndex ← seg.index;
v: PrincOps.InterimPageState = MapValueForSeg[seg];
lp: LONG POINTER;
THROUGH [0..nUnits)
DO
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[index];
IF scriptBase[su.parent].bootLoaded THEN EXIT;
index ← index + SIZE[swapUnit BootStartList.Entry];
REPEAT
FINISHED => RETURN;
ENDLOOP;
lp ← OpenSegForTransfer[seg.segment];
IF seg.sph =
NIL
THEN {
BootloadedSegToLoadmap[seg, filePage, v.flags];
FOR page:
CARDINAL
IN [seg.base..seg.base+seg.pages)
DO
EnterPage[page: page, value: v];
WritePage[lp];
lp ← lp + wordsPerPage;
ENDLOOP;
}
ELSE {
index: BootStartList.SwapUnitIndex ← seg.index;
THROUGH [0..nUnits)
DO
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[index];
IF scriptBase[su.parent].bootLoaded
THEN {
BootloadedSwapUnitToLoadmap[index, filePage, v.flags, seg];
FOR i:
CARDINAL
IN [0..su.pages)
DO
EnterPage[page: scriptBase[su.parent].vmPage + su.base + i, value: v];
WritePage[lp];
lp ← lp + wordsPerPage;
ENDLOOP;
}
ELSE lp ← lp + su.pages*wordsPerPage;
index ← index + SIZE[swapUnit BootStartList.Entry];
ENDLOOP;
};
CloseSegAfterTransfer[seg.segment];
};
WriteFileSeg:
PROC [seg:
MBVM.FileSeg] = {
scriptBase: BootStartList.Base = data.scriptBase;
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[seg.index];
v: PrincOps.InterimPageState = MapValueForSeg[seg];
lp: LONG POINTER;
IF ~scriptBase[su.parent].bootLoaded THEN RETURN;
lp ← OpenSegForTransfer[seg.segment];
BootloadedSegToLoadmap[seg, filePage, v.flags];
FOR page:
CARDINAL
IN [seg.base..seg.base+seg.pages)
DO
EnterPage[page: page, value: v];
WritePage[lp];
lp ← lp + wordsPerPage;
ENDLOOP;
CloseSegAfterTransfer[seg.segment];
};
AppendDataSeg:
PROC [seg:
MBVM.DataSeg] = {
IF ~AppendNecessary[@data.scriptBase[seg.index]] THEN RETURN;
SegToLoadmap[seg, filePage];
FOR page:
CARDINAL
IN [seg.base..seg.base+seg.pages)
DO
lp: LONG POINTER = MBVM.GetPage[page];
IF lp = NIL THEN WriteEmptyPage[] ELSE WritePage[lp];
ENDLOOP;
AppendCodeSeg:
PROC [seg:
MBVM.CodeSeg] = {
lp: LONG POINTER;
nUnits: CARDINAL = IF seg.sph = NIL THEN 1 ELSE seg.sph.length;
index: BootStartList.SwapUnitIndex ← seg.index;
scriptBase: BootStartList.Base = data.scriptBase;
THROUGH [0..nUnits)
DO
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[index];
IF AppendNecessary[su] THEN EXIT;
index ← index + SIZE[swapUnit BootStartList.Entry];
REPEAT
FINISHED => RETURN;
ENDLOOP;
lp ← OpenSegForTransfer[seg.segment];
IF seg.sph =
NIL
THEN {
SegToLoadmap[seg, filePage];
THROUGH [0..seg.pages)
DO
WritePage[lp];
lp ← lp + wordsPerPage;
ENDLOOP;
}
ELSE {
index: BootStartList.SwapUnitIndex ← seg.index;
THROUGH [0..nUnits)
DO
su: LONG POINTER TO swapUnit BootStartList.Entry = @scriptBase[index];
IF AppendNecessary[su]
THEN {
SwapUnitToLoadmap[index, filePage, seg];
THROUGH [0..su.pages)
DO
WritePage[lp];
lp ← lp + wordsPerPage;
ENDLOOP;
}
ELSE lp ← lp + su.pages*wordsPerPage;
index ← index + SIZE[swapUnit BootStartList.Entry];
ENDLOOP;
};
CloseSegAfterTransfer[seg.segment];
};
AppendFileSeg:
PROC [seg:
MBVM.FileSeg] = {
lp: LONG POINTER;
IF ~AppendNecessary[@data.scriptBase[seg.index]] THEN RETURN;
lp ← OpenSegForTransfer[seg.segment];
SegToLoadmap[seg, filePage];
IF data.debug
THEN {
loadmap: IO.STREAM = data.loadmap;
index: BootStartList.SwapUnitIndex ← seg.index;
loadmap.PutF["%sSwapUnits[", IO.card[26]];
FOR i:
CARDINAL
IN [0..seg.nUnits)
DO
loadmap.PutF["%n", IO.card[LOOPHOLE[index].LONG]];
IF i ~= seg.nUnits - 1 THEN loadmap.PutRope[", "];
index ← index + SIZE[swapUnit BootStartList.Entry];
ENDLOOP;
loadmap.PutRope["]\N"];
};
FOR i:
CARDINAL
IN [0..seg.pages)
DO
WritePage[lp];
lp ← lp + wordsPerPage;
ENDLOOP;
CloseSegAfterTransfer[seg.segment];
};
AppendNecessary:
PROC [su:
LONG
POINTER
TO swapUnit BootStartList.Entry]
RETURNS [BOOL] = {RETURN[~data.scriptBase[su.parent].bootLoaded]};
Germ file output
GermMDS: CARDINAL = 37000B;
BootXferLocation: POINTER = LOOPHOLE[1376B];
GermPageCountLocation: POINTER = LOOPHOLE[1377B];
WriteGermFile:
PUBLIC
PROC = {
data.typescript.PutF["Writing *q file..."];
InitializeGermFile[];
data.nFilePages ← data.nResidentPages ← data.nBootLoadedPages ← WriteGerm[];
FinalizeGermFile[];
data.typescript.PutRope["finished writing.\N"];
IF data.etherFormat THEN MakeEtherFile[];
};
InitializeGermFile:
PROC = {
data.bootStream ← FileIO.Open[fileName: data.output, accessOptions: overwrite];
filePage ← 0;
};
FinalizeGermFile:
PROC = {
fp: Segments.FP ← FileIO.CapabilityFromStream[data.bootStream];
file: Segments.FHandle;
data.bootStream.Close[];
data.bootStream ← NIL;
Now set the create time to the desired value
file ← Segments.InsertFile[@fp, Segments.Write];
Segments.SetFileTimes[file: file, create: data.buildTime];
Segments.ReleaseFile[file];
};
WriteGerm:
PROC
RETURNS [germPages:
CARDINAL ← 0] = {
segs: MBVM.Segs = MBVM.SortSegs[];
relocationPages: CARDINAL;
RelocateGerm:
PROC = {
codeRelocation:
LONG
CARDINAL =
PrincOpsUtils.LongMult[(relocationPages ← GermMDS - data.mdsBase), wordsPerPage];
RelocateOneModule:
PROC [loadee:
MB.BHandle, mth: BcdDefs.MTHandle]
RETURNS [
BOOL] = {
gf: PrincOps.GlobalFrame;
MBVM.CopyRead[from: loadee.mt[mth.gfi].frame, to: @gf, nwords: SIZE[PrincOps.GlobalFrame]];
gf.code.longbase ← gf.code.longbase + codeRelocation;
MBVM.CopyWrite[to: loadee.mt[mth.gfi].frame, from: @gf, nwords: SIZE[PrincOps.GlobalFrame]];
RETURN[FALSE]
};
[] ← MB.DoAllModules[RelocateOneModule];
};
IF data.debug THEN MB.DumpSegs[segs, "WRITING GERM"];
RelocateGerm[];
FOR i: CARDINAL IN [0..segs.length) DO germPages ← germPages + segs[i].pages; ENDLOOP;
MBVM.Write[p: BootXferLocation, v: MB.StartControlLink[]];
MBVM.Write[p: GermPageCountLocation, v: germPages];
BootloadedHeadingToLoadmap["\N\NGERM FILE MAP\N\N"];
FOR i:
CARDINAL
IN [0..segs.length)
DO
WITH s: segs[i]
SELECT
FROM
data => WriteGermData[@s, relocationPages];
code => WriteGermCode[@s, relocationPages];
file => ERROR;
ENDCASE;
ENDLOOP;
data.loadmap.PutF["\N\NGerm file pages: %n\N", IO.card[germPages]];
WriteGermData:
PROC [seg:
MBVM.DataSeg, relocationPages:
CARDINAL] = {
v: PrincOps.InterimPageState ← MapValueForSeg[seg];
BootloadedSegToLoadmap[seg, filePage, v.flags, relocationPages];
FOR page:
CARDINAL
IN [seg.base..seg.base+seg.pages)
DO
lp: LONG POINTER = MBVM.GetPage[page];
IF lp = NIL THEN WriteEmptyPage[] ELSE WritePage[lp];
ENDLOOP;
WriteGermCode:
PROC [seg:
MBVM.CodeSeg, relocationPages:
CARDINAL] = {
v: PrincOps.InterimPageState ← MapValueForSeg[seg];
lp: LONG POINTER ← OpenSegForTransfer[seg.segment];
BootloadedSegToLoadmap[seg, filePage, v.flags, relocationPages];
THROUGH [0..seg.pages)
DO
WritePage[lp];
lp ← lp + wordsPerPage;
ENDLOOP;
CloseSegAfterTransfer[seg.segment];
};
Output Subroutines
MapValueForSeg:
PROC [seg:
MBVM.Seg]
RETURNS [PrincOps.InterimPageState] = {
flags: PrincOps.PageFlags ←
IF ~seg.info.readOnly THEN PrincOps.flagsClean ELSE PrincOps.flagsReadOnly;
reserved = FALSE (0) on a D0 means don't log single bit memory error
RETURN[PrincOps.InterimPageState[logSingleError: FALSE, flags: flags, realPage: 0]]
};
OpenSegForTransfer:
PROC [seg: Segments.SHandle]
RETURNS [lp:
LONG
POINTER] = {
Segments.SwapIn[seg];
lp ← Segments.SegmentAddress[seg];
};
CloseSegAfterTransfer:
PROC [seg: Segments.SHandle] =
INLINE {Segments.Unlock[seg]};
EnterPage:
PROC [page:
MBVM.Base, value: PrincOps.InterimPageState] = {
entries: LONG POINTER TO ARRAY [0..0) OF BootFile.Entry;
IF currentEntry = nEntries THEN AddTrailerPage[];
entries ←
IF nEntries = BootFile.maxEntriesPerTrailer THEN @trailer.entries ELSE @header.entries;
entries[currentEntry] ← [page: page, value: value];
currentEntry ← currentEntry + 1;
};
AddTrailerPage:
PROC = {
stream: IO.STREAM = data.bootStream;
IF trailer ~= NIL THEN trailerIndex ← WriteTrailerPage[]
ELSE {
create trailer page
trailer ← LOOPHOLE[NEW[PageOfWords]];
trailerIndex ← stream.GetIndex[];
};
stream.SetLength[trailerIndex+bytesPerPage];
stream.SetIndex[trailerIndex+bytesPerPage];
MB.Zero[LOOPHOLE[trailer], wordsPerPage];
trailer.version ← BootFile.currentVersion;
nEntries ← BootFile.maxEntriesPerTrailer;
currentEntry ← 0;
data.loadmap.PutF["%6n Trailer Page\N", IO.card[filePage]];
filePage ← filePage + 1;
};
WriteTrailerPage:
PROC
RETURNS [index:
INT] = {
stream: IO.STREAM = data.bootStream;
index ← stream.GetIndex[];
stream.SetIndex[trailerIndex];
stream.UnsafePutBlock[
block: [base: LOOPHOLE[trailer], startIndex: 0, stopIndexPlusOne: bytesPerPage]];
stream.SetIndex[index];
};
WritePage:
PROC [p:
LONG
POINTER] = {
filePage ← filePage + 1;
data.bootStream.UnsafePutBlock[block: [base: p, startIndex: 0, stopIndexPlusOne: bytesPerPage]];
};
WriteEmptyPage:
PROC = {
filePage ← filePage + 1;
THROUGH [0..bytesPerPage) DO data.bootStream.PutChar['\000]; ENDLOOP;
};
Loadmap Subroutines
BootloadedHeadingToLoadmap:
PROC [r: Rope.
ROPE] = {
loadmap: IO.STREAM = data.loadmap;
loadmap.PutRope[r];
loadmap.PutRope[" File VM Pages Map Type Source[base,pages]\N"];
loadmap.PutRope[" Page Address (*=Pin) Flags\N"];
};
BootloadedSegToLoadmap:
PROC [
seg: MBVM.Seg, filePage: MBVM.Base, flags: PrincOps.PageFlags, relocation: CARDINAL ← 0] = {
loadmap: IO.STREAM = data.loadmap;
BootloadedCommonToLoadmap[
filePage, seg.base.LONG + relocation, seg.pages, flags,
data.germ OR (data.scriptBase[seg.index].info.state = resident), seg];
loadmap.PutChar[Ascii.CR];
};
BootloadedSwapUnitToLoadmap:
PROC [
index: BootStartList.SwapUnitIndex, filePage: MBVM.Base, flags: PrincOps.PageFlags, seg: MBVM.Seg] = {
loadmap: IO.STREAM = data.loadmap;
su: LONG POINTER TO swapUnit BootStartList.Entry = @data.scriptBase[index];
BootloadedCommonToLoadmap[
filePage, data.scriptBase[su.parent].vmPage + su.base, su.pages, flags,
su.info.state = resident, seg];
loadmap.PutF["[%n,%n]", IO.card[su.base], IO.card[su.pages]];
IF data.debug
THEN
loadmap.PutF[" SwapUnit[%n]", IO.card[LOOPHOLE[index, CARDINAL].LONG]];
loadmap.PutChar[Ascii.CR];
};
BootloadedCommonToLoadmap:
PROC [
filePage: MBVM.Base, vmPage: PrincOps.PageNumber, pages: CARDINAL,
flags: PrincOps.PageFlags,
resident: BOOL, seg: MBVM.Seg] = {
loadmap: IO.STREAM = data.loadmap;
loadmap.PutF["%6n
%8n
%4n%g",
IO.card[filePage],
IO.card[vmPage*wordsPerPage],
IO.card[pages],
IO.rope[IF resident THEN "*" ELSE " "]
];
loadmap.PutF["
%g%g%g
",
IO.rope[IF flags.readonly THEN "W" ELSE " "],
IO.rope[IF flags.dirty THEN "D" ELSE " "],
IO.rope[IF flags.referenced THEN "R" ELSE " "]
];
SegmentSourceToLoadmap[seg];
};
NonBootloadedHeadingToLoadmap:
PROC [r: Rope.
ROPE] = {
loadmap: IO.STREAM = data.loadmap;
loadmap.PutRope[r];
loadmap.PutRope[" File VM Pages Type Source[base,pages]\N"];
loadmap.PutRope[" Page Address\N"];
};
SegToLoadmap:
PROC [seg:
MBVM.Seg, backingPage:
MBVM.Base] = {
CommonToLoadmap[backingPage, seg.base.LONG, seg.pages, seg];
data.loadmap.PutChar[Ascii.CR];
};
SwapUnitToLoadmap:
PROC [
index: BootStartList.SwapUnitIndex, backingPage: MBVM.Base, seg: MBVM.Seg] = {
loadmap: IO.STREAM = data.loadmap;
su: LONG POINTER TO swapUnit BootStartList.Entry = @data.scriptBase[index];
CommonToLoadmap[
backingPage, data.scriptBase[su.parent].vmPage + su.base, su.pages, seg];
loadmap.PutF["[%n,%n]", IO.card[su.base], IO.card[su.pages]];
IF data.debug
THEN
loadmap.PutF[" SwapUnit[%n]", IO.card[LOOPHOLE[index, CARDINAL].LONG]];
loadmap.PutChar[Ascii.CR];
};
CommonToLoadmap:
PROC [
filePage: MBVM.Base, vmPage: PrincOps.PageNumber, pages: CARDINAL, seg: MBVM.Seg] = {
data.loadmap.PutF["%6n
%8n
%4n
",
IO.card[filePage],
IO.card[vmPage*wordsPerPage],
IO.card[pages]
];
SegmentSourceToLoadmap[seg];
};
SegmentSourceToLoadmap:
PROC [seg:
MBVM.Seg] = {
loadmap: IO.STREAM = data.loadmap;
file: Segments.FHandle;
fileBase: CARDINAL;
WITH s: seg
SELECT
FROM
data => {loadmap.PutRope["data"]; RETURN};
code => {loadmap.PutRope["code "]; file ← s.file; fileBase ← s.fileBase};
file => {loadmap.PutRope["file "]; file ← s.file; fileBase ← s.fileBase};
ENDCASE;
data.loadmap.PutF["%f[%n,%n]", IO.card[LOOPHOLE[file.LONG]], IO.card[fileBase], IO.card[seg.pages]];
};
Ether Boot/Germ Output
MakeEtherFile:
PROC = {
inStream, outStream: IO.STREAM ← NIL;
name: STRING ← [40];
bufferPages: CARDINAL = 50;
bufferSpace: Space.Handle = Space.Create[bufferPages, Space.virtualMemory];
buffer: LONG POINTER = Space.LongPointer[bufferSpace];
PutEtherHeader:
PROC [stream:
IO.
STREAM] = {
etherHeader: EtherHeader ← [createTime: MesaToBCPLTime[data.buildTime]];
stream.UnsafePutBlock[
block: [base: @etherHeader, startIndex: 0, stopIndexPlusOne: 2*SIZE[EtherHeader]]];
stream.UnsafePutBlock[
block: [base: name, startIndex: 0, stopIndexPlusOne: 2*SIZE[StringBody[name.maxlength]]]];
THROUGH [2*(
SIZE[EtherHeader]+
SIZE[StringBody[name.maxlength]])..bytesPerPage)
DO
stream.PutChar['\000];
ENDLOOP;
};
MesaToBCPLTime:
PROC [t: Time.Packed]
RETURNS [BCPLTime] =
INLINE
{RETURN [[high: PrincOpsUtils.HighHalf[t], low: PrincOpsUtils.LowHalf[t]]]};
Space.Map[bufferSpace];
data.typescript.PutF["Writing ether *q file..."];
{
ENABLE
UNWIND => {
IF inStream ~= NIL THEN inStream.Close[];
IF outStream ~= NIL THEN outStream.Close[];
Space.Delete[bufferSpace];
};
ConvertUnsafe.AppendRope[to: name, from: data.output];
inStream ← FileIO.Open[fileName: data.output];
outStream ← FileIO.Open[
fileName: data.etherOutput, accessOptions: overwrite,
createLength: inStream.GetLength[] + bytesPerPage
];
PutEtherHeader[outStream];
DO
bytes:
INT = inStream.UnsafeGetBlock[
block: [base: buffer, startIndex: 0, stopIndexPlusOne: bufferPages*bytesPerPage]];
IF bytes = 0 THEN EXIT;
outStream.UnsafePutBlock[block: [base: buffer, startIndex: 0, stopIndexPlusOne: bytes]];
ENDLOOP;
};
inStream.Close[];
outStream.Close[];
Space.Delete[bufferSpace];
data.typescript.PutRope["finished writing.\N"];
};
END.