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; 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 = -- after the very first execution, the germ entry point is here BEGIN handle: BootChannel.Handle; GermSwap.InitializeMDS[]; -- set pMon ShowMP[MPCodes.germStarting]; DO 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]; 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; 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: BOOL _ FALSE; -- 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]; 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; 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 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; pEntry _ pEntryGroup; count _ countGroup; WHILE count ~= 0 DO 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; ProcessorFace.SetMP[MPCodes.germInLoad]; 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; SELECT inLoadMode FROM load => BEGIN Transfer[channel, NULL, transferCleanup]; -- final call to allow cleanup 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 ~(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] = BEGIN 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[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; page _ 0; countRemaining _ countData; DO 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 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; 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] = 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 = 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; 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] = 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]}; 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] = BEGIN BC.Transfer[handle, page, count]; END; 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] = 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; 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]]; pageAfterGerm _ pageAfterGerm + 1; ENDLOOP; END; Initialize: PROC = -- Assume called from main body BEGIN InitAlloc: PROC RETURNS[ page: PageNumber] = INLINE BEGIN 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; 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 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. Æ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 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. 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. 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 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. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 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[]: ʘJšœ™Jšœ/™/Jšœ9™9J˜Jšœh™hJ˜šÏk ˜ Jšœœ ˜Jšœ œF˜WJšœ œƒ˜‘Jšœ œ]˜nJšœ œq˜Jšœœ˜)JšœœÒ˜ßJšœ œOœ˜àJšœœA˜TJšœœO˜bJšœ œ˜.Jšœ œ*˜˜I˜5J˜$—J˜Jšœ˜Jšœ˜—˜Jš˜šœœœ˜.J˜—Jšœ2œœž ˜NJšœ œ@˜KJ˜ Jšœœ˜%šœ$œ˜:Jšœœ&˜H—Jšœž˜,JšœE˜EJ˜"Jšœ™Jšœ˜—˜ Jšœ-˜/šœ˜Jšœ$˜$Jšœ4˜4Jšœ˜—Jšœ˜"—Jšœœ˜—Jšœ˜—Jšœ˜Jšœ˜J˜—šŸœœ˜,Jšœ0œ˜AJš˜Jšœœœž5˜JJ˜Jšœ*ž˜9J˜8J˜4Jšœ œ˜/Jšœœ˜Jšœœœ˜&J˜šŸœœž˜ Jš˜J˜%šœ˜Jšœœ)˜@—J˜Jšœœ˜&J˜5Jšœž˜—Jšœ˜Jšœ"™"J˜!Jšœœ˜&Jš œœ œ œœ ˜8šœ+œ˜3Jšœœ ˜2Jšœ˜#J˜—J˜+šœ"˜,˜Jš˜J˜ JšœJ˜JJšœ:ž˜IJšœ˜—Jšœ œ˜Jšœ˜—J˜#J˜J˜!J˜Jšœ˜J™JšœW™WJšœ ž˜!J˜š˜Jšœ™Jšœ œ˜)JšœK™KJ˜šœ˜šœ˜Jšœ)™)Jšœ™šœœœ œ ˜EJš˜Jš˜J˜8šœœ˜.J˜=—Jšœ˜—J˜Jšœ˜—šœ˜šœ˜Jšœœ2˜I——Jšœœ˜J˜Jšœ˜—Jšœ ™ J˜J˜šœ ˜Jšœ™J˜!šœœœž˜8Jšœœ˜>—š˜Jš˜šœž˜J˜J˜Jšœœ˜šœ œœœ ˜FJšœžœœœ˜"—Jšœ˜—J˜/Jšœ˜—Jšœž˜—Jšœœ˜&J˜šœ˜J˜1Jšœœ˜Jšœ˜—JšœS™SJ˜(Jšœ™J˜-Jšœœœ˜ Jš œœ œ œœ ˜:J˜!Jšœœ˜&Jšœ,œ ˜RJ˜"J˜Jšœ˜Jšœ˜—Jšœ™šœ ˜˜Jš˜Jšœœž˜IšœG™GJšœ)™)—šœ œœ˜7˜6J˜1—Jšœ˜—J˜Jšœ˜—˜ šœž4˜AJš˜J˜!J˜/J˜7J˜J˜#Jšœ˜š˜š œ œœœœ˜JJ˜ —Jšœ*˜,Jšœ&ž&˜PJšœœž+˜VJš œœœœœ(˜JJšœ˜š˜šœ œœ˜0Jš˜J˜7Jšœœœ˜0Jšœœ˜$J˜(Jšœ˜—J˜Jšœ˜—˜+J˜9——Jšœ˜Jšœœž˜IJš˜—šœœž ˜Jšœœž˜IJšœ˜šœ™šœœœ œ ˜EJšœ2˜6—J˜Jšœ˜—Jšœ˜——Jšœ˜—Jšœ˜J˜—šŸ œœZœ˜pJšœ6™6Jš˜J˜8J˜$Jšœ œ˜/Jšœœ˜Jšœœœž˜)Jšœ"™"Jšœ>™>J˜J˜š˜šœ#˜)J˜—Jšœœœ˜)Jšœ˜—Jšœ7žœ˜NJš œœ œ œœ ˜8šœž.˜GJšœœ5˜JJ˜ —Jšœœ˜,J˜!J˜Jšœ˜J™Jšœ$™$J˜ J˜š˜Jšœ™Jšœ œž˜;J˜šœ˜J˜J˜)Jšœœ˜J˜Jšœ˜—Jšœ"ž˜5J˜J˜šœ ˜Jšœ™J˜!š˜Jšœ™J˜J˜Jšœœ˜Jšœ œœœ˜2Jšœ˜—J˜/Jšœž˜"—Jšœœ˜&J˜-Jšœœœ˜ Jš œœ œ œœ ˜:J˜"J˜Jšœž/˜EJšœ˜Jšœ˜—šœ˜ JšœžJ˜PJ˜!J˜/J˜7J˜Jšœ˜š˜š œ œœœœ˜JJ˜ —Jš œœœœœ(˜JJšœ˜š˜J˜(J˜Jšœ˜—Jšœ#ž3˜V˜+J˜9—Jšœ˜Jšœœ˜&—Jšœ˜—Jšœœž˜HJšœ˜J˜—šŸ œœœ˜;JšœP™PJš˜šœ"˜)Jšžœœœœ˜L—Jšœœ˜Jšœ˜ Jšœ˜J˜—šŸ œœ˜JšœÇ™ÇJš˜J˜šœœ˜-J˜Jš œ œœ œœœ˜SJšœœœ˜JšœIœœ˜UJšœœ˜Jšœ%ž˜<šœœ˜=Jš œœ œœœ˜8—Jšœ˜—Jšœ˜J˜—JšœG™GšŸœœœ˜Jšœœ*˜4Jš œ œœœœœ˜"Jšœ˜&Jšœ!ž+œ˜NJ˜—Jšœ<™<šŸœœ˜2Jšœ˜ Jš˜šœ˜#Jšœ6œ˜AJš˜—Jšœ˜J˜—šŸ œœœ˜'Jšœœ˜#J˜—š Ÿœœœœœ˜FJšœ'˜-J˜—Jšœæ™æš Ÿœœœœ˜:Jš˜Jšœœœœ˜AJšœ˜J˜—š Ÿ œœŸœœœ˜+Jšœ5œ˜>J˜—šŸ œœ˜Jš œ œŸœœ œ œ˜AJšœ ˜J˜—šŸœœœœ˜>Jšœœ˜%Jšœœ˜#Jšœ˜J˜—šŸœœœ œ.˜OJšœ"™"Jš˜Jšœ˜!Jšœ˜J˜—Jšœœœœž˜JJ˜Jšœû™ûJ˜šŸ œœ˜J˜,J˜—šŸ œœ œ+˜NJš˜šœœœ˜$J˜Jšœ œ8˜IJšœ œ4˜EJšœ˜—Jšœœ˜ Jšœ˜—J˜Jšœœœ˜J˜šŸœœž2˜UJš˜Jšœ˜Jšœ˜šœ˜ Jšœœœ"˜6šœœœ˜ JšœD˜D—Jšœ˜Jšœ:œœ˜JJšœ˜—Jšœ˜J˜—Jšœ:™:Jšœ¢™¢J˜Jšœa™ašŸ œœœ œœœœ œ˜PJš˜J˜#šœ ˜˜J˜˜JšœB˜BJ˜$——JšœL™LJ˜"Jšœ˜—Jšœ˜J˜—Jšœ:™:J˜šŸ œœž˜2Jšœ™Jš˜šŸ œœœ˜3Jš˜Jšœ>™>Jšœ,™,šœœ+˜5J˜*—JšœB˜FJšœ˜—Jšœœœ˜7J˜@šœ œœœ˜HJšœ œœœ˜TJ˜—Jšœ œ˜*Jšœœ˜;J˜Jšœž8˜Vš˜J˜J˜šœ˜ J˜LJšœ œœ˜—Jšœ˜—Jšœ˜J˜J˜J˜JšœH™HJšœ?™?Jšœ™J˜(Jšœ4™4˜(Jšœ˜$—J˜&J˜Jšœœ ž*˜?Jšœ˜J˜—Jšœž-˜HJšœ+ž˜GJšœž˜J˜Jšœ˜J˜Jš˜J˜5˜Jšœœ/˜GJ˜Jšœœ1˜IJ˜Jšœœ,˜DJ˜Jšœœ;˜RJ˜JšœœI˜aJ˜Jšœœ6˜LJ˜Jšœœ.˜DJ˜Jšœœ˜2J˜JšœœD˜[J˜Jšœœ&˜@J˜Jšœœœ ˜@J˜Jšœœf˜€J˜JšœœPœœ˜kJ˜J˜ŒJ˜J˜?—J˜J˜—…—HjmM