Germ>BootSwapGerm.mesa
Last Edited by: Taft, February 25, 1983 3:00 pm
Last Edited by: Andrew Birrell, December 13, 1983 3:18 pm
Note: I think the code in initialize assumes the machine starts the germ with memory mapped at address 0
DIRECTORY
Basics USING [LongDiv],
BootChannel USING [Create, Operation, Handle, Transfer, transferCleanup, transferWait],
BootFile USING [Continuation, currentVersion, Entry, Header, InLoadMode, Location, maxEntriesPerHeader, maxEntriesPerTrailer, MDSIndex, Trailer],
GermPrivate USING [Assoc, flagsClean, flagsVacant, GetF, RealPageNumber, SetF, TeleDebug, Value, valueVacant],
GermSwap USING [Action, countSkip, Initialize, InitializeMDS, pRequest, pCountGerm, pInitialLink, pMon, ReadMDS, ResponseKind],
MesaRuntimeInit USING [Start, TrapsImpl],
MPCodes USING [cantWorldSwap, germStarting, germOutLoad, germInLoad, germMapIO, germBadBootFile, germBadPhysicalVolume, germControlFault, germDeviceError, germERROR, germFinished, germStartFault, germTeledebugServer, Code],
PrincOps USING [PageCount, PageNumber, wordsPerPage, ControlLink, FrameHandle, returnOffset, SD, sError, sErrorList, sReturnError, sReturnErrorList, sSignal, sSignalList, StateVector, sUnnamedError, UnboundLink, zRET, zSLB],
PrincOpsUtils USING [Free, GetReturnFrame, IsBound, PageNumberForAddress, WriteWDC],
ProcessorFace USING [GetClockPulses, GetNextAvailableVM, Go, microsecondsPerHundredPulses, SetMP],
RuntimeError USING [ControlFault, StartFault],
VolumeFormat USING [PhysicalRoot, PRCurrentVersion, PRSeal];
BootSwapGerm: PROGRAM
IMPORTS Basics, BC: BootChannel, GermPrivate, GermSwap, MesaRuntimeInit, PrincOpsUtils, ProcessorFace, RuntimeError
EXPORTS BootChannel, GermPrivate--countVM, Error--
SHARES GermSwap =
BEGIN OPEN BootChannel, BootFile, GermSwap, PrincOps;
Do NOT save any status between DoOutLoad and DoInLoad relating to the request. The next time everything in the outside world may have changed.
The booting action defined by the Principles of Operation should include:
1. Put all usable real memory somewhere in virtual memory.
2. Read countGerm pages of a "boot swap germ" into virtual memory beginning at page pageGerm+countSkip (steal real memory from high end to do this).
3. Set GermSwap.pRequest^ to [inLoad, locationOfBootFile].
4. Set WDC>0, NWW=0, MDS=pageGerm, STKP=0.
5. Xfer[dest: GermSwap.pInitialLink].
At present, buffer space allocated for the BootChannel's is reclaimed when the request is complete. Currently only the BootChannelEther allocates buffer space. When non-initial-booting operations via the ether are implemented, we will have to hang onto this buffer space forever.
countVM: PUBLIC PageCount; -- Export to GermPrivate
firstPageNumber: PageNumber = 0; -- NB: not FIRST[PageNumber], because it's an INT!
pageGerm: PageNumber = GetPageMDS[] + countSkip; -- should be a constant engraved in stone
pageBuffer: PageNumber; -- page used to read/write boot file map.
pageOtherBuffer: PageNumber; -- extra page used for double-buffering Cedar MapIO
pageGermKeep: PageNumber; -- highest (mapped) page of germ VM that we retain for all time.
--TEMP FIX FOR GERMSWAP BUG-- pCountGerm: POINTER TO CARDINAL =
LOOPHOLE[GermSwap.pCountGerm];
pageAfterGerm: PageNumber ← pageGerm + pCountGerm^;
current end of (mapped) germ storage (includes allocated buffer space, doesn't include pageTemp). Note that DoInLoad uses a scratch VM page at pageAfterGerm.
dFirst64KStorage: LONG DESCRIPTOR FOR ARRAY OF WORD = DESCRIPTOR[
LOOPHOLE[LONG[177200B], LONG POINTER], 200B];
A piece of the first 64K that we know nobody uses, for allocating IOCB's. When the germ moves to the first 64K, this should be put in its global frame.
cedarVersion: CARDINAL = 150; -- version number of outload files written with cedarOutLoad
Run: PROC = -- after the very first execution, the germ entry point is here
BEGIN
handle: BootChannel.Handle;
GermSwap.InitializeMDS[]; -- set pMon
ShowMP[MPCodes.germStarting];
DO
inLoad exits through JumpCall2, outLoad does explicit EXIT, bootPhysicalVolume turns itself into an inLoad
SELECT GermSwap.pRequest.action FROM
inLoad =>
BEGIN
continuation: Continuation;
responseKind: GermSwap.ResponseKind;
mdsiOther: BootFile.MDSIndex;
destOther: UNSPECIFIED;
handle ← BC.Create[@GermSwap.pRequest.location, read, dFirst64KStorage];
[continuation, pMon.pStartListHeader] ← DoInLoad[handle];
WITH continuation SELECT FROM
initial --[mdsi, destination]-- =>
BEGIN
responseKind ← initiated;
mdsiOther ← mdsi;
destOther ← destination
END;
resumptive --[mdsi, resumee]-- =>
BEGIN
responseKind ← resumed;
mdsiOther ← mdsi;
destOther ← resumee
END;
ENDCASE => Error[MPCodes.germBadBootFile];
GermSwap.Initialize[mdsiOther]; -- set (pMon and) WriteMDS machinery
pMon.responseKind ← responseKind;
ShowMP[MPCodes.germFinished];
JumpCall2[arg1: mdsiOther, arg2: destOther, Proc: pMon.CrossMDSCall];
frees our frame
END;
outLoad, pilotOutLoad =>
BEGIN
handle ← BC.Create[@GermSwap.pRequest.location, write, dFirst64KStorage];
DoOutLoad[handle, pMon.inLoadMode, pMon.continuation,
GermSwap.pRequest.action = outLoad];
pMon.responseKind ← outLoaded;
EXIT;
END;
bootPhysicalVolume =>
BEGIN
pvDesc: POINTER TO VolumeFormat.PhysicalRoot =
PointerFromPage[pageBuffer];
GermSwap.pRequest.location.diskFileID.firstLink ← LOOPHOLE[LONG[0]]; --kludge!
handle ← BC.Create[@GermSwap.pRequest.location, rawRead, dFirst64KStorage];
Transfer[handle, pageBuffer, 1];
Transfer[handle, NULL, transferWait];
IF pvDesc.seal ~= VolumeFormat.PRSeal OR pvDesc.version ~=
VolumeFormat.PRCurrentVersion THEN Error[MPCodes.germBadPhysicalVolume];
Transfer[handle, 0, 0]; -- shut down channel
GermSwap.pRequest.location.diskFileID ← pvDesc.bootingInfo[bootFile];
GermSwap.pRequest.action ← inLoad;
now get the boot file and go
END;
teledebug =>
IF PrincOpsUtils.IsBound[GermPrivate.TeleDebug]
THEN {
ShowMP[MPCodes.germTeledebugServer];
GermPrivate.TeleDebug[pageBuffer, dFirst64KStorage];
EXIT}
ELSE Error[MPCodes.cantWorldSwap];
ENDCASE => ERROR;
ENDLOOP;
ShowMP[MPCodes.germFinished];
END;
DoInLoad: PROC [channel: BootChannel.Handle]
RETURNS [continuation: Continuation, pStartListHeader: POINTER] =
BEGIN
cedar: BOOLFALSE; -- whether outload file was written with cedarOutLoad
inLoadMode: InLoadMode;
realPageTemp: GermPrivate.RealPageNumber; -- SkipPageHack
count, countData, countGroup, countRemaining: PageCount;
page, pageLastMapped, pageNext, pageRun: PageNumber;
pBuffer: POINTER = PointerFromPage[pageBuffer];
nEntry: CARDINAL;
pEntry, pEntryGroup: POINTER TO Entry;
value: GermPrivate.Value;
SkipPage: PROC = -- SkipPageHack
BEGIN
pageTemp: PageNumber = pageAfterGerm;
GermPrivate.Assoc[pageTemp,
GermPrivate.Value[FALSE, GermPrivate.flagsClean, realPageTemp]];
Transfer[channel, pageTemp, 1];
Transfer[channel, NULL, transferWait];
GermPrivate.Assoc[pageTemp, GermPrivate.valueVacant];
END; --
ShowMP[MPCodes.germInLoad];
Read first page, containing header
Transfer[channel, pageBuffer, 1];
Transfer[channel, NULL, transferWait];
BEGIN OPEN header: LOOPHOLE[pBuffer, POINTER TO Header];
IF header.version ~= BootFile.currentVersion THEN {
IF header.version = cedarVersion THEN cedar ← TRUE
ELSE Error[MPCodes.germBadBootFile]
};
pStartListHeader ← header.pStartListHeader;
SELECT (inLoadMode ← header.inLoadMode) FROM
load =>
BEGIN
CompactVM[];
pageLastMapped ← firstPageNumber + GetCountRunMapped[firstPageNumber] - 1;
realPageTemp ← GermPrivate.GetF[pageLastMapped].realPage; -- SkipPageHack
END;
restore => NULL;
ENDCASE;
continuation ← header.continuation;
countData ← header.countData;
pEntryGroup ← @header.entries[0];
nEntry ← maxEntriesPerHeader;
END;
Restore real memory and hardware map from boot file, beginning with data of first group
page ← 0; -- next page to restore
countRemaining ← countData;
DO
Calculate group size
countGroup ← MIN[nEntry, countRemaining];
Set up map entries to be vacant or nonvacant (and writable), as appropriate
pEntry ← pEntryGroup;
THROUGH [0..countGroup) DO
WHILE page < pEntry.page DO
nongerm pages not in boot file are vacant
IF ~InGerm[page] THEN
IF ~(page IN [pageGerm..pageAfterGerm) OR page = 376B OR page = 377B)
THEN
BEGIN
value ← GermPrivate.SetF[page, GermPrivate.valueVacant];
IF inLoadMode = load AND ~IsVacant[value] THEN
GermPrivate.Assoc[pageLastMapped ← pageLastMapped + 1, value]
END;
page ← page + 1;
ENDLOOP;
IF inLoadMode = restore THEN
GermPrivate.Assoc[page,
GermPrivate.Value[FALSE, GermPrivate.flagsClean, pEntry.value.realPage]];
pEntry ← pEntry + SIZE[Entry];
page ← page + 1;
ENDLOOP;
Transfer data to nonvacant pages
pEntry ← pEntryGroup;
count ← countGroup;
WHILE count ~= 0 DO
find and transfer one run
pageNext ← pageRun ← pEntry.page;
IF pageRun = 376B OR pageRun = 377B THEN -- SkipPageHack
{SkipPage[]; pEntry ← pEntry + SIZE[Entry]; count ← count - 1}
ELSE
BEGIN
DO -- until end of run found
count ← count - 1;
pageNext ← pageNext + 1;
pEntry ← pEntry + SIZE[Entry];
IF count = 0 OR pEntry.page ~= pageNext OR pageNext = 376B OR pageNext
= 377B --SkipPageHack-- THEN EXIT;
ENDLOOP;
Transfer[channel, pageRun, pageNext - pageRun];
END;
ENDLOOP; -- Restore map entries
Transfer[channel, NULL, transferWait];
pEntry ← pEntryGroup;
THROUGH [0..countGroup) DO
[] ← GermPrivate.SetF[pEntry.page, pEntry.value];
pEntry ← pEntry + SIZE[Entry]
ENDLOOP;
re-set MP in case we just overwrote the cursor (which displays the MP on a Dorado!)
ProcessorFace.SetMP[MPCodes.germInLoad];
Prepare for next group
countRemaining ← countRemaining - countGroup;
IF countRemaining = 0 THEN EXIT;
BEGIN OPEN trailer: LOOPHOLE[pBuffer, POINTER TO Trailer];
Transfer[channel, pageBuffer, 1];
Transfer[channel, NULL, transferWait];
IF trailer.version ~= BootFile.currentVersion THEN Error[MPCodes.germBadBootFile];
pEntryGroup ← @trailer.entries[0];
nEntry ← maxEntriesPerTrailer;
END;
ENDLOOP;
All groups are now loaded
SELECT inLoadMode FROM
load =>
BEGIN
Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup
Recover germ buffer storage: We can't do this when non-initial-booting
operations via the ether are implemented.
FOR page DECREASING IN [pageGermKeep..pageAfterGerm) DO
GermPrivate.Assoc[pageLastMapped ← pageLastMapped + 1,
GermPrivate.SetF[page, GermPrivate.valueVacant]];
ENDLOOP;
pageAfterGerm ← pageGermKeep;
END;
restore =>
IF cedar THEN-- Cedar Nucleus: restore map entries from bootfile
BEGIN
mapPage: PrincOps.PageNumber ← 0;
inCoreBuffer: PrincOps.PageNumber ← pageBuffer;
inTransitBuffer: PrincOps.PageNumber ← pageOtherBuffer;
ShowMP[MPCodes.germMapIO];
Transfer[channel, inCoreBuffer, 1];
UNTIL mapPage = countVM
DO
mapArray: POINTER TO ARRAY [0..PrincOps.wordsPerPage) OF GermPrivate.Value
= PointerFromPage[inCoreBuffer];
IF mapPage + PrincOps.wordsPerPage < countVM
THEN Transfer[channel, inTransitBuffer, 1]-- implicitly waits for "inCoreBuffer"
ELSE Transfer[channel, NULL, transferWait];-- wait for "inCoreBuffer" to really arrive
FOR i: CARDINAL IN CARDINAL[0..MIN[countVM-mapPage,PrincOps.wordsPerPage])
UNTIL mapPage = countVM
DO
IF mapPage NOT IN [pageGerm..pageAfterGerm) THEN
BEGIN
current: GermPrivate.Value = GermPrivate.GetF[mapPage];
IF NOT IsVacant[current] AND current.flags.dirty
THEN mapArray[i].flags.dirty ← TRUE;
GermPrivate.Assoc[mapPage, mapArray[i]];
END;
mapPage ← mapPage+1;
ENDLOOP;
{ temp: PrincOps.PageNumber = inCoreBuffer;
inCoreBuffer ← inTransitBuffer; inTransitBuffer ← temp };
ENDLOOP;
Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup
END
ELSE BEGIN -- Pilot--
Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup
WHILE page < countVM DO
IF ~InGerm[page] THEN
IF ~(page IN [pageGerm..pageAfterGerm) OR page = 376B OR page = 377B)
THEN GermPrivate.Assoc[page, GermPrivate.valueVacant];
page ← page + 1;
ENDLOOP;
END;
ENDCASE;
END;
DoOutLoad: PROC [channel: BootChannel.Handle, inLoadMode: InLoadMode, continuation: Continuation, cedar: BOOL] =
Assumptions: interrupts disabled, all devices quiesced
BEGIN
count, countData, countGroup, countRemaining: PageCount;
page, pageNext, pageRun: PageNumber;
pBuffer: POINTER = PointerFromPage[pageBuffer];
nEntry: CARDINAL;
pEntry, pEntryGroup: POINTER TO Entry; --
Construct header in first map page
Number of pages to save is total nonvacant minus those in germ
ShowMP[MPCodes.germOutLoad];
page ← countData ← 0;
DO
IF ~IsVacant[GermPrivate.GetF[page]] THEN
countData ← countData + 1;
IF (page ← page + 1) = countVM THEN EXIT;
ENDLOOP;
countData ← countData - (pageAfterGerm - pageGerm) - 2 --i.e. 376B and 377B--;
BEGIN OPEN header: LOOPHOLE[pBuffer, POINTER TO Header];
header ← [creationDate:, -- fill this when we have a Pilot T.O.D clock?
pStartListHeader: NIL, inLoadMode: inLoadMode, continuation: continuation,
countData: countData, entries:];
IF cedar THEN header.version ← cedarVersion;
pEntryGroup ← @header.entries[0];
nEntry ← maxEntriesPerHeader;
END;
Write sequence of (map, data) groups
page ← 0;
countRemaining ← countData;
DO
Calculate group size
countGroup ← MIN[nEntry, countRemaining]; -- Write map page
pEntry ← pEntryGroup;
THROUGH [0..countGroup) DO
page ← AdvancePage[page];
pEntry^ ← [page, GermPrivate.GetF[page]];
pEntry ← pEntry + SIZE[Entry];
page ← page + 1
ENDLOOP;
Transfer[channel, pageBuffer, 1]; -- Write data pages
pEntry ← pEntryGroup;
count ← countGroup;
WHILE count ~= 0 DO
find and transfer one run
pageNext ← pageRun ← pEntry.page;
DO
until end of run found
count ← count - 1;
pageNext ← pageNext + 1;
pEntry ← pEntry + SIZE[Entry];
IF count = 0 OR pEntry.page ~= pageNext THEN EXIT;
ENDLOOP;
Transfer[channel, pageRun, pageNext - pageRun];
ENDLOOP; -- Prepare for next group
Transfer[channel, NULL, transferWait];
countRemaining ← countRemaining - countGroup;
IF countRemaining = 0 THEN EXIT;
BEGIN OPEN trailer: LOOPHOLE[pBuffer, POINTER TO Trailer];
pEntryGroup ← @trailer.entries[0];
nEntry ← maxEntriesPerTrailer;
trailer ← [entries:]; -- set version and any other defaultable fields
END;
ENDLOOP;
IF cedar THEN
BEGIN -- Cedar Nucleus: write data words from entire page map (double-buffered)
mapPage: PrincOps.PageNumber ← 0;
inCoreBuffer: PrincOps.PageNumber ← pageBuffer;
inTransitBuffer: PrincOps.PageNumber ← pageOtherBuffer;
ShowMP[MPCodes.germMapIO];
UNTIL mapPage = countVM
DO
mapArray: POINTER TO ARRAY [0..PrincOps.wordsPerPage) OF GermPrivate.Value
= PointerFromPage[inCoreBuffer];
FOR i: CARDINAL IN CARDINAL[0..MIN[countVM-mapPage,PrincOps.wordsPerPage])
UNTIL mapPage = countVM
DO
mapArray[i] ← GermPrivate.GetF[mapPage];
mapPage ← mapPage+1;
ENDLOOP;
Transfer[channel, inCoreBuffer, 1];-- implicitly waits for inTransitBuffer to complete
{ temp: PrincOps.PageNumber = inCoreBuffer;
inCoreBuffer ← inTransitBuffer; inTransitBuffer ← temp };
ENDLOOP;
Transfer[channel, NULL, transferWait];
END;
Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup
END;
AdvancePage: PROC [page: PageNumber] RETURNS [PageNumber] =
Return first page at or after given page which is not vacant or part of the germ
BEGIN
WHILE IsVacant[GermPrivate.GetF[page]] OR
--InGerm[page]-- (page IN [pageGerm..pageAfterGerm) OR page IN [376B..377B])
DO page ← page + 1 ENDLOOP;
RETURN[page]
END;
CompactVM: PROC =
Find all real pages currently mapped to virtual pages and map contiguous virtual addresses starting at 0 to them. Treat Page 1 like an IO page (i.e. never relocate) until the DCB is moved out of it.
BEGIN
pageDest: PageNumber ← 0;
FOR pageSource: PageNumber IN [0..countVM) DO
value: GermPrivate.Value;
IF pageSource IN [pageGerm..pageAfterGerm) OR pageSource IN [376B..377B] THEN LOOP;
IF pageSource = 1 THEN LOOP;
IF IsVacant[value ← GermPrivate.SetF[pageSource, GermPrivate.valueVacant]] THEN LOOP;
value.flags.readonly ← FALSE;
GermPrivate.Assoc[pageDest, value]; -- put back in the map
WHILE ((pageDest ← pageDest + 1) IN [pageGerm..pageAfterGerm)
OR pageDest = 1 OR pageDest IN [376B..377B]) DO ENDLOOP;
ENDLOOP;
END;
Backstop Create routine to plug end of chain of BootChannel interfaces.
Create: PUBLIC PROC [
POINTER TO BootFile.Location, BootChannel.Operation,
LONG DESCRIPTOR FOR ARRAY OF WORD]
RETURNS [handle: BootChannel.Handle] =
{Error[MPCodes.germDeviceError]; -- nobody implements this type of device!--};
Find length of run of virtual pages all mapped to real pages
GetCountRunMapped: PROC [pageStarting: PageNumber]
RETURNS [countReal: PageCount] =
BEGIN
FOR countReal ← 0, countReal + 1 DO
IF IsVacant[GermPrivate.GetF[pageStarting + countReal]] THEN EXIT
ENDLOOP
END;
GetPageMDS: PROC RETURNS [PageNumber] =
{RETURN[GermSwap.ReadMDS[]*256]; };
IsVacant: PROC [value: GermPrivate.Value] RETURNS [BOOLEAN] = INLINE {
RETURN[value.flags=GermPrivate.flagsVacant]};
Virtual memory map has pages [ 0 .. 0+countVM ), except pages p for which InGerm[p]=TRUE. "InGerm" has been MANUALLY expanded inline, so changes to it must be propagated. In particular, see code which sets countData in DoOutLoad
InGerm: PROC [page: PageNumber] RETURNS [BOOLEAN] = INLINE
BEGIN
RETURN[page IN [pageGerm..pageAfterGerm) OR page IN [376B..377B]]
END;
JumpCall0: PROC [Proc: PROC] = MACHINE CODE
BEGIN PrincOps.zSLB, PrincOps.returnOffset; PrincOps.zRET END;
JumpCall2: PROC [
arg1, arg2: UNSPECIFIED, Proc: PROC [UNSPECIFIED, UNSPECIFIED]] =
LOOPHOLE[JumpCall0];
PointerFromPage: PROC [page: PageNumber] RETURNS [POINTER] = {
mdsP: CARDINAL = page - GetPageMDS[];
RETURN[LOOPHOLE[mdsP*wordsPerPage]]
};
Transfer: PUBLIC PROC [handle: BC.Handle, page: PageNumber, count: PageCount] =
Only public to make compiler happy
BEGIN
BC.Transfer[handle, page, count];
END;
Error: PUBLIC SIGNAL [code: MPCodes.Code] = CODE; -- export to GermPrivate
We can't set up handlers for Frame, Page, and Write Faults because they require that the ProcessDataArea be already initialized, and it's not until Pilot comes to life. If the germ is not working, try putting a Midas break at the fault handling code.
UnnamedError: PROC =
{ SignalHandler[Error, MPCodes.germERROR] };
SignalHandler: PROC [signal: SIGNAL[code: MPCodes.Code], code: MPCodes.Code] =
BEGIN
ProcessorFace.SetMP[SELECT TRUE FROM
signal = Error => code,
signal = LOOPHOLE[RuntimeError.ControlFault] => MPCodes.germControlFault,
signal = LOOPHOLE[RuntimeError.StartFault] => MPCodes.germStartFault,
ENDCASE => MPCodes.germERROR];
DO ENDLOOP;
END;
debug: BOOL = FALSE;
ShowMP: PROC[code: MPCodes.Code] = -- display code in panel (for a second if "debug")
BEGIN
ProcessorFace.SetMP[code];
IF debug
THEN BEGIN
start: LONG CARDINAL = ProcessorFace.GetClockPulses[];
pulsesPerSecond: LONG CARDINAL =
Basics.LongDiv[1D6*100, ProcessorFace.microsecondsPerHundredPulses];
ProcessorFace.SetMP[code];
WHILE ProcessorFace.GetClockPulses[] - start < pulsesPerSecond DO ENDLOOP;
END;
END;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ResidentMemory implementation, for allocating storage in the germ's MDS. AllocateMDS may be called only during module initialization! (The configuration of memory must be static during inLoad and outLoad. Also, spare real memory may not be available after the system is initially loaded)
Guaranteed not to do an ALLOC from the frame heap. Note the page is writable thanks to CompactVM
AllocateMDS: PUBLIC PROC [pages: CARDINAL] RETURNS [p: POINTER TO UNSPECIFIED] =
BEGIN
p ← PointerFromPage[pageAfterGerm];
THROUGH [0..pages) DO
GermPrivate.Assoc[
pageAfterGerm,
GermPrivate.SetF[
virtual: firstPageNumber + GetCountRunMapped[firstPageNumber] - 1,
flagsNew: GermPrivate.valueVacant]];
grab last real page (can only do during an initial boot (inLoadMode=inLoad))
pageAfterGerm ← pageAfterGerm + 1;
ENDLOOP;
END;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Initialize: PROC = -- Assume called from main body
Assume all SD entries zero
BEGIN
InitAlloc: PROC RETURNS[ page: PageNumber] = INLINE
BEGIN
check to see if the page following the germ is already mapped.
This may be the case with microcode swapping
IF NOT IsVacant[GermPrivate.GetF[pageAfterGerm]] THEN
pageAfterGerm ← (page ← pageAfterGerm) + 1
ELSE page ← PrincOpsUtils.PageNumberForAddress[AllocateMDS[pages: 1]];
END;
state: RECORD[a,b: CARDINAL, sv: PrincOps.StateVector];
mainbody: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[];
PrincOps.SD[sSignal] ← PrincOps.SD[sError] ← PrincOps.SD[sReturnError] ←
PrincOps.SD[sSignalList] ← PrincOps.SD[sErrorList] ← PrincOps.SD[sReturnErrorList] ←
SignalHandler;
PrincOps.SD[sUnnamedError] ← UnnamedError;
MesaRuntimeInit.Start[LOOPHOLE[MesaRuntimeInit.TrapsImpl]];
ProcessorFace.Go[];
ShowMP[MPCodes.germStarting]; -- on a Dorado, it didn't work without the ProcessorHead
BEGIN
page: PrincOps.PageNumber;
count: PrincOps.PageCount;
FOR countVM ← 0, page + count DO
[firstPage: page, count: count] ← ProcessorFace.GetNextAvailableVM[countVM];
IF count = 0 THEN EXIT;
ENDLOOP;
END;
pageBuffer ← InitAlloc[];
pageOtherBuffer ← InitAlloc[];
pageGermKeep ← pageAfterGerm;
we keep the buffer page forever, deallocate all else after each request.
We can't deallocate when non-initial-booting operations via the
ether are implemented.
state.sv.instbyte ← state.sv.stkptr ← 0;
Subsequent entries to the germ go directly to Run[]:
state.sv.dest ← GermSwap.pInitialLink^ ←
LOOPHOLE[Run, PrincOps.ControlLink];
state.sv.source ← mainbody.returnlink;
PrincOpsUtils.Free[mainbody];
RETURN WITH state.sv -- to Run[], never to return to Initialize
END;
PrincOpsUtils.WriteWDC[1]; -- temporary hack for Dandelion...delete soon
ProcessorFace.SetMP[MPCodes.germStarting]; -- let them know we are here
Initialize[]; -- never returns
END.
LOG
For earlier log entries see Amargosa archive version.
April 10, 1980 11:59 AM Forrest Implement call to Teledebug.Debug.
April 17, 1980 12:44 AM Forrest Get teledebug from Boot not Bootswap
April 17, 1980 10:39 PM Luniewski AllocateMDSPages=>AllocateMDS
April 18, 1980 3:58 PM Knutsen Export allocateMDSInternal, residentMemoryLock
May 15, 1980 6:18 PM McJones Mesa 6; call OISProcessorFace.Start; temporarily initialize WDC
June 10, 1980 9:16 AM Forrest PrincOps traps/use physical volume Format
June 23, 1980 2:42 PM McJones OISProcessorFace => ProcessorFace
July 20, 1980 9:18 PM Forrest PrincOpsRuntime
August 5, 1980 9:17 AM Forrest Add test for Page after germ being mapped, use GetFlags
September 9, 1980 5:50 PM Forrest/McJones Add cGermFinished
December 10, 1980 9:51 AM Knutsen New name for PSB.Monitor.
February 4, 1981 11:37 AM Knutsen PrincOps fields changed names. Fault Notification: deleted Alloc and Page trap handlers.
March 21, 1981 8:10 PM Taft Transplant my changes from Mokelumne: deal with asynchronous Transfer I/O.
April 26, 1983 11:50 am Andrew Birrell Changes for 5.0 cross version: outload/inload preserve vacant map data; convert to 5.0 MPCodes.
October 31, 1983 10:53 am Andrew Birrell Conversion to 5.0.