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 September 30, 1983 4:08 pm
DIRECTORY
Ascii USING [CR],
Basics USING [LongMult, LongNumber],
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 [
bool, card, Close, GetIndex, GetLength, PutChar, PutF, PutRope, rope, SetIndex, SetLength, STREAM, UnsafeGetBlock, UnsafePutBlock],
MB USING [BHandle, DoAllModules, DumpSegs, Handle, StartControlLink],
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 [LowHalf, ZERO],
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 Basics, 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.PutRope["Writing boot 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: Basics.LongMult[data.nFilePages, bytesPerPage]
];
data.bootStream.SetLength[bytesPerPage];
data.bootStream.SetIndex[bytesPerPage];
data.bootHeader ← header ← LOOPHOLE[NEW[PageOfWords]];
PrincOpsUtils.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 CARDINAL[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.PutRope["Writing germ 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 =
Basics.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];
PrincOpsUtils.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.STREAMNIL;
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 {
ln: Basics.LongNumber = LOOPHOLE[t];
RETURN [[high: ln.highbits, low: ln.lowbits]]
};
Space.Map[bufferSpace];
data.typescript.PutF["Writing ether %y file...", IO.bool[data.germ]];
{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.