-- NXControl.mesa; edited by Gobbel; January 16, 1981 9:32 PM
-- Last modified December 14, 1983 2:29 PM by Taft
-- Last modified June 13, 1986 6:08 PM by Wyatt
DIRECTORY
AltoDisplay USING [DCBchainHead, DCBHandle, DCBnil],
BcplOps USING [BcplJSR],
Boot: FROM "BootX" USING [bootPhysicalVolume, inLoad, Location, nullDiskFileID, Request,
pRequest],
BootDirDefs USING [cmd, CmdDirEntry, CmdDirEntryPtr, DirEntryPtr,
DirEntryType, file, FileDirEntryPtr, germ, InsertDirEntry, killProber,
ListPossibleMatches, Lookup, ProbeProcess, uCode],
BootSwap USING [sPilotSwitches],
ControlDefs USING [FieldDescriptor, FrameHandle],
DeviceTypes USING [ethernet, sa4000],
DiskDefs USING [
CB, CBptr, DA, DL, DS, DSdone, DSgoodStatus, DSmaskStatus, InvalidDA],
EFTPDefs USING [EFTPAbortReceiving, EFTPEndReceiving,
EFTPFinishReceiving, EFTPGetBlock, EFTPOpenForReceiving,
EFTPSetRecvTimeout, EFTPTimeOut],
IODefs USING [BS, ControlA, ControlW, CR, DEL, ESC, NewLine, ReadChar, ReadLine,
Rubout, SP, WriteChar, WriteLine, WriteDecimal, WriteOctal, WriteString],
InlineDefs USING [BITAND, BITSHIFT, BITXOR, LongCOPY],
KeyDefs USING [Keys],
MiscDefs USING [CallDebugger, Zero],
MMOps USING [BootViaNet, MakeBoot],
Mopcodes USING [zLI4, zMISC, zRBL, zSHIFT, zSTARTIO, zWFS],
NXDefs USING [Erase, Host, illPtr, Line, LineReset, NewLine, NoteUserAction,
NXDisplay, ResetTo, Timer, SetTime, UserAbort, WatchDog],
OsStaticDefs USING [OsStatics, AltoVersionNumber],
ProcessDefs USING [
Detach, DisableInterrupts, EnableInterrupts, MsecToTicks, SetTimeout],
PupDefs USING [AppendPupAddress, GetFreePupBuffer, PupBuffer,
PupPackageMake, PupRouterSendThis, SetPupContentsWords,
UniqueLocalPupAddress],
PupTypes USING [PupAddress],
SDDefs USING [SD, sUncaughtSignal],
StringDefs USING [AppendChar, AppendDecimal, AppendString,
AppendSubString, EquivalentSubStrings, InvalidNumber, StringToDecimal,
SubStringDescriptor],
SystemDefs USING [AllocateHeapNode, AllocateResidentPages, FreePages],
StartList,
TemporaryBooting USING [defaultSwitches, Switches, UpDown],
TimeDefs USING [AppendDayTime, PackedTime, UnpackDT];
NXControl: MONITOR
IMPORTS BootDirDefs, EFTPDefs, InlineDefs, IODefs,
MiscDefs, MMOps, BcplOps, NXDefs, ProcessDefs, PupDefs, StringDefs,
SystemDefs, TimeDefs
EXPORTS NXDefs
SHARES DiskDefs =
BEGIN OPEN BootDirDefs, DiskDefs;
req: Boot.Request;
switches: TemporaryBooting.Switches ← TemporaryBooting.defaultSwitches;
switchString: STRING ← [30];
cursor: POINTER TO ARRAY [0..16) OF WORD = LOOPHOLE[431B];
doneCursor: ARRAY [0..16) OF WORD ← -- "Loaded"
[160000B, 40000B, 41616B, 42122B,
42116B, 46122B, 175637B, 0,
30006B, 10002B, 10002B, 70616B,
111122B, 111722B, 111022B, 74717B];
Question: SIGNAL [s: STRING] = CODE;
alto: BOOLEAN;
debug: PUBLIC BOOLEAN ← FALSE;
CmdRec: TYPE = RECORD [
proc: PROC, name: STRING, validOnAlto: BOOLEAN ← TRUE];
nCommands: CARDINAL = 11;
cmdTable: ARRAY [0..nCommands) OF CmdRec = [
[BootDP0, "BootDP0"],
[Cedar, "Cedar", FALSE],
[FileStat, "FileStat"],
[Othello, "Othello", FALSE],
[Partition, "Partition", FALSE],
[PhysVolBoot, "PhysicalVolumeBoot", FALSE],
[Probe, "Probe"],
[Quit, "Quit"],
[ReadSwitches, "Switches", FALSE],
[SetTimeCmd, "SetTime"],
[SetVersions, "SetVersions", FALSE]];
Catcher: PROC [msg, signal: UNSPECIFIED, frame: ControlDefs.FrameHandle] =
{MiscDefs.CallDebugger["UNCAUGHT SIGNAL"L]};
Run: PROCEDURE =
BEGIN OPEN IODefs;
cmdPtr: DirEntryPtr;
DO ENABLE
BEGIN
Rubout => BEGIN WriteString[" XXX"L]; LOOP END;
Question =>
BEGIN ENABLE NXDefs.UserAbort => GOTO Aborted;
NXDefs.LineReset["Command, from:"L];
ListPossibleMatches[s, cmd];
NXDefs.NewLine[]; NXDefs.Line["or boot file, from:"L];
ListPossibleMatches[s, file]; WriteChar[CR];
RESUME;
EXITS Aborted => RESUME;
END;
END;
IF ~IODefs.NewLine[] THEN WriteChar[CR]; WriteChar['>];
cmdPtr ← ReadCmd[">"L];
WITH entry: cmdPtr SELECT FROM
cmd => entry.proc[];
file =>
SELECT entry.sysType FROM
alto => MMOps.BootViaNet[entry.bfn, entry.host.host];
pilot => EtherBoot[@entry];
ENDCASE;
ENDCASE;
ENDLOOP;
END;
ReadCmd: PROC [
prompt: STRING, type: DirEntryType ← cmd+file,
acceptDefault: BOOLEAN ← FALSE, default: STRING ← ""L]
RETURNS [cmdPtr: DirEntryPtr] =
BEGIN OPEN IODefs, NXDefs, StringDefs;
s: STRING ← [45];
startOver: BOOLEAN ← default.length>0;
s.length ← 0; AppendString[s, default];
DO
SELECT ReadName[prompt, s, startOver] FROM
CR, ESC, SP =>
BEGIN
IF s.length=0 THEN IF acceptDefault THEN RETURN[NIL] ELSE
{FlashDisplay[]; LOOP};
cmdPtr ← Lookup[s, type];
SELECT cmdPtr FROM
NIL =>
{FlashDisplay[]; WriteString[" ?"L]; startOver ← TRUE;
Probe[]; LOOP};
illPtr => FlashDisplay[];
ENDCASE => RETURN;
END;
ENDCASE;
startOver ← FALSE;
ENDLOOP;
END;
ReadDecimal: PROC [
prompt: STRING, acceptDefault: BOOLEAN ← FALSE, default: CARDINAL ← 0]
RETURNS [CARDINAL] =
BEGIN OPEN IODefs, NXDefs, StringDefs;
s: STRING ← [45];
startOver: BOOLEAN ← acceptDefault;
s.length ← 0;
IF acceptDefault THEN AppendDecimal[s, default];
DO ENABLE Question =>
BEGIN
WriteChar['?]; WriteChar[CR];
WriteLine[" Decimal number"L];
WriteString[prompt]; WriteString[s]; LOOP
END;
SELECT ReadName[prompt, s, startOver] FROM
CR, ESC, SP => RETURN[StringToDecimal[s ! InvalidNumber =>
{WriteString[" ?"L]; CONTINUE}]];
'? =>
BEGIN
WriteChar['?]; WriteChar[CR];
WriteLine[" Decimal number"L];
WriteString[prompt]; WriteString[s]; LOOP
END;
ENDCASE;
startOver ← FALSE;
ENDLOOP;
END;
ReadName: PROC [prompt, s: STRING, new: BOOLEAN]
RETURNS [c: CHARACTER] =
BEGIN OPEN IODefs, NXDefs, StringDefs;
DO
c ← ReadChar[]; NoteUserAction[];
ResetTo[prompt.length+s.length];
SELECT c FROM
BS, ControlA => Erase[1, s];
SP, CR, ESC => RETURN;
DEL => SIGNAL Rubout;
ControlW => Erase[s.length, s];
'? =>
BEGIN
WriteChar['?]; WriteChar[CR];
SIGNAL Question[IF new THEN ""L ELSE s];
WriteString[prompt]; WriteString[s]; LOOP
END;
>SP =>
BEGIN
IF new THEN {ResetTo[prompt.length]; s.length ← 0};
IF s.length=s.maxlength THEN {FlashDisplay[]; LOOP};
WriteChar[c]; AppendChar[s, c];
END;
ENDCASE => FlashDisplay[];
new ← FALSE;
ENDLOOP;
END;
FlashDisplay: PROC =
BEGIN
dcb: AltoDisplay.DCBHandle;
FOR dcb ← AltoDisplay.DCBchainHead↑, dcb.next UNTIL dcb=NIL DO
dcb.background ← black ENDLOOP;
THROUGH [0..10000] DO ENDLOOP;
FOR dcb ← AltoDisplay.DCBchainHead↑, dcb.next UNTIL dcb=NIL DO
dcb.background ← white ENDLOOP;
END;
InstallCommands: PROC =
BEGIN OPEN SystemDefs;
entry: CmdDirEntryPtr;
FOR i: CARDINAL IN [0..nCommands) DO
IF alto AND ~cmdTable[i].validOnAlto THEN LOOP;
entry ← AllocateHeapNode[SIZE[CmdDirEntry]];
entry.name ← cmdTable[i].name;
entry.vp ← cmd[cmdTable[i].proc];
InsertDirEntry[entry];
ENDLOOP;
END;
Quit: PROC = {MMOps.BootViaNet[0]};
Probe: PROC = {ProcessDefs.Detach[FORK ProbeProcess[]]};
SetTimeCmd: PROC = {ProcessDefs.Detach[FORK NXDefs.SetTime[]]};
Partition: PROC =
BEGIN OPEN IODefs, BcplOps;
setPartition: RECORD [a, b: WORD] ← [61037B, 1400B];
partition, status: CARDINAL;
status ← BcplJSR[JSR, @setPartition, 0];
WriteString[" number "L]; WriteDecimal[status];
partition ← ReadDecimal[">Partition number "L, TRUE, status];
[] ← BcplJSR[JSR, @setPartition, partition];
END;
BootDP0: PROC =
BEGIN OPEN AltoDisplay, DiskDefs, InlineDefs, IODefs, SystemDefs;
StartIO: PROC [CARDINAL] = MACHINE CODE BEGIN Mopcodes.zSTARTIO END;
i: CARDINAL;
bltAndJump: ARRAY [0..5] OF UNSPECIFIED ← [
111000B, -- mov 0 2
21000B, -- lda 0 0, 2
25001B, -- lda 1 1, 2
35002B, -- lda 3 2, 2
61005B, -- blt
1]; -- jmp 1
bltArgs: RECORD [a, b, c: UNSPECIFIED];
cb: CBptr ← AllocateHeapNode[SIZE[CB]];
oldDCBChainHead: DCBHandle;
label: POINTER TO DL ← AllocateHeapNode[SIZE[DL]];
data: POINTER TO ARRAY [0..256) OF WORD
← LOOPHOLE[AllocateResidentPages[1]];
csb: POINTER TO CSB = LOOPHOLE[521B];
keys: POINTER TO WORD = LOOPHOLE[177034B];
bootLabel: POINTER TO DL = LOOPHOLE[402B];
bootStatus: POINTER ← data+1;
CSB: TYPE = RECORD [cb: CBptr, status: DS, addr: DA];
oldDCBChainHead ← DCBchainHead↑;
ProcessDefs.DisableInterrupts[];
DCBchainHead↑ ← DCBnil;
FOR i IN [0..2000] DO ENDLOOP;
StartIO[3]; -- clear Ethernet
csb.cb ← NIL; csb.addr ← InvalidDA;
FOR i IN [1..10] DO
MiscDefs.Zero[cb, SIZE[CB]];
cb.command ← [110B, DiskCheck, DiskRead, DiskRead, 0, 0];
cb.headerAddress ← @cb.header;
cb.labelAddress ← label;
cb.dataAddress ← data;
cb.header.diskAddress ← LOOPHOLE[BITXOR[keys↑, -1]];
csb.cb ← cb; -- start the disk
WHILE cb.status.done#DSdone DO ENDLOOP; -- wait for completion
IF BITAND[cb.status, DSmaskStatus]=DSgoodStatus THEN EXIT;
REPEAT
FINISHED =>
BEGIN
ProcessDefs.EnableInterrupts[];
DCBchainHead↑ ← oldDCBChainHead;
WriteChar[CR];
WriteString["10 consecutive errors trying to read vda 0"L];
RETURN
END;
ENDLOOP;
bootLabel↑ ← label↑; -- 402B ← label
bootStatus↑ ← cb.status; -- 2B ← disk status
bltArgs.a ← data-1; bltArgs.b ← 400B; bltArgs.c ← -256;
[] ← BcplOps.BcplJSR[JSR, @bltAndJump, @bltArgs]; -- bye bye
END;
FileStat: PROC =
BEGIN OPEN InlineDefs, IODefs, PupDefs, PupTypes, StringDefs, TimeDefs;
ENABLE Question =>
BEGIN ENABLE NXDefs.UserAbort => GOTO Aborted;
NXDefs.LineReset["File name, from:"L];
ListPossibleMatches[s, IF alto THEN file ELSE file+uCode+germ];
WriteChar[CR]; RESUME
EXITS Aborted => RESUME;
END;
s: STRING ← [25];
bfNum: CARDINAL;
bfDate: PackedTime;
hostAddr: PupAddress;
uSwitchKbd: BOOLEAN =
IF alto THEN OsStaticDefs.OsStatics.AltoVersion.engineeringnumber<2
ELSE ProcessorType[]=CSL OR ProcessorType[]=Dorado;
keys: ARRAY [0..15] OF STRING ←
[IF uSwitchKbd THEN " <blank-top>"L ELSE " <BW>"L,
IF uSwitchKbd THEN " <blank-middle>"L ELSE " <FR4>"L,
" ]"L, " <quote>"L, " <comma>"L, " L"L,
" O"L, " X"L, " I"L, " 9"L, " A"L, " S"L,
" Q"L, " W"L, " 2"L, " 3"L];
entry: DirEntryPtr;
WriteString[" for file "L];
entry ← ReadCmd[">FileStat for file "L, file+uCode+germ];
WITH entry SELECT FROM
file => {bfNum ← bfn; hostAddr ← host; bfDate ← date};
uCode, germ => {bfNum ← bfn; hostAddr ← host; bfDate ← date};
ENDCASE;
WriteChar[CR];
WriteString["File number "L];
WriteOctal[bfNum];
WriteString[", from host "L];
s.length ← 0; AppendPupAddress[s, hostAddr];
s.length ← s.length-1; WriteString[s];
WriteString[", created "L]; s.length ← 0;
AppendDayTime[s, UnpackDT[bfDate]];
WriteLine[s];
WriteString["Keys: <BS>"L];
FOR i: INTEGER IN [0..16) DO
IF BITAND[BITSHIFT[bfNum, -i], 1]=1 THEN WriteString[keys[i]];
ENDLOOP;
END;
SetVersions: PROC =
BEGIN OPEN IODefs;
entry: DirEntryPtr;
WriteLine[" for germ and microcode"L];
BEGIN ENABLE Question =>
BEGIN ENABLE NXDefs.UserAbort => GOTO Aborted;
NXDefs.LineReset["Available germ files:"L];
ListPossibleMatches[s, germ];
WriteChar[CR]; RESUME
EXITS Aborted => RESUME;
END;
WriteString["Germ: "L];
WriteString[IF germEntry=NIL THEN pilotGerm[ProcessorType[]]
ELSE germEntry.name];
entry ← ReadCmd[
"Germ: "L, germ, TRUE,
IF germEntry=NIL THEN pilotGerm[ProcessorType[]] ELSE germEntry.name];
WriteChar[CR];
IF entry#NIL THEN germEntry ← entry;
END;
BEGIN ENABLE Question =>
BEGIN ENABLE NXDefs.UserAbort => GOTO Aborted;
NXDefs.LineReset["Available microcode files:"L];
ListPossibleMatches[s, uCode]; WriteChar[CR];
RESUME
EXITS Aborted => RESUME;
END;
WriteString["Microcode: "L];
WriteString[
IF uCodeEntry=NIL THEN
microcodeFiles[ProcessorType[]] ELSE uCodeEntry.name];
entry ← ReadCmd[
"Microcode: "L, uCode, TRUE,
IF uCodeEntry=NIL THEN
microcodeFiles[ProcessorType[]] ELSE uCodeEntry.name];
WriteChar[CR];
IF entry#NIL THEN uCodeEntry ← entry;
END;
END;
ReadSwitches: PROC =
{IODefs.WriteString[": "L]; IODefs.ReadLine[switchString]};
SetSwitches: PROC =
BEGIN OPEN IODefs;
FOR i: CARDINAL IN [0..switchString.length) DO
SELECT switchString[i] FROM
IN ['A..'Z] => Set[down, @switches, (switchString[i]-'A)+10];
IN ['a..'z] => Set[down, @switches, (switchString[i]-'a)+10];
IN ['0..'9] => Set[down, @switches, switchString[i]-'0];
ENDCASE;
ENDLOOP;
switches.g ← down;
END;
BitIndex: TYPE = CARDINAL [0..4096);
Bit: TYPE = CARDINAL [0..1];
BitDescriptor: TYPE = ControlDefs.FieldDescriptor;
Set: PROC [upDown: TemporaryBooting.UpDown, p: POINTER, index: BitIndex] =
INLINE {SetBitWithDesc[LOOPHOLE[upDown], p, BD[index]]};
BD: PROC [CARDINAL] RETURNS [BitDescriptor] =
MACHINE CODE BEGIN Mopcodes.zLI4; Mopcodes.zSHIFT END;
SetBitWithDesc: PROC [b: Bit, p: POINTER, bd: BitDescriptor] =
MACHINE CODE BEGIN Mopcodes.zWFS END;
LoadRam: PROC [p: LONG POINTER, andJump: BOOLEAN] =
MACHINE CODE BEGIN Mopcodes.zMISC, 3 END;
ClearDevices: PROC =
MACHINE CODE BEGIN Mopcodes.zMISC, 4 END;
MapFlags: TYPE = MACHINE DEPENDENT RECORD [
LogSE, W, D, Ref: BOOLEAN];
vacantFlags: MapFlags = [FALSE, TRUE, TRUE, FALSE];
cleanFlags: MapFlags = [FALSE, FALSE, FALSE, FALSE];
MapEntry: TYPE = MACHINE DEPENDENT RECORD [
flags: MapFlags,
realPage: [0..7777B]];
RealPage: TYPE = CARDINAL [0..10000B);
VirtualPage: TYPE = CARDINAL [0..40000B);
vacant: MapEntry = [vacantFlags,0];
clean: MapEntry = [cleanFlags,0];
ASSOC: PROC [CARDINAL, MapEntry] =
MACHINE CODE {Mopcodes.zMISC, 0};
SETF: PROC [CARDINAL, MapEntry] RETURNS [MapEntry] =
MACHINE CODE {Mopcodes.zMISC, 1};
LPFromPage: PROC [p: CARDINAL] RETURNS [LONG POINTER] =
INLINE {RETURN[LOOPHOLE[LONG[p]*pageSize]]};
LongRead: PROC [LONG POINTER] RETURNS [CARDINAL] =
MACHINE CODE {Mopcodes.zRBL, 0};
CountRealPages: PROC RETURNS [pageCount: CARDINAL] =
BEGIN
FOR pageCount ← 0, pageCount+1 DO
m: MapEntry ← SETF[pageCount, clean];
[] ← SETF[pageCount, m];
IF m = vacant THEN EXIT;
ENDLOOP;
RETURN
END;
MovePages: PROC [from, to, count: CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0..count) DO
m: MapEntry ← SETF[from+i, clean];
ASSOC[from+i, vacant];
ASSOC[to+i, m];
ENDLOOP;
RETURN
END;
NullDA: DA = LOOPHOLE[0];
BootInfo: TYPE = ARRAY [0..8) OF UNSPECIFIED;
nullBootInfo: BootInfo ← ALL[0];
pageSize: CARDINAL = 256;
firstHyperPage: CARDINAL = 256;
germMDSIndex: CARDINAL = 76B;
germMDSPage: CARDINAL = germMDSIndex*pageSize;
germMDS: LONG POINTER = LOOPHOLE[LONG[germMDSIndex]*200000B];
firstGermPage: CARDINAL = germMDSPage + 2;
germStart: LONG POINTER = LPFromPage[firstGermPage];
germData: LONG POINTER = germMDS + LOOPHOLE[Boot.pRequest];
germSwitches: LONG POINTER =
germMDS + LOOPHOLE[@SDDefs.SD[BootSwap.sPilotSwitches]];
pilotGerm: ARRAY Hardware OF STRING ←
["CedarD0.eg"L, "CedarD0.eg"L, "CedarD0.eg"L, "CedarDorado.eg"L];
microcodeFiles: ARRAY Hardware OF STRING ←
["CedarD0.eb"L, "CedarD0.eb"L, "CedarD0.eb"L, "CedarDorado.eb"L];
othelloFiles: ARRAY Hardware OF STRING ←
["CedarOthelloD0.pb"L, "CedarOthelloD0.pb"L, "CedarOthelloD0.pb"L, "CedarOthelloDorado.pb"L];
cedarFiles: ARRAY Hardware OF STRING ←
["BasicCedarD0.pb"L, "BasicCedarD0.pb"L, "BasicCedarD0.pb"L, "BasicCedarDorado.pb"L];
cedarGerms: ARRAY Hardware OF STRING ←
["CedarD0.eg"L, "CedarD0.eg"L, "CedarD0.eg"L, "CedarDorado.eg"L];
Hardware: TYPE = {SDD, CSL, Tor, Dorado};
uCodeEntry: DirEntryPtr ← NIL;
germEntry: DirEntryPtr ← NIL;
ProcessorType: PROC RETURNS [Hardware] =
BEGIN
Register: TYPE = MACHINE DEPENDENT RECORD [
left: [0..377B], bitClock: [0..37B], fill: [0..7B]];
Input: PROC [CARDINAL] RETURNS [Register] =
MACHINE CODE BEGIN Mopcodes.zMISC, 5; END;
reg: Register;
IF OsStaticDefs.OsStatics.AltoVersion.engineeringnumber=5 THEN
RETURN[Dorado];
FOR i: CARDINAL IN [4..16] DO
reg ← Input[i*16];
IF reg.left=2 THEN EXIT
ELSE IF reg.left=12B THEN RETURN[Tor];
REPEAT FINISHED => ERROR;
ENDLOOP;
RETURN[IF reg.bitClock=5 THEN CSL ELSE SDD]; -- 3 for SDD Dolphin
END;
GetFileName: PROC [entry: DirEntryPtr, type: DirEntryType, str: STRING]
RETURNS [STRING] =
BEGIN OPEN StringDefs;
ssP: SubStringDescriptor ← ["P"L, 0, 1]; -- what a crock...
ssA: SubStringDescriptor ← ["AlphaPilot"L, 0, 10];
ss: SubStringDescriptor;
root: STRING ← SELECT type FROM
germ => pilotGerm[ProcessorType[]],
uCode => microcodeFiles[ProcessorType[]],
ENDCASE => ERROR;
str.length ← 0;
IF entry=NIL THEN {AppendString[str, root]; RETURN[str]};
ss ← [entry.name, 0, ssP.length];
IF EquivalentSubStrings[@ss, @ssP] THEN
{AppendSubString[str, @ssP]; AppendString[str, root]; RETURN[str]};
ss.length ← ssA.length; IF EquivalentSubStrings[@ss, @ssA] THEN
{AppendSubString[str, @ssA]; AppendString[str, root]; RETURN[str]};
AppendString[str, root];
RETURN[str];
END;
EtherBoot: PROC [entry: FileDirEntryPtr] =
BEGIN
req.action ← Boot.inLoad;
req.location ←
[deviceType: DeviceTypes.ethernet, deviceOrdinal: 0,
vp: ethernet[entry.bfn, entry.host.net, entry.host.host]];
SoftBoot[entry];
END;
PhysVolBoot: PROC =
BEGIN -- boot Shugart disk
req.action ← Boot.bootPhysicalVolume;
req.location ←
[deviceType: DeviceTypes.sa4000, deviceOrdinal: 0,
vp: disk[Boot.nullDiskFileID]];
SoftBoot[];
END;
FlipCursor: PROC =
BEGIN
FOR i: CARDINAL IN[0..16) DO
cursor[i] ← InlineDefs.BITXOR[cursor[i], -1] ENDLOOP;
END;
EtherGetModule: ENTRY PROC
[entry: DirEntryPtr, pProc: PROCEDURE RETURNS [LONG POINTER]]
RETURNS [pages: CARDINAL] =
BEGIN OPEN EFTPDefs, IODefs, ProcessDefs, PupDefs, PupTypes;
n, zero, lastn: CARDINAL ← 0;
i, tP, firstP, lastP: LONG POINTER;
bufP: POINTER ← NIL; -- must be initialized since NIL means not allocated
me: PupAddress;
oneSecond: CONDITION;
host: PupAddress ← WITH entry SELECT FROM
file => host, uCode, germ => host,
ENDCASE => ERROR;
bfn: CARDINAL ← WITH entry SELECT FROM
file => bfn, uCode, germ => bfn,
ENDCASE => ERROR;
buffer: PupBuffer;
squares: ARRAY [0..16) OF WORD ←
[377B, 377B, 377B, 377B,
377B, 377B, 377B, 377B,
177400B, 177400B, 177400B, 177400B,
177400B, 177400B, 177400B, 177400B];
BEGIN ENABLE EFTPTimeOut =>
{WriteString["receiver timed out"L]; GOTO ErrorExit};
IF entry=NIL THEN RETURN[0];
pages ← 0;
SetTimeout[@oneSecond, MsecToTicks[1000]];
cursor↑ ← squares;
me ← UniqueLocalPupAddress[@host];
bufP ← SystemDefs.AllocateResidentPages[1];
EFTPSetRecvTimeout[100]; -- short timeout to get things rolling
-- first set up receiver
[] ← EFTPOpenForReceiving[me
! EFTPTimeOut => -- at least once, since we haven't asked for file
BEGIN
EFTPSetRecvTimeout[5000];
IF (n←n+1)>10 THEN
{WriteString["no connection established"L]; GOTO ErrorExit};
buffer ← GetFreePupBuffer[];
buffer.source ← me;
buffer.dest ← host;
buffer.pupType ← bootFileSend;
buffer.pupID.b ← bfn;
SetPupContentsWords[buffer, 0];
[] ← PupRouterSendThis[buffer];
RESUME;
END];
[] ← EFTPGetBlock[bufP, 512];
-- first block is alto bootloader, discard it
FlipCursor[];
IF entry.type=uCode THEN -- keep LoadRamAndJump happy
BEGIN
firstP ← tP ← pProc[] + pageSize - 1; pages ← pages+1;
InlineDefs.LongCOPY[from: @zero, to: tP, nwords: 1];
END;
lastn ← 512; -- so check below succeeds first time
DO -- main receive loop
n ← EFTPGetBlock[bufP, 512 ! EFTPEndReceiving => EXIT];
IF lastn<512 THEN
{WriteString["short EFTP block in middle of file"L]; GOTO ErrorExit};
lastn ← n;
tP ← pProc[]; pages ← pages+1;
InlineDefs.LongCOPY[from: bufP, to: tP, nwords: pageSize];
FlipCursor[];
ENDLOOP;
EFTPFinishReceiving[];
SystemDefs.FreePages[bufP]; bufP ← NIL;
IF entry.type=uCode THEN
{lastP ← tP+n/2; n ← 0;
FOR i ← firstP, i+1 UNTIL i=lastP DO n ← n+LongRead[i] ENDLOOP;
IF n#0 THEN
{WriteString["microcode checksum error"L]; GOTO ErrorExit}};
WAIT oneSecond;
EXITS ErrorExit =>
{IF bufP#NIL THEN SystemDefs.FreePages[bufP];
EFTPAbortReceiving[""L]; RETURN[0]};
END;
END;
SoftBoot: PROC [dirEntry: DirEntryPtr ← NIL] =
BEGIN OPEN IODefs;
germPages, rpCount, uCodePages: CARDINAL;
nextGermTo, nextGermFrom: CARDINAL;
nextHyperPage: CARDINAL ← firstHyperPage;
entry: DirEntryPtr;
fName: STRING ← [40];
GetGermPage: PROCEDURE RETURNS [p: LONG POINTER] =
BEGIN
ProcessDefs.DisableInterrupts[];
MovePages[from: nextGermFrom, to: nextGermTo, count: 1];
ProcessDefs.EnableInterrupts[];
p ← LPFromPage[nextGermTo];
nextGermTo ← nextGermTo+1; nextGermFrom ← nextGermFrom-1;
END;
GetHyperPage: PROCEDURE RETURNS [p: LONG POINTER] =
BEGIN
p ← LPFromPage[nextHyperPage];
nextHyperPage ← nextHyperPage+1;
END;
BEGIN
killProber ← TRUE;
SetSwitches[];
WriteString["...loading germ..."L];
entry ← IF germEntry#NIL THEN germEntry
ELSE Lookup[GetFileName[dirEntry, germ, fName], germ, FALSE];
IF entry=NIL THEN
{WriteChar[CR]; WriteString["Can't find file "L]; WriteLine[fName]; RETURN};
rpCount ← CountRealPages[];
nextGermFrom ← rpCount-1; -- start at end of real memory
nextGermTo ← firstGermPage;
germPages ← EtherGetModule[entry, GetGermPage];
IF germPages=0 THEN
{WriteChar[CR];
WriteLine["EFTP problem - couldn't get germ"L]; GOTO Abort};
WriteString["loading microcode..."L];
entry ← IF uCodeEntry#NIL THEN uCodeEntry
ELSE Lookup[GetFileName[dirEntry, uCode, fName], uCode, FALSE];
IF entry=NIL THEN
{WriteChar[CR];
WriteString["Can't find file "L]; WriteLine[fName]; GOTO Abort};
uCodePages ← EtherGetModule[entry, GetHyperPage];
IF uCodePages=0 THEN
{WriteChar[CR];
WriteLine["EFTP problem - couldn't get microcode"L]; GOTO Abort};
ProcessDefs.DisableInterrupts[];
AltoDisplay.DCBchainHead↑ ← AltoDisplay.DCBnil;
THROUGH [0..2000] DO ENDLOOP; -- let things quiet down
InlineDefs.LongCOPY[from: @req, to: germData, nwords: SIZE[Boot.Request]];
InlineDefs.LongCOPY[from: @switches, to: germSwitches,
nwords: SIZE[TemporaryBooting.Switches]];
cursor↑ ← doneCursor; -- since display is turned off
LoadRam[LPFromPage[firstHyperPage]+pageSize-1, TRUE];
EXITS Abort => -- put real pages back
MovePages[from: firstGermPage, to: rpCount-germPages,
count: nextGermTo-firstGermPage];
END;
END;
Othello: PROC = {BootGeneric[othelloFiles]};
Cedar: PROC =
BEGIN
IF germEntry=NIL THEN germEntry ← Lookup[cedarGerms[ProcessorType[]], germ, FALSE];
BootGeneric[cedarFiles];
END;
BootGeneric: PROC [fileNameTable: ARRAY Hardware OF STRING] =
BEGIN OPEN IODefs, NXDefs;
cmdPtr: DirEntryPtr ← Lookup[fileNameTable[ProcessorType[]], file, FALSE];
SELECT cmdPtr FROM
NIL =>
{FlashDisplay[]; WriteString[" ?"L]; Probe[]; RETURN};
illPtr => {FlashDisplay[]; RETURN};
ENDCASE;
WITH entry: cmdPtr SELECT FROM
cmd => entry.proc[];
file =>
SELECT entry.sysType FROM
alto => MMOps.BootViaNet[entry.bfn, entry.host.host];
pilot => EtherBoot[@entry];
ENDCASE;
ENDCASE;
END;
-- Initialization
BEGIN
vers: RECORD [WORD, WORD] ← [61014B, 1400B];
version: OsStaticDefs.AltoVersionNumber;
debug ← KeyDefs.Keys.Spare1=down OR debug;
IF ~debug THEN MMOps.MakeBoot[];
SDDefs.SD[SDDefs.sUncaughtSignal] ← Catcher;
version ← BcplOps.BcplJSR[JSR, @vers, 0];
OsStaticDefs.OsStatics.AltoVersion ← version;
alto ← version.engineeringnumber<4;
START NXDefs.NXDisplay;
InstallCommands[];
PupDefs.PupPackageMake[];
ProcessDefs.Detach[FORK NXDefs.Host];
ProcessDefs.Detach[FORK NXDefs.Timer];
ProcessDefs.Detach[FORK NXDefs.SetTime];
ProcessDefs.Detach[FORK ProbeProcess];
ProcessDefs.Detach[FORK NXDefs.WatchDog];
Run[];
END;
END...