DIRECTORY Basics USING [LongDiv], BootChannel USING [Create, Operation, Handle, Transfer, transferCleanup, transferWait], BootFile USING [Continuation, currentVersion, Entry, ExchangePageFlags, ExchangePageState, GetPageValue, Header, InLoadMode, Location, maxEntriesPerHeader, maxEntriesPerTrailer, MDSIndex, SetPageValue, Trailer], GermPrivate USING [TeleDebug], 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, Code], PrincOps USING [ControlLink, flagsClean, flagsVacant, FrameHandle, PageCount, PageNumber, PageState, PageValue, RealPageNumber, returnOffset, SD, sError, sErrorList, sReturnError, sReturnErrorList, sSignal, sSignalList, StateVector, sUnnamedError, UnboundLink, wordsPerPage, 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, BootFile, GermPrivate, GermSwap, MesaRuntimeInit, PrincOpsUtils, ProcessorFace, RuntimeError EXPORTS BootChannel, GermPrivate--countVM, Error-- SHARES GermSwap = { OPEN BootChannel, BootFile, BootFile, GermSwap, PrincOps; stateVacant: PrincOps.PageState = LOOPHOLE[PrincOps.flagsVacant]; stateClean: PrincOps.PageState = LOOPHOLE[PrincOps.flagsClean]; valueVacant: PrincOps.PageValue = [state: stateVacant, real: 0]; valuesPerPage: CARDINAL = PrincOps.wordsPerPage / SIZE[PrincOps.PageValue]; PageValueArray: TYPE = ARRAY [0..valuesPerPage) OF PrincOps.PageValue; 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^; dFirst64KStorage: LONG DESCRIPTOR FOR ARRAY OF WORD = DESCRIPTOR[ LOOPHOLE[LONG[177200B], LONG POINTER], 200B]; cedarVersion: CARDINAL = 150; -- version number of outload files written with cedarOutLoad Run: PROC = { handle: BootChannel.Handle; GermSwap.InitializeMDS[]; -- set pMon ShowMP[MPCodes.germStarting]; DO SELECT GermSwap.pRequest.action FROM inLoad => { 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]-- => { responseKind _ initiated; mdsiOther _ mdsi; destOther _ destination }; resumptive --[mdsi, resumee]-- => { responseKind _ resumed; mdsiOther _ mdsi; destOther _ resumee }; 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]; }; outLoad, pilotOutLoad => { handle _ BC.Create[@GermSwap.pRequest.location, write, dFirst64KStorage]; DoOutLoad[handle, pMon.inLoadMode, pMon.continuation, GermSwap.pRequest.action = outLoad]; pMon.responseKind _ outLoaded; EXIT; }; bootPhysicalVolume => { 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; }; teledebug => IF PrincOpsUtils.IsBound[LOOPHOLE[GermPrivate.TeleDebug]] THEN { GermPrivate.TeleDebug[pageBuffer, dFirst64KStorage]; EXIT} ELSE Error[MPCodes.cantWorldSwap]; ENDCASE => ERROR; ENDLOOP; ShowMP[MPCodes.germFinished]; }; DoInLoad: PROC [channel: BootChannel.Handle] RETURNS [continuation: Continuation, pStartListHeader: POINTER] = { cedar: BOOL _ FALSE; -- whether outload file was written with cedarOutLoad inLoadMode: InLoadMode; realPageTemp: PrincOps.RealPageNumber; -- SkipPageHack count, countData, countGroup, countRemaining: PageCount; page, pageLastMapped, pageNext, pageRun: PageNumber; pBuffer: POINTER = PointerFromPage[pageBuffer]; nEntry: CARDINAL; pEntry, pEntryGroup: POINTER TO Entry; value: PrincOps.PageValue; SkipPage: PROC = { pageTemp: PageNumber = pageAfterGerm; BootFile.SetPageValue[pageTemp, PrincOps.PageValue[stateClean, realPageTemp]]; Transfer[channel, pageTemp, 1]; Transfer[channel, NULL, transferWait]; BootFile.SetPageValue[pageTemp, valueVacant]; }; ShowMP[MPCodes.germInLoad]; Transfer[channel, pageBuffer, 1]; Transfer[channel, NULL, transferWait]; { 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 => { CompactVM[]; pageLastMapped _ firstPageNumber + GetCountRunMapped[firstPageNumber] - 1; realPageTemp _ BootFile.GetPageValue[pageLastMapped].real; -- SkipPageHack }; restore => NULL; ENDCASE; continuation _ header.continuation; countData _ header.countData; pEntryGroup _ @header.entries[0]; nEntry _ maxEntriesPerHeader; }; page _ 0; -- next page to restore countRemaining _ countData; DO countGroup _ MIN[nEntry, countRemaining]; pEntry _ pEntryGroup; THROUGH [0..countGroup) DO WHILE page < pEntry.page DO IF ~(page IN [pageGerm..pageAfterGerm) OR page = 376B OR page = 377B) THEN { value _ BootFile.ExchangePageFlags[page, PrincOps.flagsVacant]; IF inLoadMode = load AND ~IsVacant[value] THEN BootFile.SetPageValue[pageLastMapped _ pageLastMapped + 1, value] }; page _ page + 1; ENDLOOP; IF inLoadMode = restore THEN BootFile.SetPageValue[page, PrincOps.PageValue[stateClean, pEntry.value.real]]; pEntry _ pEntry + SIZE[Entry]; page _ page + 1; ENDLOOP; pEntry _ pEntryGroup; count _ countGroup; WHILE count ~= 0 DO pageNext _ pageRun _ pEntry.page; IF pageRun = 376B OR pageRun = 377B THEN { SkipPage[]; pEntry _ pEntry + SIZE[Entry]; count _ count - 1} ELSE { 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 THEN EXIT; ENDLOOP; Transfer[channel, pageRun, pageNext - pageRun]; }; ENDLOOP; -- Restore map entries Transfer[channel, NULL, transferWait]; pEntry _ pEntryGroup; THROUGH [0..countGroup) DO [] _ BootFile.ExchangePageState[pEntry.page, pEntry.value.state]; pEntry _ pEntry + SIZE[Entry] ENDLOOP; ProcessorFace.SetMP[MPCodes.germInLoad]; countRemaining _ countRemaining - countGroup; IF countRemaining = 0 THEN EXIT; { 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; }; ENDLOOP; SELECT inLoadMode FROM load => { Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup FOR page DECREASING IN [pageGermKeep..pageAfterGerm) DO BootFile.SetPageValue[pageLastMapped _ pageLastMapped + 1, BootFile.ExchangePageState[page, stateVacant]]; ENDLOOP; pageAfterGerm _ pageGermKeep; }; restore => IF cedar THEN { 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 PageValueArray = 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,valuesPerPage]) UNTIL mapPage = countVM DO IF mapPage NOT IN [pageGerm..pageAfterGerm) THEN { current: PrincOps.PageValue = BootFile.GetPageValue[mapPage]; IF NOT IsVacant[current] AND current.state.flags.dirty THEN mapArray[i].state.flags.dirty _ TRUE; BootFile.SetPageValue[mapPage, mapArray[i]]; }; mapPage _ mapPage+1; ENDLOOP; { temp: PrincOps.PageNumber = inCoreBuffer; inCoreBuffer _ inTransitBuffer; inTransitBuffer _ temp }; ENDLOOP; Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup } ELSE { Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup WHILE page < countVM DO IF ~(page IN [pageGerm..pageAfterGerm) OR page = 376B OR page = 377B) THEN BootFile.SetPageValue[page, valueVacant]; page _ page + 1; ENDLOOP; }; ENDCASE; }; DoOutLoad: PROC [channel: BootChannel.Handle, inLoadMode: InLoadMode, continuation: Continuation, cedar: BOOL] = { count, countData, countGroup, countRemaining: PageCount; page, pageNext, pageRun: PageNumber; pBuffer: POINTER = PointerFromPage[pageBuffer]; nEntry: CARDINAL; pEntry, pEntryGroup: POINTER TO Entry; -- ShowMP[MPCodes.germOutLoad]; page _ countData _ 0; DO IF ~IsVacant[BootFile.GetPageValue[page]] THEN countData _ countData + 1; IF (page _ page + 1) = countVM THEN EXIT; ENDLOOP; countData _ countData - (pageAfterGerm - pageGerm) - 2 --i.e. 376B and 377B--; { header: POINTER TO Header = LOOPHOLE[pBuffer, POINTER TO Header]; header.pStartListHeader _ NIL; header.inLoadMode _ inLoadMode; header.continuation _ continuation; header.countData _ countData; header.version _ IF cedar THEN cedarVersion ELSE BootFile.currentVersion; pEntryGroup _ @header.entries[0]; nEntry _ maxEntriesPerHeader; }; page _ 0; countRemaining _ countData; DO countGroup _ MIN[nEntry, countRemaining]; -- Write map page pEntry _ pEntryGroup; THROUGH [0..countGroup) DO page _ AdvancePage[page]; pEntry^ _ [page, BootFile.GetPageValue[page]]; pEntry _ pEntry + SIZE[Entry]; page _ page + 1 ENDLOOP; Transfer[channel, pageBuffer, 1]; -- Write data pages pEntry _ pEntryGroup; count _ countGroup; WHILE count ~= 0 DO pageNext _ pageRun _ pEntry.page; DO 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; { trailer: POINTER TO Trailer = LOOPHOLE[pBuffer, POINTER TO Trailer]; pEntryGroup _ @trailer.entries[0]; nEntry _ maxEntriesPerTrailer; trailer.version _ BootFile.currentVersion; -- set version }; ENDLOOP; IF cedar THEN { mapPage: PrincOps.PageNumber _ 0; inCoreBuffer: PrincOps.PageNumber _ pageBuffer; inTransitBuffer: PrincOps.PageNumber _ pageOtherBuffer; ShowMP[MPCodes.germMapIO]; UNTIL mapPage = countVM DO mapArray: POINTER TO PageValueArray = PointerFromPage[inCoreBuffer]; FOR i: CARDINAL IN CARDINAL[0..MIN[countVM-mapPage,valuesPerPage]) UNTIL mapPage = countVM DO mapArray[i] _ BootFile.GetPageValue[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]; }; Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup }; AdvancePage: PROC [page: PageNumber] RETURNS [PageNumber] = { WHILE IsVacant[BootFile.GetPageValue[page]] OR --InGerm[page]-- (page IN [pageGerm..pageAfterGerm) OR page IN [376B..377B]) DO page _ page + 1 ENDLOOP; RETURN[page] }; CompactVM: PROC = { pageDest: PageNumber _ 0; FOR pageSource: PageNumber IN [0..countVM) DO value: PrincOps.PageValue; IF pageSource IN [pageGerm..pageAfterGerm) OR pageSource IN [376B..377B] THEN LOOP; IF pageSource = 1 THEN LOOP; value _ BootFile.ExchangePageFlags[pageSource, PrincOps.flagsVacant]; IF IsVacant[value] THEN LOOP; value.state.flags.readonly _ FALSE; BootFile.SetPageValue[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; }; 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!--}; GetCountRunMapped: PROC [pageStarting: PageNumber] RETURNS [countReal: PageCount] = { FOR countReal _ 0, countReal + 1 DO IF IsVacant[BootFile.GetPageValue[pageStarting + countReal]] THEN EXIT ENDLOOP }; GetPageMDS: PROC RETURNS [PageNumber] = { RETURN[GermSwap.ReadMDS[]*256]; }; IsVacant: PROC [value: PrincOps.PageValue] RETURNS [BOOLEAN] = INLINE { RETURN[value.state.flags=PrincOps.flagsVacant]; }; InGerm: PROC [page: PageNumber] RETURNS [BOOLEAN] = INLINE { RETURN[page IN [pageGerm..pageAfterGerm) OR page IN [376B..377B]] }; JumpCall0: PROC [Proc: PROC] = MACHINE CODE { PrincOps.zSLB, PrincOps.returnOffset; PrincOps.zRET; }; 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] = { BC.Transfer[handle, page, count]; }; Error: PUBLIC SIGNAL [code: MPCodes.Code] = CODE; -- export to GermPrivate UnnamedError: PROC = { SignalHandler[Error, MPCodes.germERROR]; }; SignalHandler: PROC [signal: SIGNAL[code: MPCodes.Code], code: MPCodes.Code] = { 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; }; debug: BOOL = FALSE; ShowMP: PROC[code: MPCodes.Code] = { ProcessorFace.SetMP[code]; IF debug THEN { start: LONG CARDINAL = ProcessorFace.GetClockPulses[]; pulsesPerSecond: LONG CARDINAL = Basics.LongDiv[1D6*100, ProcessorFace.microsecondsPerHundredPulses]; ProcessorFace.SetMP[code]; WHILE ProcessorFace.GetClockPulses[] - start < pulsesPerSecond DO ENDLOOP; }; }; AllocateMDS: PUBLIC PROC [pages: CARDINAL] RETURNS [p: POINTER] = { p _ PointerFromPage[pageAfterGerm]; THROUGH [0..pages) DO BootFile.SetPageValue[ pageAfterGerm, BootFile.ExchangePageFlags[ firstPageNumber + GetCountRunMapped[firstPageNumber] - 1, PrincOps.flagsVacant]]; pageAfterGerm _ pageAfterGerm + 1; ENDLOOP; }; Initialize: PROC = { InitAlloc: PROC RETURNS[ page: PageNumber] = INLINE { IF NOT IsVacant[BootFile.GetPageValue[pageAfterGerm]] THEN pageAfterGerm _ (page _ pageAfterGerm) + 1 ELSE page _ PrincOpsUtils.PageNumberForAddress[AllocateMDS[pages: 1]]; }; 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] _ LOOPHOLE[SignalHandler]; PrincOps.SD[sUnnamedError] _ LOOPHOLE[UnnamedError]; MesaRuntimeInit.Start[LOOPHOLE[MesaRuntimeInit.TrapsImpl]]; ProcessorFace.Go[]; ShowMP[MPCodes.germStarting]; -- on a Dorado, it didn't work without the ProcessorHead { 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; }; pageBuffer _ InitAlloc[]; pageOtherBuffer _ InitAlloc[]; pageGermKeep _ pageAfterGerm; state.sv.instbyte _ state.sv.stkptr _ 0; 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 }; PrincOpsUtils.WriteWDC[1]; -- temporary hack for Dandelion...delete soon ProcessorFace.SetMP[MPCodes.germStarting]; -- let them know we are here Initialize[]; -- never returns }. 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. ψBootSwapGerm.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Taft, February 25, 1983 3:00 pm Andrew Birrell, December 13, 1983 3:18 pm Russ Atkinson, February 13, 1985 5:09:49 pm PST Note: I think the code in initialize assumes the machine starts the germ with memory mapped at address 0 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. current end of (mapped) germ storage (includes allocated buffer space, doesn't include pageTemp). Note that DoInLoad uses a scratch VM page at pageAfterGerm. 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. after the very first execution, the germ entry point is here inLoad exits through JumpCall2, outLoad does explicit EXIT, bootPhysicalVolume turns itself into an inLoad frees our frame now get the boot file and go Read first page, containing header Restore real memory and hardware map from boot file, beginning with data of first group Calculate group size Set up map entries to be vacant or nonvacant (and writable), as appropriate nongerm pages not in boot file are vacant IF ~InGerm[page] THEN Transfer data to nonvacant pages find and transfer one run re-set MP in case we just overwrote the cursor (which displays the MP on a Dorado!) Prepare for next group All groups are now loaded Recover germ buffer storage: We can't do this when non-initial-booting operations via the ether are implemented. Pilot (is this still viable?) IF ~InGerm[page] THEN Assumptions: interrupts disabled, all devices quiesced Construct header in first map page Number of pages to save is total nonvacant minus those in germ Write sequence of (map, data) groups Calculate group size find and transfer one run until end of run found Cedar Nucleus: write data words from entire page map (double-buffered) Return first page at or after given page which is not vacant or part of the germ 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. Backstop Create routine to plug end of chain of BootChannel interfaces. Find length of run of virtual pages all mapped to real pages 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 Only public to make compiler happy 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. display code in panel (for a second if "debug") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 grab last real page (can only do during an initial boot (inLoadMode=inLoad)) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Assume called from main body & all SD entries zero check to see if the page following the germ is already mapped. This may be the case with microcode swapping 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. Subsequent entries to the germ go directly to Run[]: Κβ˜codešœ™Kšœ Οmœ1™˜I˜5K˜$—K˜Kšžœ˜Kšœ˜—šœ˜Kšœžœžœ9˜KKšœ2žœžœŸ ˜NKšœ žœ@˜KK˜ Kšœžœ˜%šžœ$žœ˜:Kšœžœ&˜H—KšœŸ˜,KšœE˜EK˜"Kšœ™Kšœ˜—˜ Kšžœžœ˜9šžœ˜Kšœ4˜4Kšžœ˜—Kšžœ˜"—Kšžœžœ˜—Kšžœ˜—Kšœ˜Kšœ˜K˜—š œžœžœ0žœ˜pKšœžœžœŸ5˜JK˜Kšœ'Ÿ˜6K˜8K˜4Kšœ žœ˜/Kšœžœ˜Kšœžœžœ˜&Kšœ˜š œžœ˜K˜%šœ˜Kšœ.˜.—K˜Kšœžœ˜&Kšœ-˜-Kšœ˜—Kšœ˜Kšœ"™"K˜!Kšœžœ˜&Kš œžœ žœ žœžœ ˜4šžœ+žœ˜3Kšžœžœ ž˜2Kšžœ˜#K˜—K˜+šžœ"ž˜,šœ ˜ K˜ KšœJ˜JKšœ;Ÿ˜JKšœ˜—Kšœ žœ˜Kšžœ˜—K˜#K˜K˜!K˜Kšœ˜K™KšœW™WKšœ Ÿ˜!K˜šž˜Kšœ™Kšœ žœ˜)KšœK™KK˜šžœž˜šžœž˜Kšœ)™)Kšœ™šžœžœžœ žœ ˜EKšžœ˜Kšœ?˜?šžœžœž˜.KšœA˜A—Kšœ˜—K˜Kšžœ˜—šžœž˜šœ˜Kšœ3˜3——Kšœžœ˜K˜Kšžœ˜—Kšœ ™ K˜K˜šžœ ž˜Kšœ™K˜!šžœžœ˜#šžœ˜Kšœ ˜ Kšœžœ˜Kšœ˜—šžœ˜šžœŸ˜K˜K˜Kšœžœ˜šžœ žœžœžœ ˜FKšœžœžœ˜—Kšžœ˜—K˜/Kšœ˜——KšžœŸ˜—Kšœžœ˜&K˜šžœž˜KšœA˜AKšœžœ˜Kšžœ˜—KšœS™SK˜(Kšœ™K˜-Kšžœžœžœ˜ š œžœ žœ žœžœ ˜6K˜!Kšœžœ˜&Kšžœ,žœ ˜RK˜"K˜Kšœ˜—Kšžœ˜—Kšœ™šžœ ž˜šœ ˜ KšœžœŸ˜IšœG™GKšœ)™)—šžœž œžœž˜7šœ:˜:Kšœ/˜/—Kšžœ˜—K˜Kšœ˜—˜ šžœžŸœ˜K˜!K˜/K˜7K˜K˜#Kšžœ˜šž˜Kšœ žœžœ0˜DKšžœ*˜,Kšžœ&Ÿ&˜PKšžœžœŸ+˜VKš žœžœžœžœžœ ˜Bšžœž˜šžœ žœžœžœ˜2Kšœ=˜=šžœžœžœ˜6Kšžœ!žœ˜*—Kšœ,˜,Kšœ˜—K˜Kšžœ˜—˜+K˜9—Kšžœ˜—KšœžœŸ˜IKšœ˜—šžœ˜Kšœ™KšœžœŸ˜IKšžœž˜šœ™šžœžœžœ žœ ˜EKšžœ*˜.—K˜Kšžœ˜—Kšœ˜——Kšžœ˜—Kšœ˜K˜—š  œžœZžœ˜rKšœ6™6K˜8K˜$Kšœ žœ˜/Kšœžœ˜KšœžœžœŸ˜)Kšœ"™"Kšœ>™>K˜K˜šž˜šžœ(ž˜.K˜—Kšžœžœžœ˜)Kšžœ˜—Kšœ7Ÿœ˜Nšœ˜Kš œžœžœ žœ žœžœ ˜AKšœžœ˜Kšœ˜Kšœ#˜#Kšœ˜Kšœžœžœžœ˜IK˜!K˜Kšœ˜—K™Kšœ$™$K˜ K˜šž˜Kšœ™Kšœ žœŸ˜;K˜šžœž˜K˜Kšœ.˜.Kšœžœ˜K˜Kšžœ˜—Kšœ"Ÿ˜5K˜K˜šžœ ž˜Kšœ™K˜!šž˜Kšœ™K˜K˜Kšœžœ˜Kšžœ žœžœžœ˜2Kšžœ˜—K˜/KšžœŸ˜"—Kšœžœ˜&K˜-Kšžœžœžœ˜ šœ˜Kš œ žœžœ žœ žœžœ ˜DK˜"K˜Kšœ*Ÿ˜9Kšœ˜—Kšžœ˜—šžœžœ˜KšœG™GK˜!K˜/K˜7K˜Kšžœ˜šž˜Kšœ žœžœ0˜DKš žœžœžœžœžœ ˜Bšžœž˜Kšœ-˜-K˜Kšžœ˜—Kšœ#Ÿ3˜V˜+K˜9—Kšžœ˜Kšœžœ˜&—Kšœ˜—KšœžœŸ˜HKšœ˜K˜—š  œžœžœ˜=KšœP™Pšžœ'ž˜.KšŸœžœžœžœ˜LKšžœžœ˜—Kšžœ˜ Kšœ˜K˜—š  œžœ˜KšœΗ™ΗK˜šžœžœž˜-Kšœ˜Kš žœ žœžœ žœžœžœ˜SKšžœžœžœ˜KšœE˜EKšžœžœžœ˜Kšœžœ˜#Kšœ)Ÿ˜@šžœžœ˜=Kš žœžœ žœžœžœ˜8—Kšžœ˜—Kšœ˜K˜—KšœG™Gš œžœžœžœžœ*žœž œžœžœžœžœžœ!˜•Kšœ Ÿ+œ˜MK˜—Kšœ<™<š œžœžœ˜Ušžœž˜#Kšžœ;žœž˜FKšž˜—Kšœ˜K˜—š  œžœžœ˜)Kšžœ˜Kšœ˜K˜—š  œžœžœžœžœ˜GKšžœ)˜/Kšœ˜K˜—Kšœζ™ζš  œžœžœžœžœ˜Kšœžœ˜%Kšžœžœ˜#Kšœ˜K˜—š œžœžœ žœ0˜QKšœ"™"Kšžœ˜!Kšœ˜K˜—KšœžœžœžœŸ˜JK˜Kšœϋ™ϋK˜š  œžœ˜Kšœ(˜(Kšœ˜K˜—š  œžœ žœ-˜Pšœžœžœž˜$K˜Kšœ žœ8˜IKšœ žœ4˜EKšžœ˜—Kšžœžœ˜ Kšœ˜—K˜Kšœžœžœ˜K˜š œžœ˜$Kšœ/™/Kšœ˜šžœžœ˜Kšœžœžœ"˜6šœžœžœ˜ KšœD˜D—Kšœ˜Kšžœ:žœžœ˜JKšœ˜—Kšœ˜K˜—Kšœ:™:Kšœ’™’K˜Kšœa™aš   œžœžœ žœžœžœ˜CK˜#šžœ ž˜šœ˜K˜šœ˜Kšœ9˜9Kšœ˜——KšœL™LK˜"Kšžœ˜—Kšœ˜K˜—Kšœ:™:K˜š  œžœ˜Kšœ2™2š  œžœžœžœ˜5Kšœ>™>Kšœ,™,šžœžœ0ž˜:K˜*—KšžœB˜FKšœ˜—Kšœžœžœ˜7K˜@šœ žœžœžœ˜HKšœ žœžœžœ˜TKšžœ˜—Kšœ žœžœ˜4Kšœžœ˜;K˜KšœŸ8˜Všœ˜K˜K˜šžœž˜ K˜LKšžœ žœžœ˜—Kšžœ˜Kšœ˜—K˜K˜K˜KšœH™HKšœ?™?Kšœ™K˜(Kšœ4™4˜(Kšžœ˜$—K˜&K˜Kšžœžœ Ÿ*˜?Kšœ˜K˜—KšœŸ-˜HKšœ+Ÿ˜GKšœŸ˜K˜Kšœ˜K˜Kšž˜K˜5˜Kšœžœ/˜GK˜Kšœžœ1˜IK˜Kšœžœ,˜DK˜Kšœžœ;˜RK˜KšœžœIž˜aK˜Kšœžœ6˜LK˜Kšœžœ.˜DK˜Kšœžœ˜2K˜KšœžœD˜[K˜Kšœžœ&˜@K˜Kšœžœžœ ˜@K˜Kšœžœf˜€K˜KšœžœPžœžœ˜kK˜K˜ŒK˜K˜?—K˜K˜—…—G”mn