MBDriver.mesa
Edited by Sandman on 6-Aug-81 15:40:03
Edited by Lewis on 28-Sep-81 16:46:51
Edited by Levin on April 13, 1983 5:00 pm
DIRECTORY
Ascii USING [CR, NUL],
Commander USING [CommandProc, Register],
Exec USING [AddCommand, GetChar, status, w],
File USING [Capability],
Heap USING [Create, Delete],
Inline USING [LongCOPY],
IO USING [EndOf, GetChar, RIS, STREAM],
LongString USING [AppendString, EquivalentString, InvalidNumber, StringToDecimal],
MB USING [
Abort, BCount, BHandle, BIndex, BObject, DumpBootHeader, DumpFrames, DumpInputBcds, DumpStartList, EchoInput, Error, FinishCache, FinishDebug, FinishLoader, FinishLoadmap, FinishMain, FinishOutput, FinishParse, FinishScript, FinishUtilities, FinishVM, Handle, InitCache, InitDebug, InitLoader, InitLoadmap, InitMain, InitMemory, InitOutput, InitParse, InitScript, InitUtilities, InitVM, InputBCDs, Load, MakeScript, Object, ProcessInput, ReportFrameAllocation, TurnOffStartTrap, WriteBootFile, WriteGermFile],
MBCommandUtil USING [
CommandObject, CommandPtr, CopyString, Create, Destroy, Failed, FreePairList, FreeString, GetNthPair, ListLength, PairList, Parse, SetExtension],
MBOut USING [Char, CR, OpenLoadmap, Spaces, Text, Time],
MBTTY USING [
Handle, PutChar, PutCR, PutDecimal, PutLine, PutLongDecimal, PutLongNumber, PutString, UserAbort],
PrincOps USING [GFTIndex],
PSB USING [PsbIndex],
Runtime USING [CallDebugger, GetBcdTime, GlobalFrame, IsBound],
RuntimeInternal USING [Codebase],
Segments USING [FHandle, FileNameProblem, FPFromFile, GetFileTimes, NewFile, ReleaseFile],
Space USING [GetAttributes, GetHandle, GetWindow, Handle, PageFromLongPointer],
Time USING [Append, Current, Packed, Unpack],
TTYIO USING [CreateTTYHandleFromStreams],
Volume USING [InsufficientSpace];
MBDriver: MONITOR
IMPORTS
Commander, Exec, Heap, Inline, IO, MB, MBCommandUtil, MBOut, MBTTY, Runtime, RuntimeInternal, Segments, Space, String: LongString, Time, TTYIO, Volume
EXPORTS MB
SHARES File =
BEGIN
useCommander: BOOL = Runtime.IsBound[Commander.Register]; -- *** temporary
data: MB.Handle ← NIL;
tty: MBTTY.Handle;
commandStream: IO.STREAM;
Outcome: TYPE = Exec.status;
RunFromCommander: Commander.CommandProc = TRUSTED {
commandStream ← IO.RIS[cmd.commandLine];
tty ← TTYIO.CreateTTYHandleFromStreams[in: cmd.in, out: cmd.out];
[] ← DoRun[];
};
RunFromExec: PROC = {
tty ← Exec.w;
[] ← DoRun[];
};
DoRun: ENTRY PROC RETURNS [outcome: Outcome] = {
ENABLE UNWIND => NULL;
WriteHerald[Time.Current[]];
DO -- until no commands remain
start: LONG CARDINAL ← Time.Current[];
nFilePages, nModules, nGFIs, nResidentPages, nBootLoadedPages: CARDINAL;
outcome ← abort;
Initialize[];
outcome ← DoWork[
! UNWIND => Finalize[];
MB.Abort, ABORTED => CONTINUE;
Volume.InsufficientSpace => {MBTTY.PutLine[tty, "!Disk full"L]; CONTINUE};
Segments.FileNameProblem[] => {
MBTTY.PutString[tty, "!Can't find "L]; MBTTY.PutLine[tty, name];
CONTINUE
}
];
SELECT outcome FROM
normal => {
nFilePages ← data.nFilePages;
nModules ← data.nModules;
nGFIs ← data.nGFIs;
nResidentPages ← data.nResidentPages;
nBootLoadedPages ← data.nBootLoadedPages;
};
abort => {MBTTY.PutLine[tty, "...MakeBoot aborted"L]; EXIT};
spare1 --no commands remain-- => {outcome ← normal; EXIT};
ENDCASE --warning or error-- => EXIT;
Finalize[];
ReportStats[
nFilePages: nFilePages, nModules: nModules, nGFIs: nGFIs,
nResidentPages: nResidentPages, nBootLoadedPages: nBootLoadedPages,
elapsedTime: (LOOPHOLE[Time.Current[], LONG CARDINAL] - start)];
ENDLOOP;
Finalize[];
};
WriteHerald: PROC [now: Time.Packed] = {
herald: STRING ← [80];
MakeBootVersion[herald];
MBTTY.PutLine[tty, herald];
herald.length ← 0;
Time.Append[herald, Time.Unpack[[now]]];
herald.length ← herald.length-3; -- remove seconds
MBTTY.PutLine[tty, herald];
};
Initialize: PROC = {
the following must be first
InitDriver[];
The order of the following is arbitrary.
MB.InitCache[data];
MB.InitDebug[data];
MB.InitLoader[data];
MB.InitLoadmap[data];
MB.InitMain[data];
MB.InitOutput[data];
MB.InitParse[data];
MB.InitScript[data];
MB.InitUtilities[data];
MB.InitVM[data];
};
Finalize: PROC = {
The ordering of the following is significant.
MB.FinishOutput[];
MB.FinishLoader[];
The ordering of the following is arbitrary.
MB.FinishVM[];
MB.FinishUtilities[];
MB.FinishScript[];
MB.FinishParse[];
MB.FinishMain[];
MB.FinishLoadmap[];
MB.FinishDebug[];
MB.FinishCache[];
the following must be last
FinishDriver[];
};
InitDriver: PROC = {
zone: UNCOUNTED ZONE ← Heap.Create[initial: 4, swapUnit: 1];
data ← zone.NEW[MB.Object];
Zero[data, SIZE[MB.Object]];
data.zone ← zone;
data.buildTime ← Time.Current[];
data.ttyHandle ← tty;
data.inputBCDs ← data.zone.NEW[MB.InputBCDs[10] ← [nBcds: 1]];
create BObject describing main input Bcd, used by ProcessCmds
data.inputBCDs.bcds[0] ← data.zone.NEW[MB.BObject ← [
name: NIL,
bcd: NIL, bcdSeg: NIL, bcdSegment: NIL,
mt: DESCRIPTOR[NIL, 0], gfiOffset: 0,
files: NIL]];
};
FinishDriver: PROC = {
zone: UNCOUNTED ZONE ← data.zone;
[] ← MBCommandUtil.FreeString[data.input];
[] ← MBCommandUtil.FreeString[data.output];
[] ← MBCommandUtil.FreeString[data.etherOutput];
[] ← MBCommandUtil.FreeString[data.loadmap];
FOR i: MB.BIndex IN [0..data.inputBCDs.nBcds) DO
IF data.inputBCDs.bcds[i] ~= NIL THEN {
[] ← MBCommandUtil.FreeString[data.inputBCDs.bcds[i].name];
data.zone.FREE[@data.inputBCDs.bcds[i]];
};
ENDLOOP;
zone.FREE[@data.inputBCDs];
zone.FREE[@data];
Heap.Delete[zone];
};
DoWork: PROC RETURNS [outcome: Outcome] = {
CheckAbort: PROC = {IF MBTTY.UserAbort[tty] THEN ERROR MB.Abort};
CheckAbort[];
IF (outcome ← ProcessCmds[]) ~= normal THEN RETURN;
MBOut.OpenLoadmap[];
MB.InitMemory[];
CheckAbort[];
EchoBCDs[];
MB.EchoInput[];
CheckAbort[];
MB.Load[];
CheckAbort[];
MB.TurnOffStartTrap[];
MB.ReportFrameAllocation[];
IF data.debug THEN {MB.DumpInputBcds[]; MB.DumpFrames[]};
CheckAbort[];
IF data.germ THEN MB.WriteGermFile[]
ELSE {
MB.MakeScript[];
CheckAbort[];
MB.WriteBootFile[];
};
CheckAbort[];
IF data.debug AND ~data.germ THEN {MB.DumpBootHeader[]; MB.DumpStartList[]};
RETURN[normal]
};
ProcessCmds: PROC RETURNS [outcome: Outcome] = {
args, results: MBCommandUtil.PairList;
switches, sourceName: LONG STRINGNIL;
commandPtr: MBCommandUtil.CommandPtr ← MBCommandUtil.Create[GetChar];
GetChar: PROC RETURNS [char: CHARACTER] = {
IF useCommander THEN { -- *** temporary
IF commandStream.EndOf[] THEN RETURN [Ascii.NUL];
char ← commandStream.GetChar[];
IF char = Ascii.CR THEN char ← Ascii.NUL;
}
ELSE RETURN[Exec.GetChar[]]};
CleanupParse: PROC = {
IF sourceName ~= NIL THEN {
[] ← MBCommandUtil.FreeString[sourceName];
[] ← MBCommandUtil.FreePairList[args];
[] ← MBCommandUtil.FreePairList[results];
[] ← MBCommandUtil.FreeString[switches];
};
MBCommandUtil.Destroy[commandPtr];
};
BEGIN
[sourceName, args, results, switches] ← MBCommandUtil.Parse[
cmd: commandPtr, opX: 2+("bcd"L).length, resultX: 2+("boot"L).length
! MBCommandUtil.Failed => GOTO badCommands];
IF sourceName = NIL THEN {CleanupParse[]; RETURN[outcome: spare1]}; -- no commands remain
EXITS
badCommands => {
MBTTY.PutLine[tty, "!Bad MakeBoot command line"L];
CleanupParse[];
RETURN[outcome: error]
}
END;
IF switches # NIL THEN {
sense: BOOLEANTRUE;
FOR i: CARDINAL IN [0..switches.length) DO
SELECT switches[i] FROM
'-, '~ => sense ← ~sense;
'd, 'D => {data.debug ← sense; sense ← TRUE};
'e, 'E => {data.etherFormat ← sense; sense ← TRUE};
'g, 'G => {data.germ ← sense; sense ← TRUE};
'h, 'H => {data.hexLoadmap ← sense; sense ← TRUE};
'! => Runtime.CallDebugger["Called from MakeBoot"L];
ENDCASE;
ENDLOOP;
};
data.input ← MBCommandUtil.CopyString[s: sourceName, extra: (".bcd"L).length];
data.input ← MBCommandUtil.SetExtension[root: data.input, defaultExt: "bcd"L];
data.inputBCDs.bcds[0].name ← MBCommandUtil.CopyString[data.input];
ProcessResults[results ! UNWIND => CleanupParse[]];
EchoCommand[];
ProcessArgs[args ! UNWIND => CleanupParse[]];
CleanupParse[];
RETURN[outcome: normal]
};
EchoCommand: PROC = {
MBTTY.PutString[tty, "Building "L];
MBTTY.PutString[tty, IF data.germ THEN "germ"L ELSE "boot"L];
MBTTY.PutString[tty, " file "L]; MBTTY.PutString[tty, data.output];
IF data.etherFormat THEN {
MBTTY.PutString[tty, " and ether "L];
MBTTY.PutString[tty, IF data.germ THEN "germ"L ELSE "boot"L];
MBTTY.PutString[tty, " file "L]; MBTTY.PutString[tty, data.etherOutput];
};
MBTTY.PutCR[tty];
MBTTY.PutString[tty, "Writing load map to "L]; MBTTY.PutString[tty, data.loadmap];
MBTTY.PutCR[tty];
};
EchoBCDs: PROC = {
MBOut.Text["Input BCD"L];
IF data.inputBCDs.nBcds ~= 0 THEN MBOut.Char['s];
MBOut.Char[':]; MBOut.CR[]; MBOut.CR[];
FOR i: CARDINAL IN [0..data.inputBCDs.nBcds) DO
file: STRING = [40];
String.AppendString[file, data.inputBCDs.bcds[i].name];
MBOut.Spaces[2]; MBOut.Text[file, 39]; MBOut.Spaces[2];
{ENABLE Segments.FileNameProblem[] => CONTINUE;
MBOut.Time[Segments.GetFileTimes[Segments.NewFile[file]].create];
};
MBOut.CR[];
ENDLOOP;
MBOut.CR[];
};
ProcessResults: PROC [results: MBCommandUtil.PairList] = {
key, value: LONG STRING;
bootFileExt: LONG STRING = IF data.germ THEN "germ"L ELSE "boot"L;
loadMapExt: LONG STRING = "loadmap"L;
data.output ← data.etherOutput ← data.loadmap ← NIL;
FOR i: CARDINAL IN [0..MBCommandUtil.ListLength[results]) DO
[key: key, value: value] ← MBCommandUtil.GetNthPair[results, i];
SELECT TRUE FROM
key = NIL =>
data.output ← MBCommandUtil.CopyString[s: value, extra: bootFileExt.length+1];
String.EquivalentString["bootFile"L, key] =>
IF data.output = NIL THEN
data.output ← MBCommandUtil.CopyString[s: value, extra: bootFileExt.length+1]
ELSE MB.Error["Duplicate result keyword 'bootFile'"L];
String.EquivalentString["loadMap"L, key] =>
IF data.loadmap = NIL THEN
data.loadmap ← MBCommandUtil.CopyString[s: value, extra: loadMapExt.length+1]
ELSE MB.Error["Duplicate result keyword 'loadMap'"L];
ENDCASE => MB.Error["Unrecognized result keyword"L];
ENDLOOP;
IF data.output = NIL THEN
StripExtension[data.output ← MBCommandUtil.CopyString[data.input]];
data.output ← MBCommandUtil.SetExtension[root: data.output, defaultExt: bootFileExt];
IF data.etherFormat THEN {
etherExt: STRING = IF data.germ THEN "eg"L ELSE "pb"L;
data.etherOutput ← MBCommandUtil.CopyString[s: data.output, extra: etherExt.length+1];
StripExtension[data.etherOutput];
data.etherOutput ←
MBCommandUtil.SetExtension[root: data.etherOutput, defaultExt: etherExt];
};
EnsureNotCurrentBootFile[];
IF data.loadmap = NIL THEN
StripExtension[data.loadmap ← MBCommandUtil.CopyString[data.output]];
data.loadmap ← MBCommandUtil.SetExtension[root: data.loadmap, defaultExt: loadMapExt];
};
StripExtension: PROC [s: LONG STRING] = {
FOR i: CARDINAL IN [0..s.length) DO
IF s[i] = '. THEN {s.length ← i; RETURN};
ENDLOOP;
};
EnsureNotCurrentBootFile: PROC = {
name: STRING ← [40];
cap: File.Capability;
someBootFileCode: Space.Handle ←
Space.GetHandle[Space.PageFromLongPointer[
RuntimeInternal.Codebase[Runtime.GlobalFrame[Space.GetHandle]]]];
file: Segments.FHandle;
String.AppendString[name, data.output];
file ← Segments.NewFile[name ! Segments.FileNameProblem[] => GO TO ok];
Segments.FPFromFile[file, @cap];
Segments.ReleaseFile[file];
DO
parent: Space.Handle;
mapped: BOOL;
[parent: parent, mapped: mapped] ← Space.GetAttributes[someBootFileCode];
IF mapped THEN EXIT;
someBootFileCode ← parent;
ENDLOOP;
IF Space.GetWindow[someBootFileCode].file.fID = cap.fID THEN
MB.Error["I refuse to overwrite the currently executing boot file."L];
EXITS ok => NULL;
};
ProcessArgs: PROC [args: MBCommandUtil.PairList] = {
key, value: LONG STRING;
nProcesses, gftLength: CARDINALLAST[CARDINAL];
FOR i: CARDINAL IN [0..MBCommandUtil.ListLength[args]) DO
[key: key, value: value] ← MBCommandUtil.GetNthPair[args, i];
SELECT TRUE FROM
String.EquivalentString["parm"L, key] => {
parmFile: LONG STRING
MBCommandUtil.CopyString[s: value, extra: (".bootmesa"L).length];
parmFile ← MBCommandUtil.SetExtension[root: parmFile, defaultExt: "bootmesa"L];
MBTTY.PutString[tty, "Processing parameter file "L];
MBTTY.PutString[tty, parmFile];
MB.ProcessInput[parmFile ! UNWIND => [] ← MBCommandUtil.FreeString[parmFile]];
parmFile ← MBCommandUtil.FreeString[parmFile];
MBTTY.PutCR[tty];
};
String.EquivalentString["bcd"L, key] => {
bH: MB.BHandle;
IF data.inputBCDs.nBcds = LAST[MB.BCount] - 1 --save slot for NullConfig-- THEN
MB.Error["Too many input BCDs"L];
IF data.inputBCDs.nBcds = data.inputBCDs.length THEN {
newLength: MB.BCount = MIN[2*data.inputBCDs.length, LAST[MB.BCount]];
newInputBCDs: LONG POINTER TO MB.InputBCDs ←
data.zone.NEW[MB.InputBCDs[newLength] ← [nBcds: data.inputBCDs.nBcds]];
Inline.LongCOPY[
from: @data.inputBCDs.bcds[0], to: @newInputBCDs.bcds[0],
nwords: data.inputBCDs.nBcds*SIZE[MB.BHandle]];
data.zone.FREE[@data.inputBCDs];
data.inputBCDs ← newInputBCDs};
bH ← data.zone.NEW[MB.BObject ← [
name: NIL,
bcd: NIL, bcdSeg: NIL, bcdSegment: NIL,
mt: DESCRIPTOR[NIL, 0], gfiOffset: 0,
files: NIL]];
bH.name ← MBCommandUtil.CopyString[s: value, extra: (".bcd"L).length];
bH.name ← MBCommandUtil.SetExtension[root: bH.name, defaultExt: "bcd"L];
data.inputBCDs.bcds[data.inputBCDs.nBcds] ← bH;
data.inputBCDs.nBcds ← data.inputBCDs.nBcds+1;
};
String.EquivalentString["nProcesses"L, key] => {
nProcesses ← String.StringToDecimal[value ! String.InvalidNumber => GO TO bogus];
IF ~(nProcesses-1 IN PSB.PsbIndex) THEN GO TO bogus;
EXITS
bogus => MB.Error["Invalid nProcesses"L];
};
String.EquivalentString["gftLength"L, key] => {
gftLength ← String.StringToDecimal[value ! String.InvalidNumber => GO TO bogus];
IF ~(gftLength-1 IN PrincOps.GFTIndex) THEN GO TO bogus;
EXITS
bogus => MB.Error["Invalid gftLength"L];
};
ENDCASE => MB.Error["Unrecognized parameter keyword"L];
ENDLOOP;
IF nProcesses ~= LAST[CARDINAL] THEN {
data.nProcesses ← nProcesses;
MBTTY.PutString[tty, "Number of processes set to "L];
MBTTY.PutDecimal[tty, nProcesses];
MBTTY.PutCR[tty];
};
IF gftLength ~= LAST[CARDINAL] THEN {
data.gftLength ← gftLength;
MBTTY.PutString[tty, "GFT length set to "L];
MBTTY.PutDecimal[tty, gftLength];
MBTTY.PutCR[tty];
};
};
ReportStats: PROC [
nFilePages, nModules, nGFIs, nResidentPages, nBootLoadedPages: CARDINAL,
elapsedTime: LONG CARDINAL] = {
OPEN MBTTY;
PutString[tty, "Boot file pages: "L];
PutDecimal[tty, nFilePages];
PutString[tty, " ("L];
PutDecimal[tty, nBootLoadedPages];
PutString[tty, " bootloaded, of which "L];
PutDecimal[tty, nResidentPages];
PutLine[tty, " are resident)"L];
PutString[tty, "Modules: "L];
PutDecimal[tty, nModules];
PutString[tty, " (requiring "L];
PutDecimal[tty, nGFIs];
PutLine[tty, " GFIs)"L];
PutString[tty, "Time: "L];
IF elapsedTime > 60 THEN {
PutLongDecimal[tty, elapsedTime/60]; PutChar[tty, ':];
elapsedTime ← elapsedTime MOD 60;
};
PutLongNumber[tty, elapsedTime, [base: 10, zerofill: TRUE, unsigned: TRUE, columns: 2]];
PutCR[tty];
};
Miscellaneous Utilities
Abort: PUBLIC SIGNAL = CODE;
Error: PUBLIC PROC [msg: STRING] = {
MBTTY.PutCR[data.ttyHandle];
MBTTY.PutString[data.ttyHandle, "MakeBoot Error: "L];
MBTTY.PutLine[data.ttyHandle, msg];
SIGNAL MB.Abort;
};
Zero: PUBLIC PROC [p: LONG POINTER, n: CARDINAL] = {
IF n # 0 THEN {p^ ← 0; Inline.LongCOPY[from: p, to: p+1, nwords: n-1]};
};
MakeBootVersion: PUBLIC PROC [s: STRING] = {
s.length ← 0;
String.AppendString[s, "Cedar MakeBoot of "L];
Time.Append[s, Time.Unpack[Runtime.GetBcdTime[]]];
s.length ← s.length-3; -- remove seconds
};
Init: PROC = {
IF useCommander THEN -- *** temporary
Commander.Register[key: "MakeBoot", proc: RunFromCommander, doc: NIL]
ELSE Exec.AddCommand["MakeBoot.~"L, RunFromExec];
};
Init[];
END.